This is an automated email from the ASF dual-hosted git repository.
maskit 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 d76fe3bb90 header_rewrite: Add set-effective-address operator (#12521)
d76fe3bb90 is described below
commit d76fe3bb906956df644d563669fdeb213b4e0b4d
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Wed Sep 24 12:24:26 2025 -0600
header_rewrite: Add set-effective-address operator (#12521)
* header_rewrite: Add set-effective-address operator
* Add documentation
* Fix typo
* Fix rest syntax
* Apply the change for private_slot
* Fix the debug message
* Update factory.cc
* Use get_arg instead of get_value
* Add tests
* Remove unnecessary set-header for debugging
* Use the default ready condtions that micorserver has
---
doc/admin-guide/plugins/header_rewrite.en.rst | 13 +++++
plugins/header_rewrite/factory.cc | 2 +
plugins/header_rewrite/operators.cc | 42 ++++++++++++++++
plugins/header_rewrite/operators.h | 25 ++++++++++
.../gold/header_rewrite_effective_address.gold | 7 +++
.../header_rewrite_effective_address.test.py | 56 ++++++++++++++++++++++
.../rules/rule_effective_address.conf | 23 +++++++++
7 files changed, 168 insertions(+)
diff --git a/doc/admin-guide/plugins/header_rewrite.en.rst
b/doc/admin-guide/plugins/header_rewrite.en.rst
index de2b1cbecf..1711337964 100644
--- a/doc/admin-guide/plugins/header_rewrite.en.rst
+++ b/doc/admin-guide/plugins/header_rewrite.en.rst
@@ -1241,6 +1241,19 @@ If ``PROXY`` is set, and PROXY protocol is used, the
source IP address provided
.. note::
The conditions return an empty string if the source is set to ``PROXY``
but PROXY protocol header does not present.
+set-effective-address
+~~~~~~~~~~~~~~~~~~~~~
+::
+
+ set-effective-address <address>
+
+This operator allows you to set client's effective address for a transaction.
The address will be used on other conditions and
+operators that use client's IP address.
+
+.. note::
+ This operator also changes `INBOUND_IP_SOURCE` to `PLUGIN` to make the
address available for other conditions and operators.
+ See `set-plugin-cntl`_ for the detail.
+
Operator Flags
--------------
diff --git a/plugins/header_rewrite/factory.cc
b/plugins/header_rewrite/factory.cc
index f06029d24e..3317b49b33 100644
--- a/plugins/header_rewrite/factory.cc
+++ b/plugins/header_rewrite/factory.cc
@@ -87,6 +87,8 @@ operator_factory(const std::string &op)
o = new OperatorSetStateInt8();
} else if (op == "set-state-int16") {
o = new OperatorSetStateInt16();
+ } else if (op == "set-effective-address") {
+ o = new OperatorSetEffectiveAddress();
} else {
TSError("[%s] Unknown operator: %s", PLUGIN_NAME, op.c_str());
return nullptr;
diff --git a/plugins/header_rewrite/operators.cc
b/plugins/header_rewrite/operators.cc
index f6fff45540..cb7ac53c12 100644
--- a/plugins/header_rewrite/operators.cc
+++ b/plugins/header_rewrite/operators.cc
@@ -1585,3 +1585,45 @@ OperatorSetStateInt16::exec(const Resources &res) const
return true;
}
+
+void
+OperatorSetEffectiveAddress::initialize(Parser &p)
+{
+ Operator::initialize(p);
+
+ _value.set_value(p.get_arg(), this);
+}
+
+void
+OperatorSetEffectiveAddress::initialize_hooks()
+{
+ add_allowed_hook(TS_HTTP_READ_REQUEST_HDR_HOOK);
+ add_allowed_hook(TS_REMAP_PSEUDO_HOOK);
+}
+
+bool
+OperatorSetEffectiveAddress::exec(const Resources &res) const
+{
+ std::string value;
+ _value.append_value(value, res);
+
+ // Never set an empty address
+ if (value.empty()) {
+ Dbg(pi_dbg_ctl, "Address is empty, skipping");
+ return true;
+ }
+
+ auto addr = swoc::IPAddr(value);
+ struct sockaddr_storage storage;
+ addr.copy_to(reinterpret_cast<struct sockaddr *>(&storage));
+ TSHttpTxnVerifiedAddrSet(res.state.txnp, reinterpret_cast<struct sockaddr
*>(&storage));
+
+ PrivateSlotData private_data;
+ private_data.raw =
reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp, _txn_private_slot));
+ private_data.ip_source = IP_SRC_PLUGIN;
+
+ Dbg(pi_dbg_ctl, " Setting plugin control INBOUND_IP_SOURCE to
IP_SRC_PLUGIN");
+ TSUserArgSet(res.state.txnp, _txn_private_slot, reinterpret_cast<void
*>(private_data.raw));
+
+ return true;
+}
diff --git a/plugins/header_rewrite/operators.h
b/plugins/header_rewrite/operators.h
index b0943b7e19..4ff4f0edcb 100644
--- a/plugins/header_rewrite/operators.h
+++ b/plugins/header_rewrite/operators.h
@@ -626,3 +626,28 @@ protected:
private:
Value _value;
};
+
+class OperatorSetEffectiveAddress : public Operator
+{
+public:
+ OperatorSetEffectiveAddress() { Dbg(dbg_ctl, "Calling CTOR for
OperatorSetEffectiveAddress"); }
+
+ // noncopyable
+ OperatorSetEffectiveAddress(const OperatorSetEffectiveAddress &) = delete;
+ void operator=(const OperatorSetEffectiveAddress &) = delete;
+
+ void initialize(Parser &p) override;
+
+protected:
+ void initialize_hooks() override;
+ bool exec(const Resources &res) const override;
+
+ bool
+ need_txn_private_slot() const override
+ {
+ return true;
+ }
+
+private:
+ Value _value;
+};
diff --git
a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_effective_address.gold
b/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_effective_address.gold
new file mode 100644
index 0000000000..063298216b
--- /dev/null
+++
b/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_effective_address.gold
@@ -0,0 +1,7 @@
+``
+> Real-IP: 1.2.3.4
+``
+< HTTP/1.1 200 OK
+``
+< Effective-IP: 1.2.3.4
+``
diff --git
a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_effective_address.test.py
b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_effective_address.test.py
new file mode 100644
index 0000000000..47aa54002d
--- /dev/null
+++
b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_effective_address.test.py
@@ -0,0 +1,56 @@
+'''
+'''
+# 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.
+
+Test.Summary = '''
+Test header_rewrite set-effective-address operator.
+'''
+
+Test.ContinueOnFail = True
+# Define default ATS
+ts = Test.MakeATSProcess("ts")
+server = Test.MakeOriginServer("server")
+
+Test.testName = "header_rewrite_effective_address"
+request_get = {"headers": "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n",
"timestamp": "1469733493.993", "body": ""}
+# expected response from the origin server
+response = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n",
"timestamp": "1469733493.993", "body": ""}
+
+# add response to the server dictionary
+session_file = "sessionfile.log"
+server.addResponse(session_file, request_get, response)
+ts.Disk.records_config.update(
+ {
+ 'proxy.config.diags.debug.enabled': 1,
+ 'proxy.config.diags.debug.tags': 'header_rewrite|dbg_header_rewrite',
+ })
+# The following rule inserts a via header if the request method is a GET or
DELETE
+conf_name = "rule_effective_address.conf"
+ts.Setup.CopyAs(f'rules/{conf_name}', Test.RunDirectory)
+ts.Disk.plugin_config.AddLine(f'header_rewrite.so
{Test.RunDirectory}/{conf_name}')
+ts.Disk.remap_config.AddLine(f'map http://www.example.com
http://127.0.0.1:{server.Variables.Port}')
+
+# Test that the IP address in Real-IP request header is returned in
Effective-IP response header.
+expected_output = "gold/header_rewrite_effective_address.gold"
+tr = Test.AddTestRun()
+tr.MakeCurlCommand(
+ f'--http1.1 -H "Host: www.example.com" -H "Real-IP: 1.2.3.4" --verbose
"http://127.0.0.1:{ts.Variables.port}"', ts=ts)
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.StartBefore(server)
+tr.Processes.Default.StartBefore(Test.Processes.ts)
+tr.Processes.Default.Streams.stderr = expected_output
+tr.StillRunningAfter = server
diff --git
a/tests/gold_tests/pluginTest/header_rewrite/rules/rule_effective_address.conf
b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_effective_address.conf
new file mode 100644
index 0000000000..143a2c3b43
--- /dev/null
+++
b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_effective_address.conf
@@ -0,0 +1,23 @@
+#
+# 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.
+
+cond %{READ_REQUEST_HDR_HOOK}
+ set-effective-address %{HEADER:Real-IP}
+
+cond %{SEND_RESPONSE_HDR_HOOK}
+ set-header Effective-IP %{INBOUND:REMOTE-ADDR}
+