Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions config.example.json
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
}
],
Expand Down
27 changes: 27 additions & 0 deletions drogon_ctl/create_model.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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_)
Expand Down
8 changes: 5 additions & 3 deletions drogon_ctl/templates/config_json.csp
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
}
],
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion lib/src/HttpAppFrameworkImpl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,8 @@ void HttpAppFrameworkImpl::addDbClient(
name,
isFast,
characterSet,
timeout});
timeout,
std::move(options)});
}
else if (dbType == "sqlite3")
{
Expand Down
1 change: 1 addition & 0 deletions orm_lib/inc/drogon/orm/DbConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct MysqlConfig
bool isFast;
std::string characterSet;
double timeout;
std::unordered_map<std::string, std::string> connectOptions;
};

struct Sqlite3Config
Expand Down
12 changes: 12 additions & 0 deletions orm_lib/src/DbClientManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ void DbClientManager::addDbClient(const DbConfig &config)
cfg.username,
cfg.password,
cfg.characterSet);
if (!cfg.connectOptions.empty())
{
std::string optionStr;
for (auto const &[key, value] : cfg.connectOptions)
{
optionStr += " ";
optionStr += escapeConnString(key);
optionStr += "=";
optionStr += escapeConnString(value);
}
connStr += optionStr;
}
dbInfos_.emplace_back(DbInfo{connStr, config});
#else
std::cout << "The Mysql is not supported in current drogon build, "
Expand Down
49 changes: 42 additions & 7 deletions orm_lib/src/mysql_impl/MysqlConnection.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,18 @@ MysqlConnection::MysqlConnection(trantor::EventLoop *loop,
static MysqlEnv env;
static thread_local MysqlThreadEnv threadEnv;
mysql_init(mysqlPtr_.get());
Copy link

Copilot AI Aug 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mysql_ssl_set() call lacks documentation explaining its purpose and the implications of using null parameters. Consider adding a comment explaining that this enables SSL with default settings and that certificate verification is not performed.

Suggested change
mysql_init(mysqlPtr_.get());
mysql_init(mysqlPtr_.get());
// Enable SSL with default settings. All parameters are set to nullptr,
// which means SSL is enabled but certificate verification is NOT performed.
// This may have security implications; see MySQL C API documentation for details.

Copilot uses AI. Check for mistakes.
mysql_options(mysqlPtr_.get(), MYSQL_OPT_NONBLOCK, nullptr);
#ifdef HAS_MYSQL_OPTIONSV
mysql_optionsv(mysqlPtr_.get(), MYSQL_OPT_RECONNECT, &reconnect_);
#endif
// Get the key and value
// 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); });
// LOG_TRACE << key << "=" << value;
LOG_DEBUG << "connInfo key:[" << key << "] value:[" << value << "]";
if (key == "host")
{
host_ = value;
Expand All @@ -100,7 +96,46 @@ MysqlConnection::MysqlConnection(trantor::EventLoop *loop,
{
characterSet_ = value;
}
else 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_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(),
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_);
#endif
}

void MysqlConnection::init()
Expand Down
Loading