blob: 4cb46ee8f0802571da8c54cd62749823eebdf53c [file] [log] [blame]
/*
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
#include "cripts/Headers.hpp"
#include "cripts/Lulu.hpp"
#include "swoc/IPRange.h"
// Setup for PCRE2
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#include <vector>
#include <tuple>
#include "ts/ts.h"
#include "cripts/Lulu.hpp"
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::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