diff --git a/include/iocore/net/SSLSNIConfig.h b/include/iocore/net/SSLSNIConfig.h index 609b4c9a5b1..4e2612cad8c 100644 --- a/include/iocore/net/SSLSNIConfig.h +++ b/include/iocore/net/SSLSNIConfig.h @@ -37,15 +37,8 @@ #include #include -#if __has_include("pcre/pcre.h") -#include -#elif __has_include("pcre.h") -#include -#else -#error "Unable to locate PCRE heeader" -#endif - #include "tsutil/ts_ip.h" +#include "tsutil/Regex.h" #include "iocore/eventsystem/ConfigProcessor.h" #include "iocore/net/SNIActionItem.h" @@ -63,14 +56,6 @@ struct NextHopProperty { using ActionVector = std::vector>; -struct PcreFreer { - void - operator()(void *p) - { - pcre_free(p); - } -}; - struct NamedElement { NamedElement() {} @@ -85,7 +70,7 @@ struct NamedElement { std::vector inbound_port_ranges; - std::unique_ptr match; + Regex match; uint32_t rank = 0; ///< order of the config. smaller is higher. }; diff --git a/include/tsutil/Regex.h b/include/tsutil/Regex.h index 9852269e1cf..d7b4f1c5d38 100644 --- a/include/tsutil/Regex.h +++ b/include/tsutil/Regex.h @@ -91,6 +91,7 @@ class Regex Regex() = default; Regex(Regex const &) = delete; // No copying. Regex(Regex &&that) noexcept; + Regex &operator=(Regex &&other); ~Regex(); /** Compile the @a pattern into a regular expression. @@ -140,6 +141,9 @@ class Regex /// @return The number of capture groups in the compiled pattern. int get_capture_count(); + /// @return Is the compiled pattern empty? + bool empty() const; + private: /// @internal This effectively wraps a void* so that we can avoid requiring the pcre2.h include for the user of the Regex /// API (see Regex.cc). diff --git a/src/iocore/net/SSLSNIConfig.cc b/src/iocore/net/SSLSNIConfig.cc index 19b631e782c..d43126aff6d 100644 --- a/src/iocore/net/SSLSNIConfig.cc +++ b/src/iocore/net/SSLSNIConfig.cc @@ -42,15 +42,12 @@ #include #include #include -#include #include #include #include namespace { -constexpr int OVECSIZE{30}; - DbgCtl dbg_ctl_ssl{"ssl"}; DbgCtl dbg_ctl_ssl_sni{"ssl_sni"}; DbgCtl dbg_ctl_sni{"sni"}; @@ -100,10 +97,8 @@ NamedElement::set_glob_name(std::string name) void NamedElement::set_regex_name(const std::string ®ex_name) { - const char *err_ptr; - int err_offset = 0; if (!regex_name.empty()) { - match.reset(pcre_compile(regex_name.c_str(), PCRE_ANCHORED | PCRE_CASELESS, &err_ptr, &err_offset, nullptr)); + match.compile(regex_name, REFlags::RE_ANCHORED | REFlags::RE_CASE_INSENSITIVE); } } @@ -115,7 +110,7 @@ SNIConfigParams::get_property_config(const std::string &servername) const { const NextHopProperty *nps = nullptr; for (auto &&item : next_hop_list) { - if (pcre_exec(item.match.get(), nullptr, servername.c_str(), servername.length(), 0, 0, nullptr, 0) >= 0) { + if (item.match.exec(servername)) { // Found a match nps = &item.prop; break; @@ -231,43 +226,28 @@ SNIConfigParams::get(std::string_view servername, in_port_t dest_incoming_port) } // Check for wildcard matches - int ovector[OVECSIZE]; + RegexMatches matches; for (auto const &retval : sni_action_list) { if (element != nullptr && element->rank < retval.rank) { break; } - int length = servername.length(); - if (retval.match == nullptr && length == 0) { + if (retval.match.empty() && servername.length() == 0) { return {&retval.actions, {}}; - } else if (auto offset = pcre_exec(retval.match.get(), nullptr, servername.data(), length, 0, 0, ovector, OVECSIZE); - offset >= 0) { + } else if (retval.match.exec(servername, matches) >= 0) { if (!is_port_in_the_ranges(retval.inbound_port_ranges, dest_incoming_port)) { continue; } - if (offset == 1) { - // first pair identify the portion of the subject string matched by the entire pattern - if (ovector[0] == 0 && ovector[1] == length) { - // full match - return {&retval.actions, {}}; - } else { - continue; - } - } - // If contains groups - if (offset == 0) { - // reset to max if too many. - offset = OVECSIZE / 3; + if (matches.size() == 1) { + // full match + return {&retval.actions, {}}; } ActionItem::Context::CapturedGroupViewVec groups; - groups.reserve(offset); - for (int strnum = 1; strnum < offset; strnum++) { - const std::size_t start = ovector[2 * strnum]; - const std::size_t length = ovector[2 * strnum + 1] - start; - - groups.emplace_back(servername.data() + start, length); + groups.reserve(matches.size()); + for (int count = 1; count < matches.size(); count++) { + groups.emplace_back(matches[count]); } return {&retval.actions, {std::move(groups)}}; } diff --git a/src/tsutil/Regex.cc b/src/tsutil/Regex.cc index d1410da32eb..19095323a4c 100644 --- a/src/tsutil/Regex.cc +++ b/src/tsutil/Regex.cc @@ -213,6 +213,21 @@ Regex::Regex(Regex &&that) noexcept _Code::set(that._code, nullptr); } +//---------------------------------------------------------------------------- +Regex & +Regex::operator=(Regex &&other) +{ + if (this != &other) { + auto ptr = _Code::get(_code); + if (ptr != nullptr) { + pcre2_code_free(ptr); + } + _code = other._code; + _Code::set(other._code, nullptr); + } + return *this; +} + //---------------------------------------------------------------------------- Regex::~Regex() { @@ -297,12 +312,14 @@ Regex::exec(std::string_view subject, RegexMatches &matches) const matches._size = count; - if (count < 0) { - return count; - } - - if (count > 0) { + // match was successful + if (count >= 0) { matches._subject = subject; + + // match but the output vector was too small, adjust the size of the matches + if (count == 0) { + matches._size = pcre2_get_ovector_count(RegexMatches::_MatchData::get(matches._match_data)); + } } return count; @@ -319,6 +336,13 @@ Regex::get_capture_count() return captures; } +//---------------------------------------------------------------------------- +bool +Regex::empty() const +{ + return _Code::get(_code) == nullptr; +} + //---------------------------------------------------------------------------- DFA::~DFA() {}