diff --git a/include/maxscale/config.hh b/include/maxscale/config.hh index 39742ded5..8647a586f 100644 --- a/include/maxscale/config.hh +++ b/include/maxscale/config.hh @@ -349,6 +349,45 @@ public: */ SERVER* get_server(const std::string& key) const; + /** + * Get an array of servers. The value is expected to be a comma-separated list of server names. + * + * @param key Parameter name + * @param name_error_out If a server name was not found, it is written here. Only the first such name + * is written. + * @return Found servers. If even one server name was invalid, the array will be empty. + */ + std::vector get_server_list(const std::string& key, std::string* name_error_out = nullptr) const; + + /** + * Get a compiled regular expression and the ovector size of the pattern. The + * return value should be freed by the caller. + * + * @param key Parameter name + * @param options PCRE2 compilation options + * @param output_ovec_size Output for match data ovector size. On error, + * nothing is written. If NULL, the parameter is ignored. + * @return Compiled regex code on success. NULL if key was not found or compilation failed. + */ + std::unique_ptr + get_compiled_regex(const std::string& key, uint32_t options, uint32_t* output_ovec_size) const; + + /** + * Get multiple compiled regular expressions and the maximum ovector size of + * the patterns. The returned regex codes should be freed by the caller. + * + * @param keys An array of parameter keys. + * @param options PCRE2 compilation options + * @param ovec_size_out If not null, the maximum ovector size of successfully + * compiled patterns is written here. + * @param compile_error_out If not null, is set to true if a pattern compilation failed. + * @return Array of compiled patterns, one element for each key. If a key is not found or the pattern + * cannot be compiled, the corresponding element will be null. + */ + std::vector> + get_compiled_regexes(const std::vector& keys, uint32_t options, + uint32_t* ovec_size_out, bool* compile_error_out); + /** * Check if a key exists. * @@ -500,61 +539,6 @@ bool config_param_is_valid(const MXS_MODULE_PARAM* params, const char* value, const CONFIG_CONTEXT* context); -/** - * @brief Get an array of servers. The caller should free the produced array, - * but not the array elements. - * - * @param params List of configuration parameters - * @param key Parameter name - * @param name_error_out If a server name was not found, it is written here. Only the first such name - * is written. - * @return Found servers. If even one server name was invalid, the array will be empty. - */ -std::vector -config_get_server_list(const MXS_CONFIG_PARAMETER* params, const char* key, - std::string* name_error_out = nullptr); - -/** - * Get a compiled regular expression and the ovector size of the pattern. The - * return value should be freed by the caller. - * - * @param params List of configuration parameters - * @param key Parameter name - * @param options PCRE2 compilation options - * @param output_ovec_size Output for match data ovector size. On error, - * nothing is written. If NULL, the parameter is ignored. - * @return Compiled regex code on success, NULL otherwise - */ -pcre2_code* config_get_compiled_regex(const MXS_CONFIG_PARAMETER* params, - const char* key, - uint32_t options, - uint32_t* output_ovec_size); - -/** - * Get multiple compiled regular expressions and the maximum ovector size of - * the patterns. The returned regex codes should be freed by the caller. - * - * @param params List of configuration parameters - * @param keys An array of parameter names. If an element is not found in @c params, - * the corresponding spot in @c out_codes is set to NULL. - * @param keys_size Size of both @c keys and @c out_arr - * @param options PCRE2 compilation options - * @param out_ovec_size If not NULL, the maximum ovector size of successfully - * compiled patterns is written here. - * @param out_codes An array of handles to compiled codes. The referenced pointers - * will be set to point to the compiled codes. The array size must be equal to - * @c keys array size and it must contain valid pointers. - * - * @return True, if all patterns given by @c keys were successfully compiled. - * False otherwise. - */ -bool config_get_compiled_regexes(const MXS_CONFIG_PARAMETER* params, - const char* keys[], - int keys_size, - uint32_t options, - uint32_t* out_ovec_size, - pcre2_code** out_codes[]); - /** * Break a comma-separated list into a string array. Removes whitespace from list items. * diff --git a/include/maxscale/pcre2.hh b/include/maxscale/pcre2.hh index 290d93a27..15279f98d 100644 --- a/include/maxscale/pcre2.hh +++ b/include/maxscale/pcre2.hh @@ -63,3 +63,21 @@ struct CloserTraits } }; } + +namespace std +{ + +template<> class default_delete +{ +public: + void operator()(pcre2_code* p) + { + if (p) + { + pcre2_code_free(p); + } + } +}; + +} + diff --git a/server/core/config.cc b/server/core/config.cc index 3463fa832..64309497d 100644 --- a/server/core/config.cc +++ b/server/core/config.cc @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include #include #include @@ -1732,10 +1732,9 @@ bool MXS_CONFIG_PARAMETER::contains(const string& key) const return can_be_null ? m_contents.count(key) > 0 : false; } -std::vector config_get_server_list(const MXS_CONFIG_PARAMETER* params, const char* key, - string* name_error_out) +std::vector MXS_CONFIG_PARAMETER::get_server_list(const string& key, string* name_error_out) const { - auto names_list = params->get_string(key); + auto names_list = get_string(key); auto server_names = config_break_list_string(names_list); std::vector server_arr = SERVER::server_find_by_unique_names(server_names); for (size_t i = 0; i < server_arr.size(); i++) @@ -1765,58 +1764,60 @@ char* MXS_CONFIG_PARAMETER::get_c_str_copy(const string& key) const return rval; } -pcre2_code* config_get_compiled_regex(const MXS_CONFIG_PARAMETER* params, - const char* key, - uint32_t options, - uint32_t* output_ovec_size) +std::unique_ptr +MXS_CONFIG_PARAMETER::get_compiled_regex(const string& key, uint32_t options, + uint32_t* output_ovec_size) const { - auto regex_string = params->get_string(key); - pcre2_code* code = NULL; + auto regex_string = get_string(key); + std::unique_ptr code; if (!regex_string.empty()) { uint32_t jit_available = 0; pcre2_config(PCRE2_CONFIG_JIT, &jit_available); - code = compile_regex_string(regex_string.c_str(), jit_available, options, output_ovec_size); + code.reset(compile_regex_string(regex_string.c_str(), jit_available, options, output_ovec_size)); } return code; } -bool config_get_compiled_regexes(const MXS_CONFIG_PARAMETER* params, - const char* keys[], - int keys_size, - uint32_t options, - uint32_t* out_ovec_size, - pcre2_code** out_codes[]) +std::vector> +MXS_CONFIG_PARAMETER::get_compiled_regexes(const std::vector& keys, uint32_t options, + uint32_t* ovec_size_out, bool* compile_error_out) { - bool rval = true; + std::vector> rval; + bool compile_error = false; uint32_t max_ovec_size = 0; uint32_t ovec_size_temp = 0; - for (int i = 0; i < keys_size; i++) + for (auto& key : keys) { - mxb_assert(out_codes[i]); - *out_codes[i] = config_get_compiled_regex(params, - keys[i], - options, - &ovec_size_temp); - if (*out_codes[i]) + std::unique_ptr code; + /* get_compiled_regex() returns null if the config setting didn't exist. */ + if (contains(key)) { - if (ovec_size_temp > max_ovec_size) + code = get_compiled_regex(key, options, &ovec_size_temp); + if (code) { - max_ovec_size = ovec_size_temp; + if (ovec_size_temp > max_ovec_size) + { + max_ovec_size = ovec_size_temp; + } + } + else + { + compile_error = true; } } - /* config_get_compiled_regex() returns null also if the config setting - * didn't exist. Check that before setting error state. */ - else if (params->contains(keys[i])) - { - rval = false; - } + rval.push_back(std::move(code)); } - if (out_ovec_size) + + if (ovec_size_out) { - *out_ovec_size = max_ovec_size; + *ovec_size_out = max_ovec_size; + } + if (compile_error_out) + { + *compile_error_out = compile_error; } return rval; } @@ -3724,7 +3725,7 @@ int create_new_monitor(CONFIG_CONTEXT* obj, std::set& monitored_ser if (params->contains(CN_SERVERS)) { string name_not_found; - auto servers = config_get_server_list(params, CN_SERVERS, &name_not_found); + auto servers = params->get_server_list(CN_SERVERS, &name_not_found); if (servers.empty()) { err = true; diff --git a/server/core/monitor.cc b/server/core/monitor.cc index 1ecfe0fe1..b454e7d54 100644 --- a/server/core/monitor.cc +++ b/server/core/monitor.cc @@ -214,7 +214,7 @@ bool Monitor::configure_base(const MXS_CONFIG_PARAMETER* params) m_settings.conn_settings.password = params->get_string(CN_PASSWORD); // The monitor serverlist has already been checked to be valid. Empty value is ok too. - auto servers_temp = config_get_server_list(params, CN_SERVERS); + auto servers_temp = params->get_server_list(CN_SERVERS); for (auto elem : servers_temp) { // This function checks if server is already monitored. TODO: This should be a config error. @@ -2233,7 +2233,7 @@ std::vector mon_config_get_servers(const MXS_CONFIG_PARAM } string name_error; - auto servers = config_get_server_list(params, key, &name_error); + auto servers = params->get_server_list(key, &name_error); if (!servers.empty()) { // All servers in the array must be monitored by the given monitor. diff --git a/server/modules/filter/binlogfilter/binlogfilter.hh b/server/modules/filter/binlogfilter/binlogfilter.hh index 5cfafa5c6..5b1cb1307 100644 --- a/server/modules/filter/binlogfilter/binlogfilter.hh +++ b/server/modules/filter/binlogfilter/binlogfilter.hh @@ -15,15 +15,16 @@ #include #include #include +#include #include "binlogfiltersession.hh" // Binlog Filter configuration struct BinlogConfig { BinlogConfig(const MXS_CONFIG_PARAMETER* pParams) - : match(config_get_compiled_regex(pParams, "match", 0, nullptr)) + : match(pParams->get_compiled_regex("match", 0, nullptr).release()) , md_match(match ? pcre2_match_data_create_from_pattern(match, nullptr) : nullptr) - , exclude(config_get_compiled_regex(pParams, "exclude", 0, nullptr)) + , exclude(pParams->get_compiled_regex("exclude", 0, nullptr).release()) , md_exclude(exclude ? pcre2_match_data_create_from_pattern(exclude, nullptr) : nullptr) { } diff --git a/server/modules/filter/ccrfilter/ccrfilter.cc b/server/modules/filter/ccrfilter/ccrfilter.cc index 6b9fcfba0..27017f765 100644 --- a/server/modules/filter/ccrfilter/ccrfilter.cc +++ b/server/modules/filter/ccrfilter/ccrfilter.cc @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include using std::string; @@ -97,11 +97,14 @@ public: new_instance->m_nomatch = params->get_string(PARAM_IGNORE); int cflags = params->get_enum("options", option_values); - const char* keys[] = {PARAM_MATCH, PARAM_IGNORE}; - pcre2_code** code_arr[] = {&new_instance->re, &new_instance->nore}; - if (!config_get_compiled_regexes(params, keys, sizeof(keys) / sizeof(char*), - cflags, &new_instance->ovector_size, - code_arr)) + bool compile_error = false; + auto code_arr = params->get_compiled_regexes({PARAM_MATCH, PARAM_IGNORE}, + cflags, + &new_instance->ovector_size, + &compile_error); + new_instance->re = code_arr[0].release(); + new_instance->nore = code_arr[1].release(); + if (compile_error) { delete new_instance; new_instance = nullptr; diff --git a/server/modules/filter/qlafilter/qlafilter.cc b/server/modules/filter/qlafilter/qlafilter.cc index cd7609558..b0069762c 100644 --- a/server/modules/filter/qlafilter/qlafilter.cc +++ b/server/modules/filter/qlafilter/qlafilter.cc @@ -167,29 +167,24 @@ void QlaFilterSession::close() QlaInstance* QlaInstance::create(const std::string name, MXS_CONFIG_PARAMETER* params) { - bool error = false; QlaInstance* my_instance = NULL; - const char* keys[] = {PARAM_MATCH, PARAM_EXCLUDE}; - pcre2_code* re_match = NULL; - pcre2_code* re_exclude = NULL; uint32_t ovec_size = 0; int cflags = params->get_enum(PARAM_OPTIONS, option_values); - pcre2_code** code_arr[] = {&re_match, &re_exclude}; - if (config_get_compiled_regexes(params, - keys, - sizeof(keys) / sizeof(char*), - cflags, - &ovec_size, - code_arr)) + bool compile_error = false; + auto code_arr = params->get_compiled_regexes({PARAM_MATCH, PARAM_EXCLUDE}, cflags, + &ovec_size, &compile_error); + auto re_match = std::move(code_arr[0]); + auto re_exclude = std::move(code_arr[1]); + if (!compile_error) { // The instance is allocated before opening the file since open_log_file() takes the instance as a // parameter. Will be fixed (or at least cleaned) with a later refactoring of functions/methods. my_instance = new(std::nothrow) QlaInstance(name, params); if (my_instance) { - my_instance->m_re_match = re_match; - my_instance->m_re_exclude = re_exclude; + my_instance->m_re_match = re_match.release(); + my_instance->m_re_exclude = re_exclude.release(); my_instance->m_ovec_size = ovec_size; // Try to open the unified log file if (my_instance->m_settings.write_unified_log) @@ -200,24 +195,9 @@ QlaInstance* QlaInstance::create(const std::string name, MXS_CONFIG_PARAMETER* p { delete my_instance; my_instance = NULL; - error = true; } } } - else - { - error = true; - } - } - else - { - error = true; - } - - if (error) - { - pcre2_code_free(re_match); - pcre2_code_free(re_exclude); } return my_instance; diff --git a/server/modules/filter/qlafilter/qlafilter.hh b/server/modules/filter/qlafilter/qlafilter.hh index 24f55bb42..8748b7104 100644 --- a/server/modules/filter/qlafilter/qlafilter.hh +++ b/server/modules/filter/qlafilter/qlafilter.hh @@ -19,7 +19,7 @@ #include #include #include -#include +#include class QlaFilterSession; struct LogEventElems; diff --git a/server/modules/filter/regexfilter/regexfilter.cc b/server/modules/filter/regexfilter/regexfilter.cc index 0d8d8d565..591d166c1 100644 --- a/server/modules/filter/regexfilter/regexfilter.cc +++ b/server/modules/filter/regexfilter/regexfilter.cc @@ -22,7 +22,7 @@ #include #include #include -#include +#include /** * @file regexfilter.c - a very simple regular expression rewrite filter. @@ -229,7 +229,7 @@ static MXS_FILTER* createInstance(const char* name, MXS_CONFIG_PARAMETER* params int cflags = params->get_enum("options", option_values); - if (!(my_instance->re = config_get_compiled_regex(params, "match", cflags, nullptr))) + if (!(my_instance->re = params->get_compiled_regex("match", cflags, nullptr).release())) { free_instance(my_instance); return NULL; diff --git a/server/modules/filter/tee/tee.cc b/server/modules/filter/tee/tee.cc index a71dfab81..4b5eaf11f 100644 --- a/server/modules/filter/tee/tee.cc +++ b/server/modules/filter/tee/tee.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include "tee.hh" #include "teesession.hh" @@ -66,8 +67,8 @@ Tee* Tee::create(const char* name, MXS_CONFIG_PARAMETER* params) { SERVICE* service = params->get_service("service"); uint32_t cflags = params->get_enum("options", option_values); - pcre2_code* match = config_get_compiled_regex(params, "match", cflags, NULL); - pcre2_code* exclude = config_get_compiled_regex(params, "exclude", cflags, NULL); + pcre2_code* match = params->get_compiled_regex("match", cflags, NULL).release(); + pcre2_code* exclude = params->get_compiled_regex("exclude", cflags, NULL).release(); Tee* my_instance = new(std::nothrow) Tee(service, params->get_string("source"), diff --git a/server/modules/routing/avrorouter/avro.cc b/server/modules/routing/avrorouter/avro.cc index 1f9c09ef9..1ac50d0a8 100644 --- a/server/modules/routing/avrorouter/avro.cc +++ b/server/modules/routing/avrorouter/avro.cc @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include @@ -130,8 +130,8 @@ Avro::Avro(SERVICE* service, MXS_CONFIG_PARAMETER* params, SERVICE* source, SRow , row_count(0) , row_target(params->get_integer("group_rows")) , task_handle(0) - , handler(service, handler, config_get_compiled_regex(params, "match", 0, NULL), - config_get_compiled_regex(params, "exclude", 0, NULL)) + , handler(service, handler, params->get_compiled_regex("match", 0, NULL).release(), + params->get_compiled_regex("exclude", 0, NULL).release()) { if (source) { diff --git a/server/modules/routing/schemarouter/schemarouter.cc b/server/modules/routing/schemarouter/schemarouter.cc index 7967359d6..4ad5f27e5 100644 --- a/server/modules/routing/schemarouter/schemarouter.cc +++ b/server/modules/routing/schemarouter/schemarouter.cc @@ -22,7 +22,7 @@ Config::Config(MXS_CONFIG_PARAMETER* conf) : refresh_min_interval(conf->get_integer("refresh_interval")) , refresh_databases(conf->get_bool("refresh_databases")) , debug(conf->get_bool("debug")) - , ignore_regex(config_get_compiled_regex(conf, "ignore_databases_regex", 0, NULL)) + , ignore_regex(conf->get_compiled_regex("ignore_databases_regex", 0, NULL).release()) , ignore_match_data(ignore_regex ? pcre2_match_data_create_from_pattern(ignore_regex, NULL) : NULL) , preferred_server(conf->get_server("preferred_server")) { diff --git a/server/modules/routing/schemarouter/schemarouter.hh b/server/modules/routing/schemarouter/schemarouter.hh index 2e3a2a003..0006816c9 100644 --- a/server/modules/routing/schemarouter/schemarouter.hh +++ b/server/modules/routing/schemarouter/schemarouter.hh @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include