This is an automated email from the ASF dual-hosted git repository.
masaori pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 27478a7ffe Add config file support for cache_fill (#12347)
27478a7ffe is described below
commit 27478a7ffea60dfc1d7ad27bf1cb4fd2413f0943
Author: Jasmine Emanouel <[email protected]>
AuthorDate: Thu Jul 17 11:14:28 2025 +1000
Add config file support for cache_fill (#12347)
---
plugins/experimental/cache_fill/CMakeLists.txt | 2 +-
plugins/experimental/cache_fill/cache_fill.cc | 80 +++++++---
plugins/experimental/cache_fill/configs.cc | 213 +++++++++++++++++++++++++
plugins/experimental/cache_fill/configs.h | 89 +++++++++++
plugins/experimental/cache_fill/rules.cc | 145 +++++++++++++++++
plugins/experimental/cache_fill/rules.h | 78 +++++++++
6 files changed, 583 insertions(+), 24 deletions(-)
diff --git a/plugins/experimental/cache_fill/CMakeLists.txt
b/plugins/experimental/cache_fill/CMakeLists.txt
index 5a780a7f60..61f1da8764 100644
--- a/plugins/experimental/cache_fill/CMakeLists.txt
+++ b/plugins/experimental/cache_fill/CMakeLists.txt
@@ -15,6 +15,6 @@
#
#######################
-add_atsplugin(cache_fill background_fetch.cc cache_fill.cc)
+add_atsplugin(cache_fill background_fetch.cc cache_fill.cc configs.cc rules.cc)
verify_remap_plugin(cache_fill)
diff --git a/plugins/experimental/cache_fill/cache_fill.cc
b/plugins/experimental/cache_fill/cache_fill.cc
index c1df5d1451..ad3d90c3bf 100644
--- a/plugins/experimental/cache_fill/cache_fill.cc
+++ b/plugins/experimental/cache_fill/cache_fill.cc
@@ -39,6 +39,7 @@
#include "ts/remap.h"
#include "ts/remap_version.h"
#include "background_fetch.h"
+#include "configs.h"
static const char *
getCacheLookupResultName(TSCacheLookupResult result)
@@ -108,23 +109,29 @@ cont_check_cacheable(TSHttpTxn txnp)
// if a background fetch is allowed for this request
//
static int
-cont_handle_cache(TSCont /* contp ATS_UNUSED */, TSEvent event, void *edata)
+cont_handle_cache(TSCont contp, TSEvent event, void *edata)
{
- TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
- if (TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE == event) {
- bool const requested = cont_check_cacheable(txnp);
- if (requested) // Made a background fetch request, do not cache the
response
- {
- Dbg(dbg_ctl, "setting no store");
- TSHttpTxnCntlSet(txnp, TS_HTTP_CNTL_SERVER_NO_STORE, true);
- TSHttpTxnCacheLookupStatusSet(txnp, TS_CACHE_LOOKUP_MISS);
- }
+ TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
+ BgFetchConfig *config = static_cast<BgFetchConfig *>(TSContDataGet(contp));
+
+ if (nullptr == config) {
+ // something seriously wrong..
+ TSError("[%s] Can't get configurations", PLUGIN_NAME);
+ } else if (config->bgFetchAllowed(txnp)) {
+ if (TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE == event) {
+ bool const requested = cont_check_cacheable(txnp);
+ if (requested) // Made a background fetch request, do not cache the
response
+ {
+ Dbg(dbg_ctl, "setting no store");
+ TSHttpTxnCntlSet(txnp, TS_HTTP_CNTL_SERVER_NO_STORE, true);
+ TSHttpTxnCacheLookupStatusSet(txnp, TS_CACHE_LOOKUP_MISS);
+ }
- } else {
- TSError("[%s] Unknown event for this plugin %d", PLUGIN_NAME, event);
- Dbg(dbg_ctl, "unknown event for this plugin %d", event);
+ } else {
+ TSError("[%s] Unknown event for this plugin %d", PLUGIN_NAME, event);
+ Dbg(dbg_ctl, "unknown event for this plugin %d", event);
+ }
}
-
// Reenable and continue with the state machine.
TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
return 0;
@@ -147,19 +154,46 @@ TSRemapInit(TSRemapInterface *api_info, char *errbuf, int
errbuf_size)
// We don't have any specific "instances" here, at least not yet.
//
TSReturnCode
-TSRemapNewInstance(int /* argc ATS_UNUSED */, char ** /* argv ATS_UNUSED */,
void **ih, char * /* errbuf ATS_UNUSED */,
- int /* errbuf_size ATS_UNUSED */)
+TSRemapNewInstance(int argc, char **argv, void **ih, char * /* errbuf
ATS_UNUSED */, int /* errbuf_size ATS_UNUSED */)
{
- TSCont cont = TSContCreate(cont_handle_cache, nullptr);
- *ih = cont;
- return TS_SUCCESS;
+ TSCont cont = TSContCreate(cont_handle_cache, nullptr);
+ BgFetchConfig *config = new BgFetchConfig(cont);
+ bool success = true;
+
+ // The first two arguments are the "from" and "to" URL string. We need to
+ // skip them, but we also require that there be an option to masquerade as
+ // argv[0], so we increment the argument indexes by 1 rather than by 2.
+ argc--;
+ argv++;
+
+ // This is for backwards compatibility, ugly! ToDo: Remove for ATS v9.0.0
IMO.
+ if (argc > 1 && *argv[1] != '-') {
+ Dbg(dbg_ctl, "config file %s", argv[1]);
+ if (!config->readConfig(argv[1])) {
+ success = false;
+ }
+ } else {
+ if (!config->parseOptions(argc, const_cast<const char **>(argv))) {
+ success = false;
+ }
+ }
+
+ if (success) {
+ *ih = config;
+
+ return TS_SUCCESS;
+ }
+
+ // Something went wrong with the configuration setup.
+ delete config;
+ return TS_ERROR;
}
void
TSRemapDeleteInstance(void *ih)
{
- TSCont cont = static_cast<TSCont>(ih);
- TSContDestroy(cont);
+ BgFetchConfig *config = static_cast<BgFetchConfig *>(ih);
+ delete config;
}
///////////////////////////////////////////////////////////////////////////////
@@ -171,8 +205,8 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo
* /* rri */)
if (nullptr == ih) {
return TSREMAP_NO_REMAP;
}
- TSCont const cont = static_cast<TSCont>(ih);
- TSHttpTxnHookAdd(txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, cont);
+ BgFetchConfig *config = static_cast<BgFetchConfig *>(ih);
+ TSHttpTxnHookAdd(txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK,
config->getCont());
Dbg(dbg_ctl, "TSRemapDoRemap() added hook");
return TSREMAP_NO_REMAP;
diff --git a/plugins/experimental/cache_fill/configs.cc
b/plugins/experimental/cache_fill/configs.cc
new file mode 100644
index 0000000000..9eef083b8d
--- /dev/null
+++ b/plugins/experimental/cache_fill/configs.cc
@@ -0,0 +1,213 @@
+/** @file
+
+ Plugin to perform background fetches of certain content that would
+ otherwise not be cached. For example, Range: requests / responses.
+
+ @section license License
+
+ 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.
+*/
+
+#include <getopt.h>
+#include <cstdio>
+#include <memory.h>
+
+#include "configs.h"
+#include "background_fetch.h"
+
+#include <swoc/TextView.h>
+#include <swoc/swoc_file.h>
+#include <tsutil/ts_bw_format.h>
+
+using namespace swoc::literals;
+
+// Parse the command line options. This got a little wonky, since we decided
to have different
+// syntax for remap vs global plugin initialization, and the global BG fetch
state :-/. Clean up
+// later...
+bool
+BgFetchConfig::parseOptions(int argc, const char *argv[])
+{
+ static const struct option longopt[] = {
+ {const_cast<char *>("log"), required_argument, nullptr, 'l' },
+ {const_cast<char *>("config"), required_argument, nullptr, 'c' },
+ {const_cast<char *>("allow-304"), no_argument, nullptr, 'a' },
+ {nullptr, no_argument, nullptr, '\0'}
+ };
+
+ while (true) {
+ int opt = getopt_long(argc, const_cast<char *const *>(argv), "lc",
longopt, nullptr);
+
+ if (opt == -1) {
+ break;
+ }
+
+ switch (opt) {
+ case 'l':
+ Dbg(dbg_ctl, "option: log file specified: %s", optarg);
+ _log_file = optarg;
+ break;
+ case 'c':
+ Dbg(dbg_ctl, "option: config file '%s'", optarg);
+ if (!readConfig(optarg)) {
+ // Error messages are written in the parser
+ return false;
+ }
+ break;
+ case 'a':
+ Dbg(dbg_ctl, "option: --allow-304 set");
+ _allow_304 = true;
+ break;
+ default:
+ TSError("[%s] invalid plugin option: %c", PLUGIN_NAME, opt);
+ return false;
+ break;
+ }
+ }
+
+ return true;
+}
+
+// Read a config file, populate the linked list (chain the BgFetchRule's)
+bool
+BgFetchConfig::readConfig(const char *config_file)
+{
+ if (nullptr == config_file) {
+ TSError("[%s] invalid config file", PLUGIN_NAME);
+ return false;
+ }
+
+ swoc::file::path path(config_file);
+
+ Dbg(dbg_ctl, "trying to open config file in this path: %s", config_file);
+
+ if (!path.is_absolute()) {
+ path = swoc::file::path(TSConfigDirGet()) / path;
+ }
+ Dbg(dbg_ctl, "chosen config file is at: %s", path.c_str());
+
+ std::error_code ec;
+ auto content = swoc::file::load(path, ec);
+ if (ec) {
+ swoc::bwprint(ts::bw_dbg, "[{}] invalid config file: {} {}", PLUGIN_NAME,
path, ec);
+ TSError("%s", ts::bw_dbg.c_str());
+ Dbg(dbg_ctl, "%s", ts::bw_dbg.c_str());
+ return false;
+ }
+
+ swoc::TextView text{content};
+ while (text) {
+ auto line = text.take_prefix_at('\n').ltrim_if(&isspace);
+
+ if (line.empty() || line.front() == '#') {
+ continue;
+ }
+
+ auto cfg_type = line.take_prefix_if(&isspace);
+ if (cfg_type.empty()) {
+ continue;
+ }
+
+ Dbg(dbg_ctl, "setting background_fetch exclusion criterion based on
string: %.*s", int(cfg_type.size()), cfg_type.data());
+
+ bool exclude = false;
+ if (0 == strcasecmp(cfg_type, "exclude")) {
+ exclude = true;
+ } else if (0 != strcasecmp(cfg_type, "include")) {
+ swoc::bwprint(ts::bw_dbg, "[{}] invalid specifier {}, skipping config
line", PLUGIN_NAME, cfg_type);
+ TSError("%s", ts::bw_dbg.c_str());
+ continue;
+ }
+
+ if (auto cfg_name = line.take_prefix_if(&isspace); !cfg_name.empty()) {
+ if (auto cfg_value = line.take_prefix_if(&isspace); !cfg_value.empty()) {
+ if ("Client-IP"_tv == cfg_name) {
+ swoc::IPRange r;
+ // '*' is special - match any address. Signalled by empty range.
+ if (cfg_value.size() != 1 || cfg_value.front() == '*') {
+ if (!r.load(cfg_value)) { // assume if it loads, it's not empty.
+ TSError("[%s] invalid IP address range %.*s, skipping config
value", PLUGIN_NAME, int(cfg_value.size()),
+ cfg_value.data());
+ continue;
+ }
+ }
+ _rules.emplace_back(exclude, r);
+ swoc::bwprint(ts::bw_dbg, "adding background_fetch address range
rule {} for {}: {}", exclude, cfg_name, cfg_value);
+ Dbg(dbg_ctl, "%s", ts::bw_dbg.c_str());
+ } else if ("Content-Length"_tv == cfg_name) {
+ BgFetchRule::size_cmp_type::OP op;
+ if (cfg_value[0] == '<') {
+ op = BgFetchRule::size_cmp_type::LESS_THAN_OR_EQUAL;
+ } else if (cfg_value[0] == '>') {
+ op = BgFetchRule::size_cmp_type::LESS_THAN_OR_EQUAL;
+ } else {
+ TSError("[%s] invalid Content-Length condition %.*s, skipping
config value", PLUGIN_NAME, int(cfg_value.size()),
+ cfg_value.data());
+ continue;
+ }
+ ++cfg_value; // Drop leading character.
+ swoc::TextView parsed;
+ auto n = swoc::svtou(cfg_value, &parsed);
+ if (parsed.size() != cfg_value.size()) {
+ TSError("[%s] invalid Content-Length size value %.*s, skipping
config value", PLUGIN_NAME, int(cfg_value.size()),
+ cfg_value.data());
+ continue;
+ }
+ _rules.emplace_back(exclude, op, size_t(n));
+
+ swoc::bwprint(ts::bw_dbg, "adding background_fetch content length
rule {} for {}: {}", exclude, cfg_name, cfg_value);
+ Dbg(dbg_ctl, "%s", ts::bw_dbg.c_str());
+ } else {
+ _rules.emplace_back(exclude, cfg_name, cfg_value);
+ swoc::bwprint(ts::bw_dbg, "adding background_fetch field compare
rule {} for {}: {}", exclude, cfg_name, cfg_value);
+ Dbg(dbg_ctl, "%s", ts::bw_dbg.c_str());
+ }
+ } else {
+ TSError("[%s] invalid value %.*s, skipping config line", PLUGIN_NAME,
int(cfg_name.size()), cfg_name.data());
+ }
+ }
+ }
+
+ Dbg(dbg_ctl, "Done parsing config");
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Check the configuration (either per remap, or global), and decide if
+// this request is allowed to trigger a background fetch.
+//
+bool
+BgFetchConfig::bgFetchAllowed(TSHttpTxn txnp) const
+{
+ Dbg(dbg_ctl, "Testing: request is internal?");
+ if (TSHttpTxnIsInternal(txnp)) {
+ return false;
+ }
+
+ bool allow_bg_fetch = true;
+
+ // We could do this recursively, but following the linked list is probably
more efficient.
+ for (auto const &r : _rules) {
+ if (r.check_field_configured(txnp)) {
+ Dbg(dbg_ctl, "found %s rule match", r._exclude ? "exclude" : "include");
+ allow_bg_fetch = !r._exclude;
+ break;
+ }
+ }
+
+ return allow_bg_fetch;
+}
diff --git a/plugins/experimental/cache_fill/configs.h
b/plugins/experimental/cache_fill/configs.h
new file mode 100644
index 0000000000..7d3304cea8
--- /dev/null
+++ b/plugins/experimental/cache_fill/configs.h
@@ -0,0 +1,89 @@
+/** @file
+
+ Plugin to perform background fetches of certain content that would
+ otherwise not be cached. For example, Range: requests / responses.
+
+ @section license License
+
+ 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 <cstdlib>
+#include <atomic>
+#include <string>
+#include <list>
+#include <memory>
+#include <sys/socket.h>
+
+#include "rules.h"
+
+///////////////////////////////////////////////////////////////////////////
+// This holds one complete background fetch rule
+//
+class BgFetchConfig
+{
+public:
+ using list_type = std::list<BgFetchRule>;
+
+ explicit BgFetchConfig(TSCont cont) : _cont(cont) { TSContDataSet(cont,
static_cast<void *>(this)); }
+
+ ~BgFetchConfig()
+ {
+ if (_cont) {
+ TSContDestroy(_cont);
+ }
+ }
+
+ bool parseOptions(int argc, const char *argv[]);
+
+ list_type const &
+ getRules() const
+ {
+ return _rules;
+ }
+
+ TSCont
+ getCont() const
+ {
+ return _cont;
+ }
+
+ const std::string &
+ logFile() const
+ {
+ return _log_file;
+ }
+
+ bool
+ allow304() const
+ {
+ return _allow_304;
+ }
+
+ // This parses and populates the BgFetchRule linked list (_rules).
+ bool readConfig(const char *file_name);
+
+ bool bgFetchAllowed(TSHttpTxn txnp) const;
+
+private:
+ TSCont _cont = nullptr;
+ list_type _rules;
+ bool _allow_304 = false;
+ std::string _log_file;
+};
diff --git a/plugins/experimental/cache_fill/rules.cc
b/plugins/experimental/cache_fill/rules.cc
new file mode 100644
index 0000000000..9fc5fea31b
--- /dev/null
+++ b/plugins/experimental/cache_fill/rules.cc
@@ -0,0 +1,145 @@
+/** @file
+
+ Plugin to perform background fetches of certain content that would
+ otherwise not be cached. For example, Range: requests / responses.
+
+ @section license License
+
+ 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.
+*/
+
+#include <cstdlib>
+#include <string_view>
+#include <cstring>
+#include <sys/socket.h>
+
+#include <swoc/IPEndpoint.h>
+#include <swoc/swoc_meta.h>
+
+#include "configs.h"
+#include "rules.h"
+#include "background_fetch.h"
+
+#include "tsutil/ts_bw_format.h"
+#include "tsutil/ts_ip.h"
+
+///////////////////////////////////////////////////////////////////////////
+// These are little helper functions for the main rules evaluator.
+//
+static bool
+check_value(TSHttpTxn txnp, swoc::IPRange const &range)
+{
+ const sockaddr *client_ip = TSHttpTxnClientAddrGet(txnp);
+ if (!client_ip) {
+ return false;
+ }
+
+ if (range.empty()) { // this means "match any address".
+ return true;
+ }
+
+ swoc::IPEndpoint client_addr{client_ip};
+
+ swoc::bwprint(ts::bw_dbg, "cfg_ip {::c}, client_ip {}", range, client_addr);
+ Dbg(dbg_ctl, "%s", ts::bw_dbg.c_str());
+
+ if (client_addr.family() == range.family()) {
+ return (range.is_ip4() &&
range.ip4().contains(swoc::IP4Addr(client_addr.ip4()))) ||
+ (range.is_ip6() &&
range.ip6().contains(swoc::IP6Addr(client_addr.ip6())));
+ }
+
+ return false; // Different family, no match.
+}
+
+static bool
+check_value(TSHttpTxn txnp, BgFetchRule::size_cmp_type const &cmp)
+{
+ TSMBuffer hdr_bufp;
+ TSMLoc hdr_loc;
+
+ if (TS_SUCCESS != TSHttpTxnServerRespGet(txnp, &hdr_bufp, &hdr_loc)) {
+ TSError("[%s] Failed to get resp headers", PLUGIN_NAME);
+ return false;
+ }
+
+ TSMLoc loc = TSMimeHdrFieldFind(hdr_bufp, hdr_loc,
TS_MIME_FIELD_CONTENT_LENGTH, TS_MIME_LEN_CONTENT_LENGTH);
+ if (TS_NULL_MLOC == loc) {
+ Dbg(dbg_ctl, "No content-length field in resp");
+ return false; // Field not found.
+ }
+
+ auto content_len = TSMimeHdrFieldValueUintGet(hdr_bufp, hdr_loc, loc, 0 /*
index */);
+ TSHandleMLocRelease(hdr_bufp, hdr_loc, loc);
+
+ if (cmp._op == BgFetchRule::size_cmp_type::OP::GREATER_THAN_OR_EQUAL) {
+ return content_len >= cmp._size;
+ } else if (cmp._op == BgFetchRule::size_cmp_type::OP::LESS_THAN_OR_EQUAL) {
+ return content_len <= cmp._size;
+ }
+
+ return false;
+}
+
+static bool
+check_value(TSHttpTxn txnp, BgFetchRule::field_cmp_type const &cmp)
+{
+ TSMBuffer hdr_bufp;
+ TSMLoc hdr_loc;
+
+ if (TS_SUCCESS != TSHttpTxnClientReqGet(txnp, &hdr_bufp, &hdr_loc)) {
+ TSError("[%s] Failed to get resp headers", PLUGIN_NAME);
+ return false;
+ }
+
+ TSMLoc loc = TSMimeHdrFieldFind(hdr_bufp, hdr_loc, cmp._name.data(),
cmp._name.size());
+
+ if (TS_NULL_MLOC == loc) {
+ Dbg(dbg_ctl, "no field %s in request header", cmp._name.c_str());
+ return false;
+ }
+
+ if (cmp._name.size() == 1 && cmp._name.front() == '*') {
+ Dbg(dbg_ctl, "Found %s wild card", cmp._name.c_str());
+ return true;
+ }
+
+ int val_len = 0;
+ char const *val_str = TSMimeHdrFieldValueStringGet(hdr_bufp, hdr_loc, loc,
0, &val_len);
+ bool zret = false;
+
+ if (!val_str || val_len <= 0) {
+ Dbg(dbg_ctl, "invalid field");
+ } else {
+ Dbg(dbg_ctl, "comparing with %s", cmp._value.c_str());
+ zret = std::string_view::npos != std::string_view(val_str,
val_len).find(cmp._value);
+ }
+ TSHandleMLocRelease(hdr_bufp, hdr_loc, loc);
+ return zret;
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Check if a header excludes us from running the background fetch
+//
+bool
+BgFetchRule::check_field_configured(TSHttpTxn txnp) const
+{
+ return std::visit(swoc::meta::vary{[=](std::monostate) { return false; },
+ [=](swoc::IPRange const &range) { return
check_value(txnp, range); },
+ [=](size_cmp_type const &cmp) { return
check_value(txnp, cmp); },
+ [=](field_cmp_type const &cmp) { return
check_value(txnp, cmp); }},
+ _value);
+}
diff --git a/plugins/experimental/cache_fill/rules.h
b/plugins/experimental/cache_fill/rules.h
new file mode 100644
index 0000000000..bbfc7a36ec
--- /dev/null
+++ b/plugins/experimental/cache_fill/rules.h
@@ -0,0 +1,78 @@
+/** @file
+
+ Plugin to perform background fetches of certain content that would
+ otherwise not be cached. For example, Range: requests / responses.
+
+ @section license License
+
+ 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 <cstdlib>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <variant>
+#include <sys/socket.h>
+
+#include <swoc/TextView.h>
+#include <swoc/IPRange.h>
+
+#include "ts/ts.h"
+
+///////////////////////////////////////////////////////////////////////////
+// This is a linked list of rule entries. This gets stored and parsed with the
+// BgFetchConfig object.
+//
+class BgFetchRule
+{
+ using self_type = BgFetchRule;
+
+public:
+ /// Content length / size comparison.
+ struct size_cmp_type {
+ enum OP { LESS_THAN_OR_EQUAL, GREATER_THAN_OR_EQUAL } _op; ///< Comparison
to use.
+ size_t _size; ///< Size for
comparison.
+ };
+
+ /// Field value comparison.
+ struct field_cmp_type {
+ std::string _name; ///< Field name.
+ std::string _value; ///< Value to compare. A single '*' means match
anything - check for field presence.
+ };
+
+ BgFetchRule(bool exc, size_cmp_type::OP op, size_t n) : _exclude(exc),
_value(size_cmp_type{op, n}) {}
+ BgFetchRule(bool exc, swoc::IPRange const &range) : _exclude(exc),
_value(range) {}
+
+ BgFetchRule(bool exc, swoc::TextView name, swoc::TextView value)
+ : _exclude(exc), _value(field_cmp_type{std::string(name),
std::string(value)})
+ {
+ }
+
+ BgFetchRule(self_type &&that) = default;
+
+ // Main evaluation entry point.
+ bool bgFetchAllowed(TSHttpTxn txnp) const;
+ bool check_field_configured(TSHttpTxn txnp) const;
+
+ bool _exclude; ///< Exclusion @c true or inclusion @c false.
+
+ /// Value type for the rule, which also indicates the type of check.
+ using value_type = std::variant<std::monostate, size_cmp_type,
field_cmp_type, swoc::IPRange>;
+ value_type _value; ///< Value instance for checking.
+};