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 6addcf4b2a Adds a HTTP-CNTL condition to header_rewrite (#11863)
6addcf4b2a is described below

commit 6addcf4b2ac7278dde466d4d7aa7042cd74fc1e6
Author: Leif Hedstrom <[email protected]>
AuthorDate: Thu Nov 14 21:00:31 2024 -0700

    Adds a HTTP-CNTL condition to header_rewrite (#11863)
---
 doc/admin-guide/plugins/header_rewrite.en.rst | 195 ++++++++++++++------------
 plugins/header_rewrite/conditions.cc          |  16 +++
 plugins/header_rewrite/conditions.h           |  32 +++++
 plugins/header_rewrite/factory.cc             |   2 +
 plugins/header_rewrite/operators.cc           |  29 +---
 plugins/header_rewrite/statement.cc           |  27 ++++
 plugins/header_rewrite/statement.h            |   1 +
 7 files changed, 183 insertions(+), 119 deletions(-)

diff --git a/doc/admin-guide/plugins/header_rewrite.en.rst 
b/doc/admin-guide/plugins/header_rewrite.en.rst
index dcb99bf9cb..5de3dc7695 100644
--- a/doc/admin-guide/plugins/header_rewrite.en.rst
+++ b/doc/admin-guide/plugins/header_rewrite.en.rst
@@ -212,6 +212,41 @@ phase of the transaction.  This happens when there is no 
host in the incoming UR
 and only set as a host header.  During the remap phase the host header is 
copied
 to the CLIENT-URL.  Use CLIENT-HEADER:Host if you are going to match the host.
 
+CIDR
+~~~~
+::
+
+   set-header @Client-CIDR %{CIDR:24,48}
+
+This condition takes the client IP, and applies the provided CIDR style masks
+to the IP, before producing a string. The typical use of this conditions is as
+above, producing a header that contains a IP representation which has some
+privacy properties. It can of course also be used as a regular condition, and
+the output is a string that can be compared against. The two optional
+arguments are as follows::
+
+    IPv4-Mask    Length, in bits, of the IPv4 address to preserve. Default: 24
+    IPv6-Mask    Length, in bits, of the IPv6 address to preserve. Default: 48
+
+The two arguments, if provided, are comma separated. Valid syntax includes::
+
+    %{CIDR}         Defaults to 24,48 (as above)
+    %{CIDR:16}      IPv4 CIDR mask is 16 bits, IPv6 mask is 48
+    %{CIDR:18,42}   IPv4 CIDR mask is 18 bits, IPv6 mask is 42 bits
+
+A typical use case is to insert the @-prefixed header as above, and then use
+this header in a custom log format, rather than logging the full client
+IP. Another use case could be to make a special condition on a sub-net,
+e.g.::
+
+    cond %{CIDR:8} ="8.0.0.0"
+        set-header X-Is-Eight "Yes"
+    cond %{CIDR:,8} ="fd00::" #note the IPv6 Mask is in the second position
+        set-header IPv6Internal "true"
+
+This condition has no requirements other than access to the Client IP, hence,
+it should work in any and all hooks.
+
 COOKIE
 ~~~~~~
 ::
@@ -237,32 +272,6 @@ Per-Mapping`_ above.
 The ``<part>`` allows the operand to match against just a component of the URL,
 as documented in `URL Parts`_ below.
 
-NEXT-HOP
-~~~~~~~~
-::
-
-    cond %{NEXT-HOP:<part>} <operand>
-
-Returns next hop current selected parent information.  The following qualifiers
-are supported::
-
-    %{NEXT-HOP:HOST} Name of the current selected parent.
-    %{NEXT-HOP:PORT} Port of the current selected parent.
-
-Note that the ``<part>`` of NEXT-HOP will likely not be available unless
-an origin server connection is attempted at which point it will available
-as part of the ``SEND_REQUEST_HDR_HOOK``.
-
-For example::
-
-    cond %{SEND_REQUEST_HDR_HOOK} [AND]
-    cond %{NEXT-HOP:HOST} =www.firstparent.com
-        set-header Host vhost.firstparent.com
-
-    cond %{SEND_REQUEST_HDR_HOOK} [AND]
-    cond %{NEXT-HOP:HOST} =www.secondparent.com
-        set-header Host vhost.secondparent.com
-
 GEO
 ~~~
 ::
@@ -309,6 +318,20 @@ separated string of the values from every occurrence of 
the header. Refer to
 If you wish to use a client request header, regardless of hook context, you may
 consider using the `CLIENT-HEADER`_ condition instead.
 
+HTTP-CNTL
+~~~~~~~~~
+::
+
+    cond %{HTTP-CNTL:<controller>}
+
+This condition allows you to check the state of various HTTP controls. The 
controls
+are of the same name as for `set-http-cntl`. This condition returns a ``true`` 
or
+``false`` value, depending on the state of the control. For example::
+
+    cond %{HTTP-CNTL:LOGGING} [NOT]
+
+would only continue evaluation if logging is turned off.
+
 ID
 ~~
 ::
@@ -329,41 +352,6 @@ arguments to another operator. For example::
 
     set-header ATS-Req-UUID %{ID:UNIQUE}
 
-CIDR
-~~~~
-::
-
-   set-header @Client-CIDR %{CIDR:24,48}
-
-This condition takes the client IP, and applies the provided CIDR style masks
-to the IP, before producing a string. The typical use of this conditions is as
-above, producing a header that contains a IP representation which has some
-privacy properties. It can of course also be used as a regular condition, and
-the output is a string that can be compared against. The two optional
-arguments are as follows::
-
-    IPv4-Mask    Length, in bits, of the IPv4 address to preserve. Default: 24
-    IPv6-Mask    Length, in bits, of the IPv6 address to preserve. Default: 48
-
-The two arguments, if provided, are comma separated. Valid syntax includes::
-
-    %{CIDR}         Defaults to 24,48 (as above)
-    %{CIDR:16}      IPv4 CIDR mask is 16 bits, IPv6 mask is 48
-    %{CIDR:18,42}   IPv4 CIDR mask is 18 bits, IPv6 mask is 42 bits
-
-A typical use case is to insert the @-prefixed header as above, and then use
-this header in a custom log format, rather than logging the full client
-IP. Another use case could be to make a special condition on a sub-net,
-e.g.::
-
-    cond %{CIDR:8} ="8.0.0.0"
-        set-header X-Is-Eight "Yes"
-    cond %{CIDR:,8} ="fd00::" #note the IPv6 Mask is in the second position
-        set-header IPv6Internal "true"
-
-This condition has no requirements other than access to the Client IP, hence,
-it should work in any and all hooks.
-
 INBOUND
 ~~~~~~~
 ::
@@ -463,6 +451,32 @@ METHOD
 The HTTP method (e.g. ``GET``, ``HEAD``, ``POST``, and so on) used by the
 client for this transaction.
 
+NEXT-HOP
+~~~~~~~~
+::
+
+    cond %{NEXT-HOP:<part>} <operand>
+
+Returns next hop current selected parent information.  The following qualifiers
+are supported::
+
+    %{NEXT-HOP:HOST} Name of the current selected parent.
+    %{NEXT-HOP:PORT} Port of the current selected parent.
+
+Note that the ``<part>`` of NEXT-HOP will likely not be available unless
+an origin server connection is attempted at which point it will available
+as part of the ``SEND_REQUEST_HDR_HOOK``.
+
+For example::
+
+    cond %{SEND_REQUEST_HDR_HOOK} [AND]
+    cond %{NEXT-HOP:HOST} =www.firstparent.com
+        set-header Host vhost.firstparent.com
+
+    cond %{SEND_REQUEST_HDR_HOOK} [AND]
+    cond %{NEXT-HOP:HOST} =www.secondparent.com
+        set-header Host vhost.secondparent.com
+
 NOW
 ~~~
 ::
@@ -679,6 +693,24 @@ no-op
 
 This operator does nothing, takes no arguments, and has no side effects.
 
+rm-destination
+~~~~~~~~~~~~~~
+::
+
+  rm-destination <part>
+
+Removes individual components of the remapped destination's address. When
+changing the remapped destination, ``<part>`` should be used to indicate the
+component that is being modified (see `URL Parts`_). Currently the only valid
+parts for rm-destination are QUERY, PATH, and PORT.
+
+For the query parameter, this operator takes an optional second argument,
+which is a list of query parameters to remove (or keep with ``[INV]`` 
modifier).
+
+::
+
+  rm-destination QUERY <comma separate list of query parameter>
+
 rm-header
 ~~~~~~~~~
 ::
@@ -695,6 +727,15 @@ rm-cookie
 
 Removes the cookie ``<name>``.
 
+run-plugin
+~~~~~~~~~~~~~~
+::
+
+  run-plugin <plugin-name>.so "<plugin-argument> ..."
+
+This allows to run an existing remap plugin, conditionally, from within a
+header rewrite rule.
+
 set-body
 ~~~~~~~~
 ::
@@ -774,7 +815,7 @@ the appropriate logs even when the debug tag has not been 
enabled. For
 additional information on |TS| debugging statements, refer to
 :ref:`developer-debug-tags` in the developer's documentation.
 
-**Note**: This operator is deprecated, use the ``set-http-cntl`` operator 
instead,
+**Note**: This operator is deprecated, use the `set-http-cntl` operator 
instead,
 with the ``TXN_DEBUG`` control.
 
 set-destination
@@ -790,34 +831,6 @@ used as its replacement. You must supply a non-zero length 
value, otherwise
 this operator will be an effective no-op (though a warning will be emitted to
 the logs if debugging is enabled).
 
-rm-destination
-~~~~~~~~~~~~~~
-::
-
-  rm-destination <part>
-
-Removes individual components of the remapped destination's address. When
-changing the remapped destination, ``<part>`` should be used to indicate the
-component that is being modified (see `URL Parts`_). Currently the only valid
-parts for rm-destination are QUERY, PATH, and PORT.
-
-For the query parameter, this operator takes an optional second argument,
-which is a list of query parameters to remove (or keep with ``[INV]`` 
modifier).
-
-::
-
-  rm-destination QUERY <comma separate list of query parameter>
-
-
-run-plugin
-~~~~~~~~~~~~~~
-::
-
-  run-plugin <plugin-name>.so "<plugin-argument> ..."
-
-This allows to run an existing remap plugin, conditionally, from within a
-header rewrite rule.
-
 set-header
 ~~~~~~~~~~
 ::
@@ -886,7 +899,7 @@ When invoked, and when ``<value>`` is any of ``1``, 
``true``, or ``TRUE``, this
 operator causes |TS| to abort further request remapping. Any other value and
 the operator will effectively be a no-op.
 
-**Note**: This operator is deprecated, use the ``set-http-cntl`` operator 
instead,
+**Note**: This operator is deprecated, use the `set-http-cntl` operator 
instead,
 with the ``SKIP_REMAP`` control.
 
 set-cookie
diff --git a/plugins/header_rewrite/conditions.cc 
b/plugins/header_rewrite/conditions.cc
index 67ed1f7567..747d260211 100644
--- a/plugins/header_rewrite/conditions.cc
+++ b/plugins/header_rewrite/conditions.cc
@@ -1425,3 +1425,19 @@ ConditionNextHop::eval(const Resources &res)
 
   return static_cast<const Matchers<std::string> *>(_matcher)->test(s);
 }
+
+// ConditionHttpCntl: request header.
+void
+ConditionHttpCntl::initialize(Parser &p)
+{
+  Condition::initialize(p);
+}
+
+void
+ConditionHttpCntl::set_qualifier(const std::string &q)
+{
+  Condition::set_qualifier(q);
+
+  Dbg(pi_dbg_ctl, "\tParsing %%{HTTP-CNTL:%s}", q.c_str());
+  _http_cntl_qual = parse_http_cntl_qualifier(q);
+}
diff --git a/plugins/header_rewrite/conditions.h 
b/plugins/header_rewrite/conditions.h
index c6e1ff5dfb..6568fbeba9 100644
--- a/plugins/header_rewrite/conditions.h
+++ b/plugins/header_rewrite/conditions.h
@@ -627,3 +627,35 @@ protected:
 private:
   NextHopQualifiers _next_hop_qual = NEXT_HOP_NONE;
 };
+
+// HTTP CNTL
+class ConditionHttpCntl : public Condition
+{
+public:
+  explicit ConditionHttpCntl() { Dbg(dbg_ctl, "Calling CTOR for 
ConditionHttpCntl"); }
+
+  // noncopyable
+  ConditionHttpCntl(const ConditionHttpCntl &) = delete;
+  void operator=(const ConditionHttpCntl &)    = delete;
+
+  void initialize(Parser &p) override;
+  void set_qualifier(const std::string &q) override;
+
+  void
+  append_value(std::string &s, const Resources &res) override
+  {
+    s += TSHttpTxnCntlGet(res.txnp, _http_cntl_qual) ? "TRUE" : "FALSE";
+    Dbg(pi_dbg_ctl, "Evaluating HTTP-CNTL(%s)", _qualifier.c_str());
+  }
+
+protected:
+  bool
+  eval(const Resources &res) override
+  {
+    Dbg(pi_dbg_ctl, "Evaluating HTTP-CNTL()");
+    return TSHttpTxnCntlGet(res.txnp, _http_cntl_qual);
+  }
+
+private:
+  TSHttpCntlType _http_cntl_qual = TS_HTTP_CNTL_LOGGING_MODE;
+};
diff --git a/plugins/header_rewrite/factory.cc 
b/plugins/header_rewrite/factory.cc
index 346265f893..85136f0b04 100644
--- a/plugins/header_rewrite/factory.cc
+++ b/plugins/header_rewrite/factory.cc
@@ -162,6 +162,8 @@ condition_factory(const std::string &cond)
     c = new ConditionCache();
   } else if (c_name == "NEXT-HOP") { // This condition adapts to the hook
     c = new ConditionNextHop();
+  } else if (c_name == "HTTP-CNTL") { // This condition adapts to the hook
+    c = new ConditionHttpCntl();
   } else {
     TSError("[%s] Unknown condition %s", PLUGIN_NAME, c_name.c_str());
     return nullptr;
diff --git a/plugins/header_rewrite/operators.cc 
b/plugins/header_rewrite/operators.cc
index 189e39b83f..6f5a8dcbcc 100644
--- a/plugins/header_rewrite/operators.cc
+++ b/plugins/header_rewrite/operators.cc
@@ -1150,38 +1150,11 @@ OperatorSetDebug::exec(const Resources &res) const
   return true;
 }
 
-// OperatorSetHttpCntl
-TSHttpCntlType
-parse_cntl_qualifier(const std::string &q) // Helper function for parsing 
modifiers
-{
-  TSHttpCntlType qual = TS_HTTP_CNTL_LOGGING_MODE;
-
-  if (q == "LOGGING") {
-    qual = TS_HTTP_CNTL_LOGGING_MODE;
-  } else if (q == "INTERCEPT_RETRY") {
-    qual = TS_HTTP_CNTL_INTERCEPT_RETRY_MODE;
-  } else if (q == "RESP_CACHEABLE") {
-    qual = TS_HTTP_CNTL_RESPONSE_CACHEABLE;
-  } else if (q == "REQ_CACHEABLE") {
-    qual = TS_HTTP_CNTL_REQUEST_CACHEABLE;
-  } else if (q == "SERVER_NO_STORE") {
-    qual = TS_HTTP_CNTL_SERVER_NO_STORE;
-  } else if (q == "TXN_DEBUG") {
-    qual = TS_HTTP_CNTL_TXN_DEBUG;
-  } else if (q == "SKIP_REMAP") {
-    qual = TS_HTTP_CNTL_SKIP_REMAPPING;
-  } else {
-    TSError("[%s] Invalid HTTP-CNTL() qualifier: %s", PLUGIN_NAME, q.c_str());
-  }
-
-  return qual;
-}
-
 void
 OperatorSetHttpCntl::initialize(Parser &p)
 {
   Operator::initialize(p);
-  _cntl_qual = parse_cntl_qualifier(p.get_arg());
+  _cntl_qual = parse_http_cntl_qualifier(p.get_arg());
 
   std::string flag = p.copy_value();
 
diff --git a/plugins/header_rewrite/statement.cc 
b/plugins/header_rewrite/statement.cc
index 69bacda1fe..92e9fb67b5 100644
--- a/plugins/header_rewrite/statement.cc
+++ b/plugins/header_rewrite/statement.cc
@@ -114,3 +114,30 @@ Statement::parse_url_qualifier(const std::string &q) const
 
   return qual;
 }
+
+// Parse HTTP CNTL qualifiers
+TSHttpCntlType
+Statement::parse_http_cntl_qualifier(const std::string &q) const
+{
+  TSHttpCntlType qual = TS_HTTP_CNTL_LOGGING_MODE;
+
+  if (q == "LOGGING") {
+    qual = TS_HTTP_CNTL_LOGGING_MODE;
+  } else if (q == "INTERCEPT_RETRY") {
+    qual = TS_HTTP_CNTL_INTERCEPT_RETRY_MODE;
+  } else if (q == "RESP_CACHEABLE") {
+    qual = TS_HTTP_CNTL_RESPONSE_CACHEABLE;
+  } else if (q == "REQ_CACHEABLE") {
+    qual = TS_HTTP_CNTL_REQUEST_CACHEABLE;
+  } else if (q == "SERVER_NO_STORE") {
+    qual = TS_HTTP_CNTL_SERVER_NO_STORE;
+  } else if (q == "TXN_DEBUG") {
+    qual = TS_HTTP_CNTL_TXN_DEBUG;
+  } else if (q == "SKIP_REMAP") {
+    qual = TS_HTTP_CNTL_SKIP_REMAPPING;
+  } else {
+    TSError("[%s] Invalid HTTP-CNTL() qualifier: %s", PLUGIN_NAME, q.c_str());
+  }
+
+  return qual;
+}
diff --git a/plugins/header_rewrite/statement.h 
b/plugins/header_rewrite/statement.h
index 1b5798bff3..9055558531 100644
--- a/plugins/header_rewrite/statement.h
+++ b/plugins/header_rewrite/statement.h
@@ -152,6 +152,7 @@ protected:
 
   UrlQualifiers     parse_url_qualifier(const std::string &q) const;
   NextHopQualifiers parse_next_hop_qualifier(const std::string &q) const;
+  TSHttpCntlType    parse_http_cntl_qualifier(const std::string &q) const;
 
   void
   require_resources(const ResourceIDs ids)

Reply via email to