From 8540d9c1d1de1565fd407ed175421b5902e197a1 Mon Sep 17 00:00:00 2001 From: an-tao Date: Wed, 6 Aug 2025 18:54:06 +0800 Subject: [PATCH 1/6] Support ssl in mysql connections --- orm_lib/src/mysql_impl/MysqlConnection.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/orm_lib/src/mysql_impl/MysqlConnection.cc b/orm_lib/src/mysql_impl/MysqlConnection.cc index fb352feced..ccc55378d3 100644 --- a/orm_lib/src/mysql_impl/MysqlConnection.cc +++ b/orm_lib/src/mysql_impl/MysqlConnection.cc @@ -59,6 +59,12 @@ MysqlConnection::MysqlConnection(trantor::EventLoop *loop, static MysqlEnv env; static thread_local MysqlThreadEnv threadEnv; mysql_init(mysqlPtr_.get()); + mysql_ssl_set(mysqlPtr_.get(), + nullptr, // key + nullptr, // cert + nullptr, // CA + nullptr, // CApath + nullptr); // cipher mysql_options(mysqlPtr_.get(), MYSQL_OPT_NONBLOCK, nullptr); #ifdef HAS_MYSQL_OPTIONSV mysql_optionsv(mysqlPtr_.get(), MYSQL_OPT_RECONNECT, &reconnect_); From 838313647606cd04081f4b3db07f12122bb77062 Mon Sep 17 00:00:00 2001 From: An Tao Date: Thu, 7 Aug 2025 10:59:06 +0800 Subject: [PATCH 2/6] Update orm_lib/src/mysql_impl/MysqlConnection.cc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- orm_lib/src/mysql_impl/MysqlConnection.cc | 45 ++++++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/orm_lib/src/mysql_impl/MysqlConnection.cc b/orm_lib/src/mysql_impl/MysqlConnection.cc index ccc55378d3..ee4b5459c1 100644 --- a/orm_lib/src/mysql_impl/MysqlConnection.cc +++ b/orm_lib/src/mysql_impl/MysqlConnection.cc @@ -59,12 +59,47 @@ MysqlConnection::MysqlConnection(trantor::EventLoop *loop, static MysqlEnv env; static thread_local MysqlThreadEnv threadEnv; mysql_init(mysqlPtr_.get()); + // Parse SSL parameters from connection string + std::string ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher; + auto connParams = parseConnString(connInfo); + for (auto const &kv : connParams) + { + auto key = kv.first; + auto value = kv.second; + std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c) { return tolower(c); }); + if (key == "ssl_key") + { + ssl_key = value; + } + else if (key == "ssl_cert") + { + ssl_cert = value; + } + else if (key == "ssl_ca") + { + ssl_ca = value; + } + else if (key == "ssl_capath") + { + ssl_capath = value; + } + else if (key == "ssl_cipher") + { + ssl_cipher = value; + } + } + // If all SSL parameters are empty, log a warning about certificate verification + if (ssl_key.empty() && ssl_cert.empty() && ssl_ca.empty() && ssl_capath.empty() && ssl_cipher.empty()) + { + LOG_WARN << "SSL is enabled for MySQL connection, but no certificate parameters are set. " + << "This disables certificate verification and may allow man-in-the-middle attacks."; + } mysql_ssl_set(mysqlPtr_.get(), - nullptr, // key - nullptr, // cert - nullptr, // CA - nullptr, // CApath - nullptr); // cipher + ssl_key.empty() ? nullptr : ssl_key.c_str(), + ssl_cert.empty() ? nullptr : ssl_cert.c_str(), + ssl_ca.empty() ? nullptr : ssl_ca.c_str(), + ssl_capath.empty() ? nullptr : ssl_capath.c_str(), + ssl_cipher.empty() ? nullptr : ssl_cipher.c_str()); mysql_options(mysqlPtr_.get(), MYSQL_OPT_NONBLOCK, nullptr); #ifdef HAS_MYSQL_OPTIONSV mysql_optionsv(mysqlPtr_.get(), MYSQL_OPT_RECONNECT, &reconnect_); From 70663917e5b1df15379b38935e47a3ef92e0f162 Mon Sep 17 00:00:00 2001 From: an-tao Date: Thu, 7 Aug 2025 11:14:05 +0800 Subject: [PATCH 3/6] Fix building --- lib/src/HttpAppFrameworkImpl.cc | 3 +- orm_lib/inc/drogon/orm/DbConfig.h | 1 + orm_lib/src/DbClientManager.cc | 13 ++++ orm_lib/src/mysql_impl/MysqlConnection.cc | 82 +++++++++++------------ 4 files changed, 54 insertions(+), 45 deletions(-) diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index 35448bad2f..3e74933f56 100644 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -994,7 +994,8 @@ void HttpAppFrameworkImpl::addDbClient( name, isFast, characterSet, - timeout}); + timeout, + std::move(options)}); } else if (dbType == "sqlite3") { diff --git a/orm_lib/inc/drogon/orm/DbConfig.h b/orm_lib/inc/drogon/orm/DbConfig.h index 7cbd8f3a6f..b91c8d41fc 100644 --- a/orm_lib/inc/drogon/orm/DbConfig.h +++ b/orm_lib/inc/drogon/orm/DbConfig.h @@ -48,6 +48,7 @@ struct MysqlConfig bool isFast; std::string characterSet; double timeout; + std::unordered_map connectOptions; }; struct Sqlite3Config diff --git a/orm_lib/src/DbClientManager.cc b/orm_lib/src/DbClientManager.cc index 6b92943a8d..9bcd3db522 100644 --- a/orm_lib/src/DbClientManager.cc +++ b/orm_lib/src/DbClientManager.cc @@ -215,6 +215,19 @@ void DbClientManager::addDbClient(const DbConfig &config) cfg.username, cfg.password, cfg.characterSet); + if (!cfg.connectOptions.empty()) + { + std::string optionStr = " options='"; + for (auto const &[key, value] : cfg.connectOptions) + { + optionStr += " -c "; + optionStr += escapeConnString(key); + optionStr += "="; + optionStr += escapeConnString(value); + } + optionStr += "'"; + connStr += optionStr; + } dbInfos_.emplace_back(DbInfo{connStr, config}); #else std::cout << "The Mysql is not supported in current drogon build, " diff --git a/orm_lib/src/mysql_impl/MysqlConnection.cc b/orm_lib/src/mysql_impl/MysqlConnection.cc index ee4b5459c1..a4bae7fda4 100644 --- a/orm_lib/src/mysql_impl/MysqlConnection.cc +++ b/orm_lib/src/mysql_impl/MysqlConnection.cc @@ -66,8 +66,37 @@ MysqlConnection::MysqlConnection(trantor::EventLoop *loop, { auto key = kv.first; auto value = kv.second; - std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c) { return tolower(c); }); - if (key == "ssl_key") + std::transform(key.begin(), + key.end(), + key.begin(), + [](unsigned char c) { return tolower(c); }); + LOG_DEBUG << "connInfo key:[" << key << "] value:[" << value << "]"; + if (key == "host") + { + host_ = value; + } + else if (key == "user") + { + user_ = value; + } + else if (key == "dbname") + { + // LOG_DEBUG << "database:[" << value << "]"; + dbname_ = value; + } + else if (key == "port") + { + port_ = value; + } + else if (key == "password") + { + passwd_ = value; + } + else if (key == "client_encoding") + { + characterSet_ = value; + } + else if (key == "ssl_key") { ssl_key = value; } @@ -88,11 +117,14 @@ MysqlConnection::MysqlConnection(trantor::EventLoop *loop, ssl_cipher = value; } } - // If all SSL parameters are empty, log a warning about certificate verification - if (ssl_key.empty() && ssl_cert.empty() && ssl_ca.empty() && ssl_capath.empty() && ssl_cipher.empty()) + // If all SSL parameters are empty, log a warning about certificate + // verification + if (ssl_key.empty() && ssl_cert.empty() && ssl_ca.empty() && + ssl_capath.empty() && ssl_cipher.empty()) { - LOG_WARN << "SSL is enabled for MySQL connection, but no certificate parameters are set. " - << "This disables certificate verification and may allow man-in-the-middle attacks."; + LOG_DEBUG << "no certificate parameters are set. " + << "This disables certificate verification and may allow " + "man-in-the-middle attacks."; } mysql_ssl_set(mysqlPtr_.get(), ssl_key.empty() ? nullptr : ssl_key.c_str(), @@ -104,44 +136,6 @@ MysqlConnection::MysqlConnection(trantor::EventLoop *loop, #ifdef HAS_MYSQL_OPTIONSV mysql_optionsv(mysqlPtr_.get(), MYSQL_OPT_RECONNECT, &reconnect_); #endif - // Get the key and value - auto connParams = parseConnString(connInfo); - for (auto const &kv : connParams) - { - auto key = kv.first; - auto value = kv.second; - - std::transform(key.begin(), - key.end(), - key.begin(), - [](unsigned char c) { return tolower(c); }); - // LOG_TRACE << key << "=" << value; - if (key == "host") - { - host_ = value; - } - else if (key == "user") - { - user_ = value; - } - else if (key == "dbname") - { - // LOG_DEBUG << "database:[" << value << "]"; - dbname_ = value; - } - else if (key == "port") - { - port_ = value; - } - else if (key == "password") - { - passwd_ = value; - } - else if (key == "client_encoding") - { - characterSet_ = value; - } - } } void MysqlConnection::init() From 15f8433da7d7cb349201cc29dcc73b083d5bac20 Mon Sep 17 00:00:00 2001 From: an-tao Date: Thu, 7 Aug 2025 13:39:47 +0800 Subject: [PATCH 4/6] fix mysql conn info --- orm_lib/src/DbClientManager.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/orm_lib/src/DbClientManager.cc b/orm_lib/src/DbClientManager.cc index 9bcd3db522..d25ef80953 100644 --- a/orm_lib/src/DbClientManager.cc +++ b/orm_lib/src/DbClientManager.cc @@ -217,15 +217,14 @@ void DbClientManager::addDbClient(const DbConfig &config) cfg.characterSet); if (!cfg.connectOptions.empty()) { - std::string optionStr = " options='"; + std::string optionStr; for (auto const &[key, value] : cfg.connectOptions) { - optionStr += " -c "; + optionStr += " "; optionStr += escapeConnString(key); optionStr += "="; optionStr += escapeConnString(value); } - optionStr += "'"; connStr += optionStr; } dbInfos_.emplace_back(DbInfo{connStr, config}); From c5433800c0667c278578600a864d835530f04333 Mon Sep 17 00:00:00 2001 From: an-tao Date: Thu, 7 Aug 2025 14:50:15 +0800 Subject: [PATCH 5/6] Options --- drogon_ctl/create_model.cc | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drogon_ctl/create_model.cc b/drogon_ctl/create_model.cc index 147353c1b6..2026db5c62 100644 --- a/drogon_ctl/create_model.cc +++ b/drogon_ctl/create_model.cc @@ -871,6 +871,20 @@ void create_model::createModel(const std::string &path, connStr += " client_encoding="; connStr += escapeConnString(characterSet); } + auto options = config["connect_options"]; + if (options.isObject() && !options.empty()) + { + std::string optionStr = " options='"; + for (auto const &key : options.getMemberNames()) + { + optionStr += " -c "; + optionStr += escapeConnString(key); + optionStr += "="; + optionStr += escapeConnString(options[key].asString()); + } + optionStr += "'"; + connStr += optionStr; + } auto schema = config.get("schema", "public").asString(); DbClientPtr client = drogon::orm::DbClient::newPgClient(connStr, 1); @@ -983,6 +997,19 @@ void create_model::createModel(const std::string &path, connStr += " client_encoding="; connStr += escapeConnString(characterSet); } + auto options = config["connect_options"]; + if (options.isObject() && !options.empty()) + { + std::string optionStr; + for (auto const &key : options.getMemberNames()) + { + optionStr += " "; + optionStr += escapeConnString(key); + optionStr += "="; + optionStr += escapeConnString(options[key].asString()); + } + connStr += optionStr; + } DbClientPtr client = drogon::orm::DbClient::newMysqlClient(connStr, 1); std::cout << "Connect to server..." << std::endl; if (forceOverwrite_) From 8e824a26095c7c81cbfd16fc3a243b4779d499bb Mon Sep 17 00:00:00 2001 From: an-tao Date: Thu, 7 Aug 2025 15:12:05 +0800 Subject: [PATCH 6/6] Add some comments in configuration files --- config.example.json | 6 ++++-- drogon_ctl/templates/config_json.csp | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/config.example.json b/config.example.json index d6446a0b52..856163db21 100644 --- a/config.example.json +++ b/config.example.json @@ -69,8 +69,10 @@ //auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see //the wiki for more details. "auto_batch": false - //connect_options: extra options for the connection. Only works for PostgreSQL now. - //For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS + //connect_options: extra options for the connection. + //For PostgreSQL, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS + //For MySQL, the valid options are:ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher, see + //https://dev.mysql.com/doc/c-api/8.4/en/mysql-ssl-set.html //"connect_options": { "statement_timeout": "1s" } } ], diff --git a/drogon_ctl/templates/config_json.csp b/drogon_ctl/templates/config_json.csp index a02bba1a12..ab195684aa 100644 --- a/drogon_ctl/templates/config_json.csp +++ b/drogon_ctl/templates/config_json.csp @@ -69,8 +69,10 @@ //auto_batch: this feature is only available for the PostgreSQL driver(version >= 14.0), see //the wiki for more details. "auto_batch": false - //connect_options: extra options for the connection. Only works for PostgreSQL now. - //For more information, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS + //connect_options: extra options for the connection. + //For PostgreSQL, see https://www.postgresql.org/docs/16/libpq-connect.html#LIBPQ-CONNECT-OPTIONS + //For MySQL, the valid options are:ssl_key, ssl_cert, ssl_ca, ssl_capath, ssl_cipher, see + //https://dev.mysql.com/doc/c-api/8.4/en/mysql-ssl-set.html //"connect_options": { "statement_timeout": "1s" } } ], @@ -108,7 +110,7 @@ "session_timeout": 0, //string value of SameSite attribute of the Set-Cookie HTTP response header //valid value is either 'Null' (default), 'Lax', 'Strict' or 'None' - "session_same_site" : "Null", + "session_same_site": "Null", //session_cookie_key: The cookie key of the session, "JSESSIONID" by default "session_cookie_key": "JSESSIONID", //session_max_age: The max age of the session cookie, -1 by default