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

zwoop 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 855eb10eab Produce warnings when bad mods are used (#12749)
855eb10eab is described below

commit 855eb10eabad7f7cd086e56d910574c8c6beca51
Author: Leif Hedstrom <[email protected]>
AuthorDate: Mon Jan 5 10:41:23 2026 -0700

    Produce warnings when bad mods are used (#12749)
---
 plugins/header_rewrite/condition.cc | 24 ++++++++++++------------
 plugins/header_rewrite/operator.cc  |  8 +++++---
 plugins/header_rewrite/parser.cc    | 27 ++++++++++++++++++++++++++-
 plugins/header_rewrite/parser.h     | 14 ++++++++++++--
 4 files changed, 55 insertions(+), 18 deletions(-)

diff --git a/plugins/header_rewrite/condition.cc 
b/plugins/header_rewrite/condition.cc
index da657c59d9..3d0de68477 100644
--- a/plugins/header_rewrite/condition.cc
+++ b/plugins/header_rewrite/condition.cc
@@ -80,17 +80,17 @@ Condition::initialize(Parser &p)
 {
   Statement::initialize(p);
 
-  if (p.mod_exist("OR")) {
-    if (p.mod_exist("AND")) {
+  if (p.consume_mod("OR")) {
+    if (p.consume_mod("AND")) {
       TSError("[%s] Can't have both AND and OR in mods", PLUGIN_NAME);
     } else {
       _mods |= CondModifiers::OR;
     }
-  } else if (p.mod_exist("AND")) {
+  } else if (p.consume_mod("AND")) {
     _mods |= CondModifiers::AND;
   }
 
-  if (p.mod_exist("NOT")) {
+  if (p.consume_mod("NOT")) {
     _mods |= CondModifiers::NOT;
   }
 
@@ -98,25 +98,25 @@ Condition::initialize(Parser &p)
   // strings and regexes.
   int _substr_seen = 0;
 
-  if (p.mod_exist("NOCASE")) {
+  if (p.consume_mod("NOCASE")) {
     _mods |= CondModifiers::MOD_NOCASE;
-  } else if (p.mod_exist("CASE")) {
+  } else if (p.consume_mod("CASE")) {
     // Nothing to do — default is case-sensitive, but still allow this string 
for clearness.
   }
 
-  if (p.mod_exist("EXT")) {
+  if (p.consume_mod("EXT")) {
     _mods |= CondModifiers::MOD_EXT;
     _substr_seen++;
   }
-  if (p.mod_exist("SUF")) {
+  if (p.consume_mod("SUF")) {
     _mods |= CondModifiers::MOD_SUF;
     _substr_seen++;
   }
-  if (p.mod_exist("PRE")) {
+  if (p.consume_mod("PRE")) {
     _mods |= CondModifiers::MOD_PRE;
     _substr_seen++;
   }
-  if (p.mod_exist("MID")) {
+  if (p.consume_mod("MID")) {
     _mods |= CondModifiers::MOD_MID;
     _substr_seen++;
   }
@@ -125,10 +125,10 @@ Condition::initialize(Parser &p)
     throw std::runtime_error("Only one substring modifier (EXT, SUF, PRE, MID) 
may be used.");
   }
 
-  // Deal with the "last" modifier as well.
-  if (p.mod_exist("L")) {
+  if (p.consume_mod("L")) {
     _mods |= CondModifiers::MOD_L;
   }
 
   _cond_op = parse_matcher_op(p.get_arg());
+  p.validate_mods();
 }
diff --git a/plugins/header_rewrite/operator.cc 
b/plugins/header_rewrite/operator.cc
index 4cd337ca4b..6643bb8059 100644
--- a/plugins/header_rewrite/operator.cc
+++ b/plugins/header_rewrite/operator.cc
@@ -38,17 +38,19 @@ Operator::initialize(Parser &p)
 {
   Statement::initialize(p);
 
-  if (p.mod_exist("L") || p.mod_exist("LAST")) {
+  if (p.consume_mod("L") || p.consume_mod("LAST")) {
     _mods = static_cast<OperModifiers>(_mods | OPER_LAST);
   }
 
-  if (p.mod_exist("QSA")) {
+  if (p.consume_mod("QSA")) {
     _mods = static_cast<OperModifiers>(_mods | OPER_QSA);
   }
 
-  if (p.mod_exist("I") || p.mod_exist("INV")) {
+  if (p.consume_mod("I") || p.consume_mod("INV")) {
     _mods = static_cast<OperModifiers>(_mods | OPER_INV);
   }
+
+  p.validate_mods();
 }
 
 void
diff --git a/plugins/header_rewrite/parser.cc b/plugins/header_rewrite/parser.cc
index 12f0c15d85..745f7d0882 100644
--- a/plugins/header_rewrite/parser.cc
+++ b/plugins/header_rewrite/parser.cc
@@ -181,7 +181,12 @@ Parser::preprocess(std::vector<std::string> tokens)
           std::string        t;
 
           while (getline(iss, t, ',')) {
-            _mods.push_back(t);
+            if (std::find(_mods.begin(), _mods.end(), t) != _mods.end()) {
+              // This produces an error, but it's not fatal for load / reload. 
ToDo: ATS v11 fix.
+              TSError("[%s] Duplicate modifier: %s", PLUGIN_NAME, t.c_str());
+            } else {
+              _mods.push_back(t);
+            }
           }
         } else {
           _mods.push_back(m);
@@ -303,6 +308,26 @@ Parser::cond_is_hook(TSHttpHookID &hook) const
   return false;
 }
 
+// This is a TSError() here, but where this is called from does not treat 
"false" as a
+// load failure. This is a systemic problem in a some of the parsing. ToDo: 
ATS v11 fix.
+bool
+Parser::validate_mods() const
+{
+  if (_mods.empty()) {
+    return true;
+  }
+
+  auto        it   = _mods.begin();
+  std::string list = *it++;
+
+  for (; it != _mods.end(); ++it) {
+    list += ", ";
+    list += *it;
+  }
+  TSError("[%s] Unknown modifier(s): [%s]", PLUGIN_NAME, list.c_str());
+  return false;
+}
+
 HRWSimpleTokenizer::HRWSimpleTokenizer(const std::string &line)
 {
   ParserState state            = PARSER_DEFAULT;
diff --git a/plugins/header_rewrite/parser.h b/plugins/header_rewrite/parser.h
index 634df4694b..854ba45231 100644
--- a/plugins/header_rewrite/parser.h
+++ b/plugins/header_rewrite/parser.h
@@ -195,12 +195,22 @@ public:
     return _val;
   }
 
+  // Check if the modifier exists and consume it from the list.
   bool
-  mod_exist(const std::string &m) const
+  consume_mod(const std::string &m)
   {
-    return std::find(_mods.begin(), _mods.end(), m) != _mods.end();
+    auto it = std::find(_mods.begin(), _mods.end(), m);
+
+    if (it != _mods.end()) {
+      _mods.erase(it);
+      return true;
+    }
+    return false;
   }
 
+  // Validate that all modifiers were consumed; logs error and returns false 
if not
+  bool validate_mods() const;
+
   bool cond_is_hook(TSHttpHookID &hook) const;
 
   const std::vector<std::string> &

Reply via email to