save compiled regex

This commit is contained in:
Alexander Tokmakov 2020-04-28 01:19:24 +03:00
parent e72a484beb
commit 9d43c2f6c2
2 changed files with 33 additions and 25 deletions

View File

@ -757,7 +757,7 @@ std::string DynamicQueryHandler::getQuery(Poco::Net::HTTPServerRequest & request
PredefinedQueryHandler::PredefinedQueryHandler( PredefinedQueryHandler::PredefinedQueryHandler(
IServer & server, const NameSet & receive_params_, const std::string & predefined_query_ IServer & server, const NameSet & receive_params_, const std::string & predefined_query_
, const std::optional<String> & url_regex_, const std::unordered_map<String, String> & header_name_with_regex_) , const CompiledRegexPtr & url_regex_, const std::unordered_map<String, CompiledRegexPtr> & header_name_with_regex_)
: HTTPHandler(server, "PredefinedQueryHandler"), receive_params(receive_params_), predefined_query(predefined_query_) : HTTPHandler(server, "PredefinedQueryHandler"), receive_params(receive_params_), predefined_query(predefined_query_)
, url_regex(url_regex_), header_name_with_capture_regex(header_name_with_regex_) , url_regex(url_regex_), header_name_with_capture_regex(header_name_with_regex_)
{ {
@ -779,14 +779,8 @@ void PredefinedQueryHandler::customizeContext(Poco::Net::HTTPServerRequest & req
/// If in the configuration file, the handler's header is regex and contains named capture group /// If in the configuration file, the handler's header is regex and contains named capture group
/// We will extract regex named capture groups as query parameters /// We will extract regex named capture groups as query parameters
const auto & set_query_params = [&](const char * begin, const char * end, const std::string & regex) const auto & set_query_params = [&](const char * begin, const char * end, const CompiledRegexPtr & compiled_regex)
{ {
auto compiled_regex = std::make_shared<re2_st::RE2>(regex);
if (!compiled_regex->ok())
throw Exception("cannot compile re2: " + regex + " for http handling rule, error: " + compiled_regex->error() +
". Look at https://github.com/google/re2/wiki/Syntax for reference.", ErrorCodes::CANNOT_COMPILE_REGEXP);
int num_captures = compiled_regex->NumberOfCapturingGroups() + 1; int num_captures = compiled_regex->NumberOfCapturingGroups() + 1;
re2_st::StringPiece matches[num_captures]; re2_st::StringPiece matches[num_captures];
@ -806,7 +800,7 @@ void PredefinedQueryHandler::customizeContext(Poco::Net::HTTPServerRequest & req
if (url_regex) if (url_regex)
{ {
const auto & uri = request.getURI(); const auto & uri = request.getURI();
set_query_params(uri.data(), find_first_symbols<'?'>(uri.data(), uri.data() + uri.size()), *url_regex); set_query_params(uri.data(), find_first_symbols<'?'>(uri.data(), uri.data() + uri.size()), url_regex);
} }
for (const auto & [header_name, regex] : header_name_with_capture_regex) for (const auto & [header_name, regex] : header_name_with_capture_regex)
@ -834,14 +828,8 @@ Poco::Net::HTTPRequestHandlerFactory * createDynamicHandlerFactory(IServer & ser
return addFiltersFromConfig(new HandlingRuleHTTPHandlerFactory<DynamicQueryHandler>(server, std::move(query_param_name)), server.config(), config_prefix); return addFiltersFromConfig(new HandlingRuleHTTPHandlerFactory<DynamicQueryHandler>(server, std::move(query_param_name)), server.config(), config_prefix);
} }
static inline bool capturingNamedQueryParam(NameSet receive_params, const std::string & expression) static inline bool capturingNamedQueryParam(NameSet receive_params, const CompiledRegexPtr & compiled_regex)
{ {
auto compiled_regex = std::make_shared<re2_st::RE2>(expression);
if (!compiled_regex->ok())
throw Exception("Cannot compile re2: " + expression + " for http handling rule, error: " +
compiled_regex->error() + ". Look at https://github.com/google/re2/wiki/Syntax for reference.", ErrorCodes::CANNOT_COMPILE_REGEXP);
const auto & capturing_names = compiled_regex->NamedCapturingGroups(); const auto & capturing_names = compiled_regex->NamedCapturingGroups();
return std::count_if(capturing_names.begin(), capturing_names.end(), [&](const auto & iterator) return std::count_if(capturing_names.begin(), capturing_names.end(), [&](const auto & iterator)
{ {
@ -850,6 +838,17 @@ static inline bool capturingNamedQueryParam(NameSet receive_params, const std::s
}); });
} }
static inline CompiledRegexPtr getCompiledRegex(const std::string & expression)
{
auto compiled_regex = std::make_shared<const re2_st::RE2>(expression);
if (!compiled_regex->ok())
throw Exception("Cannot compile re2: " + expression + " for http handling rule, error: " +
compiled_regex->error() + ". Look at https://github.com/google/re2/wiki/Syntax for reference.", ErrorCodes::CANNOT_COMPILE_REGEXP);
return compiled_regex;
}
Poco::Net::HTTPRequestHandlerFactory * createPredefinedHandlerFactory(IServer & server, const std::string & config_prefix) Poco::Net::HTTPRequestHandlerFactory * createPredefinedHandlerFactory(IServer & server, const std::string & config_prefix)
{ {
Poco::Util::AbstractConfiguration & configuration = server.config(); Poco::Util::AbstractConfiguration & configuration = server.config();
@ -860,7 +859,7 @@ Poco::Net::HTTPRequestHandlerFactory * createPredefinedHandlerFactory(IServer &
std::string predefined_query = configuration.getString(config_prefix + ".handler.query"); std::string predefined_query = configuration.getString(config_prefix + ".handler.query");
NameSet analyze_receive_params = analyzeReceiveQueryParams(predefined_query); NameSet analyze_receive_params = analyzeReceiveQueryParams(predefined_query);
std::unordered_map<String, String> headers_name_with_regex; std::unordered_map<String, CompiledRegexPtr> headers_name_with_regex;
Poco::Util::AbstractConfiguration::Keys headers_name; Poco::Util::AbstractConfiguration::Keys headers_name;
configuration.keys(config_prefix + ".headers", headers_name); configuration.keys(config_prefix + ".headers", headers_name);
@ -872,8 +871,9 @@ Poco::Net::HTTPRequestHandlerFactory * createPredefinedHandlerFactory(IServer &
continue; continue;
expression = expression.substr(6); expression = expression.substr(6);
if (capturingNamedQueryParam(analyze_receive_params, expression)) auto regex = getCompiledRegex(expression);
headers_name_with_regex.emplace(std::make_pair(header_name, expression)); if (capturingNamedQueryParam(analyze_receive_params, regex))
headers_name_with_regex.emplace(std::make_pair(header_name, regex));
} }
if (configuration.has(config_prefix + ".url")) if (configuration.has(config_prefix + ".url"))
@ -883,14 +883,15 @@ Poco::Net::HTTPRequestHandlerFactory * createPredefinedHandlerFactory(IServer &
if (startsWith(url_expression, "regex:")) if (startsWith(url_expression, "regex:"))
url_expression = url_expression.substr(6); url_expression = url_expression.substr(6);
if (capturingNamedQueryParam(analyze_receive_params, url_expression)) auto regex = getCompiledRegex(url_expression);
if (capturingNamedQueryParam(analyze_receive_params, regex))
return addFiltersFromConfig(new HandlingRuleHTTPHandlerFactory<PredefinedQueryHandler>( return addFiltersFromConfig(new HandlingRuleHTTPHandlerFactory<PredefinedQueryHandler>(
server, std::move(analyze_receive_params), std::move(predefined_query), std::optional<String>(url_expression), server, std::move(analyze_receive_params), std::move(predefined_query), std::move(regex),
std::move(headers_name_with_regex)), configuration, config_prefix); std::move(headers_name_with_regex)), configuration, config_prefix);
} }
return addFiltersFromConfig(new HandlingRuleHTTPHandlerFactory<PredefinedQueryHandler>( return addFiltersFromConfig(new HandlingRuleHTTPHandlerFactory<PredefinedQueryHandler>(
server, std::move(analyze_receive_params), std::move(predefined_query), std::optional<String>{} ,std::move(headers_name_with_regex)), server, std::move(analyze_receive_params), std::move(predefined_query), CompiledRegexPtr{} ,std::move(headers_name_with_regex)),
configuration, config_prefix); configuration, config_prefix);
} }

View File

@ -7,6 +7,12 @@
#include <Common/CurrentMetrics.h> #include <Common/CurrentMetrics.h>
#include <Common/HTMLForm.h> #include <Common/HTMLForm.h>
#include <re2/re2.h>
#if USE_RE2_ST
#include <re2_st/re2.h>
#else
#define re2_st re2
#endif
namespace CurrentMetrics namespace CurrentMetrics
{ {
@ -20,6 +26,7 @@ namespace DB
class WriteBufferFromHTTPServerResponse; class WriteBufferFromHTTPServerResponse;
typedef std::shared_ptr<const re2_st::RE2> CompiledRegexPtr;
class HTTPHandler : public Poco::Net::HTTPRequestHandler class HTTPHandler : public Poco::Net::HTTPRequestHandler
{ {
@ -101,12 +108,12 @@ class PredefinedQueryHandler : public HTTPHandler
private: private:
NameSet receive_params; NameSet receive_params;
std::string predefined_query; std::string predefined_query;
std::optional<String> url_regex; CompiledRegexPtr url_regex;
std::unordered_map<String, String> header_name_with_capture_regex; std::unordered_map<String, CompiledRegexPtr> header_name_with_capture_regex;
public: public:
explicit PredefinedQueryHandler( explicit PredefinedQueryHandler(
IServer & server, const NameSet & receive_params_, const std::string & predefined_query_ IServer & server, const NameSet & receive_params_, const std::string & predefined_query_
, const std::optional<String> & url_regex_, const std::unordered_map<String, String> & header_name_with_regex_); , const CompiledRegexPtr & url_regex_, const std::unordered_map<String, CompiledRegexPtr> & header_name_with_regex_);
virtual void customizeContext(Poco::Net::HTTPServerRequest & request, Context & context) override; virtual void customizeContext(Poco::Net::HTTPServerRequest & request, Context & context) override;