This is an automated email from the ASF dual-hosted git repository.

eze 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 c70884108f TSFile - remove from background_fetch plugin (#10980)
c70884108f is described below

commit c70884108fa71063f34b0f8427dc402fb14a9b0a
Author: Evan Zelkowitz <[email protected]>
AuthorDate: Wed Jan 10 11:04:32 2024 -0700

    TSFile - remove from background_fetch plugin (#10980)
    
    * TSFile - remove from background_fetch plugin.
    
    * Update docs.
    
    * Moved back to .h, used in other places besides configs.cc
    
    * Update cmake and includes to reference the moved tscpputil to tsutil
    
    ---------
    
    Co-authored-by: Alan M. Carroll <[email protected]>
---
 doc/admin-guide/plugins/background_fetch.en.rst |   2 +
 plugins/background_fetch/CMakeLists.txt         |   1 +
 plugins/background_fetch/configs.cc             | 150 +++++++++++----------
 plugins/background_fetch/configs.h              |  16 ++-
 plugins/background_fetch/rules.cc               | 171 ++++++++++++------------
 plugins/background_fetch/rules.h                |  47 ++++---
 6 files changed, 204 insertions(+), 183 deletions(-)

diff --git a/doc/admin-guide/plugins/background_fetch.en.rst 
b/doc/admin-guide/plugins/background_fetch.en.rst
index 659976599f..1cd9addd9c 100644
--- a/doc/admin-guide/plugins/background_fetch.en.rst
+++ b/doc/admin-guide/plugins/background_fetch.en.rst
@@ -73,6 +73,8 @@ The contents of the config-file could be as below::
    exclude Content-Type text
    exclude X-Foo-Bar text
    exclude Content-Length <1000
+   exclude Client-IP 127.0.0.1
+   include Client-IP 10.0.0.0/16
 
 .. important::
 
diff --git a/plugins/background_fetch/CMakeLists.txt 
b/plugins/background_fetch/CMakeLists.txt
index 94c86f4e46..0638a1071f 100644
--- a/plugins/background_fetch/CMakeLists.txt
+++ b/plugins/background_fetch/CMakeLists.txt
@@ -16,3 +16,4 @@
 #######################
 
 add_atsplugin(background_fetch background_fetch.cc configs.cc headers.cc 
rules.cc)
+target_link_libraries(background_fetch PRIVATE libswoc::libswoc ts::tsutil)
diff --git a/plugins/background_fetch/configs.cc 
b/plugins/background_fetch/configs.cc
index a7b86dc23f..2e8a6d9fa4 100644
--- a/plugins/background_fetch/configs.cc
+++ b/plugins/background_fetch/configs.cc
@@ -28,6 +28,12 @@
 
 #include "configs.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...
@@ -78,98 +84,102 @@ BgFetchConfig::parseOptions(int argc, const char *argv[])
 bool
 BgFetchConfig::readConfig(const char *config_file)
 {
-  char file_path[4096];
-  TSFile file;
-
   if (nullptr == config_file) {
     TSError("[%s] invalid config file", PLUGIN_NAME);
     return false;
   }
 
+  swoc::file::path path(config_file);
+
   Dbg(Bg_dbg_ctl, "trying to open config file in this path: %s", config_file);
 
-  if (*config_file == '/') {
-    snprintf(file_path, sizeof(file_path), "%s", config_file);
-  } else {
-    snprintf(file_path, sizeof(file_path), "%s/%s", TSConfigDirGet(), 
config_file);
+  if (!path.is_absolute()) {
+    path = swoc::file::path(TSConfigDirGet()) / path;
   }
-  Dbg(Bg_dbg_ctl, "chosen config file is at: %s", file_path);
-
-  file = TSfopen(file_path, "r");
-  if (nullptr == file) {
-    TSError("[%s] invalid config file:  %s", PLUGIN_NAME, file_path);
-    Dbg(Bg_dbg_ctl, "invalid config file: %s", file_path);
+  Dbg(Bg_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(Bg_dbg_ctl, "%s", ts::bw_dbg.c_str());
     return false;
   }
 
-  BgFetchRule *cur = nullptr;
-  char buffer[8192];
-
-  memset(buffer, 0, sizeof(buffer));
-  while (TSfgets(file, buffer, sizeof(buffer) - 1) != nullptr) {
-    char *eol = nullptr;
+  swoc::TextView text{content};
+  while (text) {
+    auto line = text.take_prefix_at('\n').ltrim_if(&isspace);
 
-    // make sure line was not bigger than buffer
-    if (nullptr == (eol = strchr(buffer, '\n')) && nullptr == (eol = 
strstr(buffer, "\r\n"))) {
-      TSError("[%s] exclusion line too long, did not get a good line in cfg, 
skipping, line: %s", PLUGIN_NAME, buffer);
-      memset(buffer, 0, sizeof(buffer));
+    if (line.empty() || line.front() == '#') {
       continue;
     }
-    // make sure line has something useful on it
-    if (eol - buffer < 2 || buffer[0] == '#') {
-      memset(buffer, 0, sizeof(buffer));
+
+    auto cfg_type = line.take_prefix_if(&isspace);
+    if (cfg_type.empty()) {
       continue;
     }
 
-    char *savePtr = nullptr;
-    char *cfg     = strtok_r(buffer, "\n\r\n", &savePtr);
-
-    if (nullptr != cfg) {
-      Dbg(Bg_dbg_ctl, "setting background_fetch exclusion criterion based on 
string: %s", cfg);
-      char *cfg_type  = strtok_r(buffer, " ", &savePtr);
-      char *cfg_name  = nullptr;
-      char *cfg_value = nullptr;
-
-      if (cfg_type) {
-        bool exclude = false;
-        if (!strcmp(cfg_type, "exclude")) {
-          exclude = true;
-        } else if (strcmp(cfg_type, "include")) {
-          TSError("[%s] invalid specifier %s, skipping config line", 
PLUGIN_NAME, cfg_type);
-          memset(buffer, 0, sizeof(buffer));
-          continue;
-        }
-        cfg_name = strtok_r(nullptr, " ", &savePtr);
-        if (cfg_name) {
-          cfg_value = strtok_r(nullptr, " ", &savePtr);
-          if (cfg_value) {
-            if (!strcmp(cfg_name, "Content-Length")) {
-              if ((cfg_value[0] != '<') && (cfg_value[0] != '>')) {
-                TSError("[%s] invalid content-len condition %s, skipping 
config value", PLUGIN_NAME, cfg_value);
-                memset(buffer, 0, sizeof(buffer));
-                continue;
-              }
-            }
-            BgFetchRule *r = new BgFetchRule(exclude, cfg_name, cfg_value);
+    Dbg(Bg_dbg_ctl, "setting background_fetch exclusion criterion based on 
string: %.*s", int(cfg_type.size()), cfg_type.data());
 
-            if (nullptr == cur) {
-              _rules = r;
-            } else {
-              cur->chain(r);
-            }
-            cur = r;
+    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;
+    }
 
-            Dbg(Bg_dbg_ctl, "adding background_fetch exclusion rule %d for %s: 
%s", exclude, cfg_name, cfg_value);
+    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(Bg_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 value %s, skipping config line", 
PLUGIN_NAME, cfg_name);
+            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(Bg_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(Bg_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());
       }
-      memset(buffer, 0, sizeof(buffer));
     }
   }
 
-  TSfclose(file);
   Dbg(Bg_dbg_ctl, "Done parsing config");
 
   return true;
@@ -190,10 +200,10 @@ BgFetchConfig::bgFetchAllowed(TSHttpTxn txnp) const
   bool allow_bg_fetch = true;
 
   // We could do this recursively, but following the linked list is probably 
more efficient.
-  for (const BgFetchRule *r = _rules; nullptr != r; r = r->_next) {
-    if (r->check_field_configured(txnp)) {
-      Dbg(Bg_dbg_ctl, "found field match %s, exclude %d", r->_field, 
static_cast<int>(r->_exclude));
-      allow_bg_fetch = !r->_exclude;
+  for (auto const &r : _rules) {
+    if (r.check_field_configured(txnp)) {
+      Dbg(Bg_dbg_ctl, "found %s rule match", r._exclude ? "exclude" : 
"include");
+      allow_bg_fetch = !r._exclude;
       break;
     }
   }
diff --git a/plugins/background_fetch/configs.h 
b/plugins/background_fetch/configs.h
index 1bf2ab7396..cdd3b04e67 100644
--- a/plugins/background_fetch/configs.h
+++ b/plugins/background_fetch/configs.h
@@ -27,13 +27,16 @@
 #include <cstdlib>
 #include <atomic>
 #include <string>
+#include <list>
+#include <memory>
+#include <sys/socket.h>
 
 #include "rules.h"
 
 // Constants
 const char PLUGIN_NAME[] = "background_fetch";
 
-extern DbgCtl Bg_dbg_ctl;
+static DbgCtl Bg_dbg_ctl{PLUGIN_NAME};
 
 ///////////////////////////////////////////////////////////////////////////
 // This holds one complete background fetch rule
@@ -41,11 +44,12 @@ extern DbgCtl Bg_dbg_ctl;
 class BgFetchConfig
 {
 public:
+  using list_type = std::list<BgFetchRule>;
+
   explicit BgFetchConfig(TSCont cont) : _cont(cont) { TSContDataSet(cont, 
static_cast<void *>(this)); }
 
   ~BgFetchConfig()
   {
-    delete _rules;
     if (_cont) {
       TSContDestroy(_cont);
     }
@@ -53,7 +57,7 @@ public:
 
   bool parseOptions(int argc, const char *argv[]);
 
-  BgFetchRule *
+  list_type const &
   getRules() const
   {
     return _rules;
@@ -83,8 +87,8 @@ public:
   bool bgFetchAllowed(TSHttpTxn txnp) const;
 
 private:
-  TSCont _cont        = nullptr;
-  BgFetchRule *_rules = nullptr;
-  bool _allow_304     = false;
+  TSCont _cont = nullptr;
+  list_type _rules;
+  bool _allow_304 = false;
   std::string _log_file;
 };
diff --git a/plugins/background_fetch/rules.cc 
b/plugins/background_fetch/rules.cc
index b8f339d6d2..cad2f2282d 100644
--- a/plugins/background_fetch/rules.cc
+++ b/plugins/background_fetch/rules.cc
@@ -25,127 +25,120 @@
 #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 "tsutil/ts_bw_format.h"
+#include "tsutil/ts_ip.h"
+
 ///////////////////////////////////////////////////////////////////////////
 // These are little helper functions for the main rules evaluator.
 //
 static bool
-check_client_ip_configured(TSHttpTxn txnp, const char *cfg_ip)
+check_value(TSHttpTxn txnp, swoc::IPRange const &range)
 {
   const sockaddr *client_ip = TSHttpTxnClientAddrGet(txnp);
-  char ip_buf[INET6_ADDRSTRLEN];
-
-  if (AF_INET == client_ip->sa_family) {
-    inet_ntop(AF_INET, &(reinterpret_cast<const sockaddr_in 
*>(client_ip)->sin_addr), ip_buf, INET_ADDRSTRLEN);
-  } else if (AF_INET6 == client_ip->sa_family) {
-    inet_ntop(AF_INET6, &(reinterpret_cast<const sockaddr_in6 
*>(client_ip)->sin6_addr), ip_buf, INET6_ADDRSTRLEN);
-  } else {
-    TSError("[%s] Unknown family %d", PLUGIN_NAME, client_ip->sa_family);
+  if (!client_ip) {
     return false;
   }
 
-  Dbg(Bg_dbg_ctl, "cfg_ip %s, client_ip %s", cfg_ip, ip_buf);
-
-  if ((strlen(cfg_ip) == strlen(ip_buf)) && !strcmp(cfg_ip, ip_buf)) {
-    Dbg(Bg_dbg_ctl, "bg fetch for ip %s, configured ip %s", ip_buf, cfg_ip);
+  if (range.empty()) { // this means "match any address".
     return true;
   }
 
-  return false;
+  swoc::IPEndpoint client_addr{client_ip};
+
+  swoc::bwprint(ts::bw_dbg, "cfg_ip {::c}, client_ip {}", range, client_addr);
+  Dbg(Bg_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_content_length(const uint32_t len, const char *cfg_val)
+check_value(TSHttpTxn txnp, BgFetchRule::size_cmp_type const &cmp)
 {
-  uint32_t cfg_cont_len = atoi(&cfg_val[1]);
+  TSMBuffer hdr_bufp;
+  TSMLoc hdr_loc;
 
-  if (cfg_val[0] == '<') {
-    return (len <= cfg_cont_len);
-  } else if (cfg_val[0] == '>') {
-    return (len >= cfg_cont_len);
-  } else {
-    TSError("[%s] Invalid content length condition %c", PLUGIN_NAME, 
cfg_val[0]);
+  if (TS_SUCCESS != TSHttpTxnServerRespGet(txnp, &hdr_bufp, &hdr_loc)) {
+    TSError("[%s] Failed to get resp headers", PLUGIN_NAME);
     return false;
   }
-}
 
-///////////////////////////////////////////////////////////////////////////
-// Check if a header excludes us from running the background fetch
-//
-bool
-BgFetchRule::check_field_configured(TSHttpTxn txnp) const
-{
-  // check for client-ip first
-  if (!strcmp(_field, "Client-IP")) {
-    if (!strcmp(_value, "*")) {
-      Dbg(Bg_dbg_ctl, "Found client_ip wild card");
-      return true;
-    }
-    if (check_client_ip_configured(txnp, _value)) {
-      Dbg(Bg_dbg_ctl, "Found client_ip match");
-      return true;
-    }
+  TSMLoc loc = TSMimeHdrFieldFind(hdr_bufp, hdr_loc, 
TS_MIME_FIELD_CONTENT_LENGTH, TS_MIME_LEN_CONTENT_LENGTH);
+  if (TS_NULL_MLOC == loc) {
+    Dbg(Bg_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;
   }
 
-  bool hdr_found = false;
+  return false;
+}
+
+static bool
+check_value(TSHttpTxn txnp, BgFetchRule::field_cmp_type const &cmp)
+{
   TSMBuffer hdr_bufp;
   TSMLoc hdr_loc;
 
-  // Check response headers. ToDo: This doesn't check e.g. Content-Type :-/.
-  if (!strcmp(_field, "Content-Length")) {
-    if (TS_SUCCESS == TSHttpTxnServerRespGet(txnp, &hdr_bufp, &hdr_loc)) {
-      TSMLoc loc = TSMimeHdrFieldFind(hdr_bufp, hdr_loc, _field, -1);
-
-      if (TS_NULL_MLOC != loc) {
-        unsigned int content_len = TSMimeHdrFieldValueUintGet(hdr_bufp, 
hdr_loc, loc, 0 /* index */);
-
-        if (check_content_length(content_len, _value)) {
-          Dbg(Bg_dbg_ctl, "Found content-length match");
-          hdr_found = true;
-        }
-        TSHandleMLocRelease(hdr_bufp, hdr_loc, loc);
-      } else {
-        Dbg(Bg_dbg_ctl, "No content-length field in resp");
-      }
-      TSHandleMLocRelease(hdr_bufp, TS_NULL_MLOC, hdr_loc);
-    } else {
-      TSError("[%s] Failed to get resp headers", PLUGIN_NAME);
-    }
-    return hdr_found;
+  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(Bg_dbg_ctl, "no field %s in request header", cmp._name.c_str());
+    return false;
   }
 
-  // Check request headers
-  if (TS_SUCCESS == TSHttpTxnClientReqGet(txnp, &hdr_bufp, &hdr_loc)) {
-    TSMLoc loc = TSMimeHdrFieldFind(hdr_bufp, hdr_loc, _field, -1);
-
-    if (TS_NULL_MLOC != loc) {
-      if (!strcmp(_value, "*")) {
-        Dbg(Bg_dbg_ctl, "Found %s wild card", _field);
-        hdr_found = true;
-      } else {
-        int val_len         = 0;
-        const char *val_str = TSMimeHdrFieldValueStringGet(hdr_bufp, hdr_loc, 
loc, 0, &val_len);
-
-        if (!val_str || val_len <= 0) {
-          Dbg(Bg_dbg_ctl, "invalid field");
-        } else {
-          Dbg(Bg_dbg_ctl, "comparing with %s", _value);
-          if (std::string_view::npos != std::string_view(val_str, 
val_len).find(_value)) {
-            hdr_found = true;
-          }
-        }
-      }
-      TSHandleMLocRelease(hdr_bufp, hdr_loc, loc);
-    } else {
-      Dbg(Bg_dbg_ctl, "no field %s in request header", _field);
-    }
-    TSHandleMLocRelease(hdr_bufp, TS_NULL_MLOC, hdr_loc);
+  if (cmp._name.size() == 1 && cmp._name.front() == '*') {
+    Dbg(Bg_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(Bg_dbg_ctl, "invalid field");
   } else {
-    TSError("[%s] Failed to get resp headers", PLUGIN_NAME);
+    Dbg(Bg_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;
+}
 
-  return hdr_found;
+///////////////////////////////////////////////////////////////////////////
+// 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/background_fetch/rules.h b/plugins/background_fetch/rules.h
index d0652c87a1..bbfc7a36ec 100644
--- a/plugins/background_fetch/rules.h
+++ b/plugins/background_fetch/rules.h
@@ -27,6 +27,11 @@
 #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"
 
@@ -36,32 +41,38 @@
 //
 class BgFetchRule
 {
+  using self_type = BgFetchRule;
+
 public:
-  BgFetchRule(bool exc, const char *field, const char *value)
-    : _exclude(exc), _field(TSstrdup(field)), _value(TSstrdup(value)), 
_next(nullptr)
-  {
-  }
+  /// 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.
+  };
 
-  ~BgFetchRule()
-  {
-    delete _field;
-    delete _value;
-    delete _next;
-  }
+  /// 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) {}
 
-  // For chaining the linked list
-  void
-  chain(BgFetchRule *n)
+  BgFetchRule(bool exc, swoc::TextView name, swoc::TextView value)
+    : _exclude(exc), _value(field_cmp_type{std::string(name), 
std::string(value)})
   {
-    _next = n;
   }
 
+  BgFetchRule(self_type &&that) = default;
+
   // Main evaluation entry point.
   bool bgFetchAllowed(TSHttpTxn txnp) const;
   bool check_field_configured(TSHttpTxn txnp) const;
 
-  bool _exclude;
-  const char *_field;
-  const char *_value;
-  BgFetchRule *_next; // For the linked list
+  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.
 };

Reply via email to