Fix failing to connect to DB if parameters contains spaces (#589)

This commit is contained in:
Martin Chang 2020-10-01 19:47:51 +08:00 committed by GitHub
parent bbb338bf12
commit ada35c43fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 106 additions and 41 deletions

View File

@ -251,6 +251,7 @@ if(pg_FOUND OR MySQL_FOUND OR SQLite3_FOUND)
orm_lib/src/DbClientImpl.cc
orm_lib/src/DbClientLockFree.cc
orm_lib/src/DbClientManager.cc
orm_lib/src/DbConnection.cc
orm_lib/src/Exception.cc
orm_lib/src/Field.cc
orm_lib/src/Result.cc

View File

@ -1,7 +1,7 @@
/**
*
* DbClientManager.cc
* An Tao
* @file DbClientManager.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
@ -22,6 +22,26 @@
using namespace drogon::orm;
using namespace drogon;
inline std::string escapeConnString(const std::string &str)
{
bool beQuoted = str.empty() || (str.find(' ') != std::string::npos);
std::string escaped;
escaped.reserve(str.size());
for (auto ch : str)
{
if (ch == '\'')
escaped.push_back('\\');
else if (ch == '\\')
escaped.push_back('\\');
escaped.push_back(ch);
}
if (beQuoted)
return "'" + escaped + "'";
return escaped;
}
void DbClientManager::createDbClients(
const std::vector<trantor::EventLoop *> &ioloops)
{
@ -97,22 +117,23 @@ void DbClientManager::createDbClient(const std::string &dbType,
const bool isFast,
const std::string &characterSet)
{
auto connStr = utils::formattedString("host=%s port=%u dbname=%s user=%s",
host.c_str(),
port,
databaseName.c_str(),
userName.c_str());
auto connStr =
utils::formattedString("host=%s port=%u dbname=%s user=%s",
escapeConnString(host).c_str(),
port,
escapeConnString(databaseName).c_str(),
escapeConnString(userName).c_str());
if (!password.empty())
{
connStr += " password=";
connStr += password;
connStr += escapeConnString(password);
}
std::string type = dbType;
std::transform(type.begin(), type.end(), type.begin(), tolower);
if (!characterSet.empty())
{
connStr += " client_encoding=";
connStr += characterSet;
connStr += escapeConnString(characterSet);
}
DbInfo info;
info.connectionInfo_ = connStr;

View File

@ -0,0 +1,57 @@
/**
*
* @file DbConnection.cc
* @author Martin Chang
*
* Copyright 2020, Martin Chang. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "DbConnection.h"
#include <regex>
using namespace drogon::orm;
std::map<std::string, std::string> DbConnection::parseConnString(
const std::string& connInfo)
{
const static std::regex re(
R"((\w+) *= *('(?:[^\n]|\\[^\n])+'|(?:\S|\\\S)+))");
std::smatch what;
std::map<std::string, std::string> params;
std::string str = connInfo;
while (std::regex_search(str, what, re))
{
assert(what.size() == 3);
std::string key = what[1];
std::string rawValue = what[2];
std::string value;
bool quoted =
!rawValue.empty() && rawValue[0] == '\'' && rawValue.back() == '\'';
value.reserve(rawValue.size());
for (size_t i = 0; i < rawValue.size(); i++)
{
if (quoted && (i == 0 || i == rawValue.size() - 1))
continue;
else if (rawValue[i] == '\\' && i != rawValue.size() - 1)
{
value.push_back(rawValue[i + 1]);
i += 1;
continue;
}
value.push_back(rawValue[i]);
}
params[key] = value;
str = what.suffix().str();
}
return params;
}

View File

@ -1,7 +1,7 @@
/**
*
* DbConnection.h
* An Tao
* @file DbConnection.h
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
@ -134,6 +134,9 @@ class DbConnection : public trantor::NonCopyable
DbConnectionCallback okCallback_{[](const DbConnectionPtr &) {}};
std::function<void(const std::exception_ptr &)> exceptionCallback_;
bool isWorking_{false};
static std::map<std::string, std::string> parseConnString(
const std::string &);
};
} // namespace orm

View File

@ -1,7 +1,7 @@
/**
*
* MysqlConnection.cc
* An Tao
* @file MysqlConnection.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
@ -57,20 +57,12 @@ MysqlConnection::MysqlConnection(trantor::EventLoop *loop,
mysql_options(mysqlPtr_.get(), MYSQL_OPT_NONBLOCK, 0);
// Get the key and value
std::regex r(" *= *");
auto tmpStr = std::regex_replace(connInfo, r, "=");
auto keyValues = utils::splitString(tmpStr, " ");
for (auto const &kvs : keyValues)
auto connParams = parseConnString(connInfo);
for (auto const &kv : connParams)
{
auto kv = utils::splitString(kvs, "=");
assert(kv.size() == 2);
auto key = kv[0];
auto value = kv[1];
if (value[0] == '\'' && value[value.length() - 1] == '\'')
{
value = value.substr(1, value.length() - 2);
}
auto key = kv.first;
auto value = kv.second;
std::transform(key.begin(), key.end(), key.begin(), tolower);
// LOG_TRACE << key << "=" << value;
if (key == "host")

View File

@ -1,7 +1,7 @@
/**
*
* Sqlite3Connection.cc
* An Tao
* @file Sqlite3Connection.cc
* @author An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
@ -55,21 +55,12 @@ Sqlite3Connection::Sqlite3Connection(
}
});
// Get the key and value
std::regex r(" *= *");
auto tmpStr = std::regex_replace(connInfo, r, "=");
std::string host, user, passwd, dbname, port;
auto keyValues = utils::splitString(tmpStr, " ");
auto connParams = parseConnString(connInfo);
std::string filename;
for (auto const &kvs : keyValues)
for (auto const &kv : connParams)
{
auto kv = utils::splitString(kvs, "=");
assert(kv.size() == 2);
auto key = kv[0];
auto value = kv[1];
if (value[0] == '\'' && value[value.length() - 1] == '\'')
{
value = value.substr(1, value.length() - 2);
}
auto key = kv.first;
auto value = kv.second;
std::transform(key.begin(), key.end(), key.begin(), tolower);
if (key == "filename")
{