| /* | |
| Licensed to the Apache Software Foundation (ASF) under one | |
| or more contributor license agreements. See the NOTICE file | |
| distributed with this work for additional information | |
| regarding copyright ownership. The ASF licenses this file | |
| to you under the Apache License, Version 2.0 (the | |
| "License"); you may not use this file except in compliance | |
| with the License. You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| #pragma once | |
| // Setup for PCRE2 | |
| #define PCRE2_CODE_UNIT_WIDTH 8 | |
| #include <pcre2.h> | |
| #include <algorithm> | |
| #include <vector> | |
| #include <tuple> | |
| #include "cripts/Headers.hpp" | |
| #include "cripts/Lulu.hpp" | |
| #include "swoc/IPRange.h" | |
| namespace cripts::Matcher | |
| { | |
| namespace Range | |
| { | |
| class IP : public swoc::IPRangeSet | |
| { | |
| using super_type = swoc::IPRangeSet; | |
| using self_type = Range::IP; | |
| public: | |
| IP() = delete; | |
| void operator=(const self_type &) = delete; | |
| explicit IP(cripts::string_view ip) { Add(ip); } | |
| IP(self_type const &ip) | |
| { | |
| for (auto &it : ip) { | |
| mark(it); | |
| } | |
| } | |
| IP(const std::initializer_list<self_type> &list) | |
| { | |
| for (auto &it : list) { | |
| for (auto &it2 : it) { | |
| mark(it2); | |
| } | |
| } | |
| } | |
| IP(std::initializer_list<cripts::string_view> list) | |
| { | |
| for (auto &it : list) { | |
| Add(it); | |
| } | |
| } | |
| bool | |
| Match(sockaddr const *target) const | |
| { | |
| return contains(swoc::IPAddr(target)); | |
| } | |
| [[nodiscard]] bool | |
| Match(in_addr_t target) const | |
| { | |
| return contains(swoc::IPAddr(target)); | |
| } | |
| [[nodiscard]] bool | |
| Match(swoc::IPAddr const &target) const | |
| { | |
| return contains(target); | |
| } | |
| [[nodiscard]] bool | |
| Contains(swoc::IPAddr const &target) const | |
| { | |
| return contains(target); | |
| } | |
| bool | |
| Contains(sockaddr const *target) const | |
| { | |
| return contains(swoc::IPAddr(target)); | |
| } | |
| [[nodiscard]] bool | |
| Contains(in_addr_t target) const | |
| { | |
| return contains(swoc::IPAddr(target)); | |
| } | |
| void | |
| Add(cripts::string_view str) | |
| { | |
| if (swoc::IPRange r; r.load(str)) { | |
| mark(r); | |
| } else { | |
| CFatal("[Matcher::Range::IP] Invalid IP range: %.*s", static_cast<int>(str.size()), str.data()); | |
| } | |
| } | |
| }; // End class IP | |
| } // namespace Range | |
| namespace List | |
| { | |
| class Method : public std::vector<cripts::Header::Method> | |
| { | |
| #undef DELETE // ToDo: macOS shenanigans here, defining DELETE as a macro | |
| using super_type = std::vector<cripts::Header::Method>; | |
| using self_type = Method; | |
| public: | |
| Method() = delete; | |
| explicit Method(cripts::Header::Method method) : std::vector<cripts::Header::Method>() { push_back(method); } | |
| void operator=(const self_type &) = delete; | |
| Method(self_type const &method) : std::vector<cripts::Header::Method>() { insert(end(), std::begin(method), std::end(method)); } | |
| Method(const std::initializer_list<self_type> &list) | |
| { | |
| for (auto &it : list) { | |
| insert(end(), std::begin(it), std::end(it)); | |
| } | |
| } | |
| Method(std::initializer_list<cripts::Header::Method> list) | |
| { | |
| for (auto &it : list) { | |
| push_back(it); | |
| } | |
| } | |
| // Make sure we only allow the cripts::Method::* constants | |
| [[nodiscard]] bool | |
| Contains(cripts::Header::Method method) const | |
| { | |
| auto data = method.Data(); | |
| return end() != | |
| std::ranges::find_if(begin(), end(), [&](const cripts::Header::Method &header) { return header.Data() == data; }); | |
| } | |
| [[nodiscard]] bool | |
| Match(cripts::Header::Method method) const | |
| { | |
| return Contains(method); | |
| } | |
| }; // End class Method | |
| } // namespace List | |
| class PCRE | |
| { | |
| public: | |
| static constexpr size_t MAX_CAPTURES = 32; | |
| using Regex = std::tuple<cripts::string, pcre2_code *>; | |
| using RegexEntries = std::vector<Regex>; | |
| using self_type = PCRE; | |
| class Result | |
| { | |
| public: | |
| friend class PCRE; | |
| Result() = delete; | |
| Result(cripts::string_view subject) : _subject(subject) {} | |
| ~Result() { pcre2_match_data_free(_data); } | |
| explicit | |
| operator bool() const | |
| { | |
| return Matched(); | |
| } | |
| cripts::string_view | |
| operator[](size_t ix) const | |
| { | |
| cripts::string_view ret; | |
| if ((Count() > ix) && _ovector) { | |
| ret = {_subject.substr(_ovector[ix * 2], _ovector[ix * 2 + 1] - _ovector[ix * 2])}; | |
| } | |
| return ret; | |
| } | |
| [[nodiscard]] bool | |
| Matched() const | |
| { | |
| return _match != 0; | |
| } | |
| [[nodiscard]] RegexEntries::size_type | |
| MatchIX() const | |
| { | |
| return _match; | |
| } | |
| [[nodiscard]] uint32_t | |
| Count() const | |
| { | |
| return _data ? pcre2_get_ovector_count(_data) : 0; | |
| } | |
| // The allocator for the PCRE2 contexts, which puts the match data etc. on the stack when used appropriately | |
| static void *malloc(PCRE2_SIZE size, void *context); | |
| private: | |
| RegexEntries::size_type _match = 0; // The index into the regex vector that match, starting at 1 for the first regex | |
| pcre2_match_data *_data = nullptr; | |
| PCRE2_SIZE *_ovector = nullptr; | |
| PCRE2_SIZE _ctx_ix = 0; | |
| std::byte _ctx_data[24 * 2 + 96 + 16 * MAX_CAPTURES]; | |
| cripts::string_view _subject; | |
| }; | |
| PCRE() = default; | |
| PCRE(const self_type &) = delete; | |
| void operator=(const self_type &) = delete; | |
| PCRE(cripts::string_view regex, uint32_t options = 0) { Add(regex, options); } | |
| PCRE(std::initializer_list<cripts::string_view> list, uint32_t options = 0) | |
| { | |
| for (auto &it : list) { | |
| Add(it, options); | |
| } | |
| } | |
| ~PCRE(); | |
| void Add(cripts::string_view regex, uint32_t options = 0, bool jit = true); | |
| Result Contains(cripts::string_view subject, PCRE2_SIZE offset = 0, uint32_t options = 0); | |
| Result | |
| Match(cripts::string_view subject, PCRE2_SIZE offset = 0, uint32_t options = 0) | |
| { | |
| return Contains(subject, offset, options); | |
| } | |
| private: | |
| RegexEntries _regexes; | |
| }; | |
| } // namespace cripts::Matcher |