From deb39fe4012e74e9b531acf0ca6d94c6a715a27c Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Wed, 16 Jul 2025 15:16:46 -0600 Subject: [PATCH 1/2] Refactoring and cleanup of HRW autest Adds the new Manager for this shindig --- tests/autest.sh.in | 2 +- tests/gold_tests/lib/ats_autest.py | 153 +++++++++++ ...er_rewrite-client.gold => client-url.gold} | 0 .../header_rewrite/gold/cond-elif.gold | 2 +- ...ewrite_cond_cache.gold => cond_cache.gold} | 26 +- .../header_rewrite/gold/cond_cache_first.gold | 15 ++ ...rite_cond_method.gold => cond_method.gold} | 0 ...txn_count.gold => cond_ssn_txn_count.gold} | 12 +- .../header_rewrite/gold/ext-sets.gold | 2 +- .../gold/header_rewrite-502.gold | 5 - ...ader_rewrite-l_value.gold => l_value.gold} | 0 .../header_rewrite/header_rewrite.test.py | 95 ------- .../header_rewrite_bundle.test.py | 246 ++++++++++++++++++ .../header_rewrite_cond_cache.test.py | 67 ----- .../header_rewrite_cond_method.test.py | 73 ------ .../header_rewrite_cond_ssn_txn_count.test.py | 101 ------- .../header_rewrite_effective_address.test.py | 56 ---- .../header_rewrite_l_value.test.py | 60 ----- .../header_rewrite/header_rewrite_url.test.py | 112 -------- .../pluginTest/header_rewrite/rules/rule.conf | 1 + .../header_rewrite/rules/rule_client.conf | 2 +- .../rules/rule_cond_method.conf | 2 +- .../rules/rule_effective_address.conf | 3 +- .../header_rewrite/rules/rule_l_value.conf | 2 + 24 files changed, 435 insertions(+), 602 deletions(-) create mode 100644 tests/gold_tests/lib/ats_autest.py rename tests/gold_tests/pluginTest/header_rewrite/gold/{header_rewrite-client.gold => client-url.gold} (100%) rename tests/gold_tests/pluginTest/header_rewrite/gold/{header_rewrite_cond_cache.gold => cond_cache.gold} (59%) create mode 100644 tests/gold_tests/pluginTest/header_rewrite/gold/cond_cache_first.gold rename tests/gold_tests/pluginTest/header_rewrite/gold/{header_rewrite_cond_method.gold => cond_method.gold} (100%) rename tests/gold_tests/pluginTest/header_rewrite/gold/{header_rewrite_cond_ssn_txn_count.gold => cond_ssn_txn_count.gold} (86%) delete mode 100644 tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite-502.gold rename tests/gold_tests/pluginTest/header_rewrite/gold/{header_rewrite-l_value.gold => l_value.gold} (100%) delete mode 100644 tests/gold_tests/pluginTest/header_rewrite/header_rewrite.test.py create mode 100644 tests/gold_tests/pluginTest/header_rewrite/header_rewrite_bundle.test.py delete mode 100644 tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_cache.test.py delete mode 100644 tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_method.test.py delete mode 100644 tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_ssn_txn_count.test.py delete mode 100644 tests/gold_tests/pluginTest/header_rewrite/header_rewrite_effective_address.test.py delete mode 100644 tests/gold_tests/pluginTest/header_rewrite/header_rewrite_l_value.test.py delete mode 100644 tests/gold_tests/pluginTest/header_rewrite/header_rewrite_url.test.py diff --git a/tests/autest.sh.in b/tests/autest.sh.in index 97136bdcc13..51afd8d53a0 100755 --- a/tests/autest.sh.in +++ b/tests/autest.sh.in @@ -5,7 +5,7 @@ # export LD_LIBRARY_PATH=${CMAKE_INSTALL_PREFIX}/lib -export PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}/gold_tests/remap:$PYTHONPATH +export PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}/gold_tests/remap:${CMAKE_CURRENT_SOURCE_DIR}/gold_tests/lib:$PYTHONPATH # Define tests to skip for CURL_UDS_FLAG if [ -n "${CURL_UDS_FLAG}" ]; then diff --git a/tests/gold_tests/lib/ats_autest.py b/tests/gold_tests/lib/ats_autest.py new file mode 100644 index 00000000000..34aa0fca1e9 --- /dev/null +++ b/tests/gold_tests/lib/ats_autest.py @@ -0,0 +1,153 @@ +''' +Shared library code for ATS autest tests. Add and update this file as needed. +''' +# 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. + +import glob +import os +import time + + +class ATSTestManager: + """ + A comprehensive test management class for Apache Traffic Server tests. + """ + host_example = "Host: www.example.com" + conn_keepalive = "Connection: keep-alive" + + def __init__(self, Test, When, test_name="ts"): + """ + Initialize the ATSTestManager with ATS and origin server processes. + """ + self.Test = Test + self.When = When + self.ts = self.Test.MakeATSProcess(test_name) + self.server = self.Test.MakeOriginServer("server") + + self.ats_port = self.ts.Variables.port + self.origin_port = self.server.Variables.Port + self.run_dir = self.Test.RunDirectory + self.localhost = f"127.0.0.1:{self.ats_port}" + + self.started = False + + # Default response header template + self.default_response_header = { + "headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + } + + def enable_diagnostics(self, tags="http_hdrs"): + """ + Configure debug logging for the ATS process. + """ + self.ts.Disk.records_config.update( + { + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.show_location': 0, + 'proxy.config.diags.debug.tags': tags, + }) + + def add_server_responses(self, responses, log_file="sessionfile.log"): + """ + Add responses to the origin server for the given request/response pairs. + """ + for req, resp in responses: + if resp is None: + resp = self.default_response_header + self.server.addResponse(log_file, req, resp) + + def add_remap_rules(self, remap_rules, disable_tls=True): + """ + Add remap rules to the ATS configuration. + + This method processes a list of remap rule dictionaries and adds them to the + remap.config file. Each rule can have associated plugins with parameters. + """ + for rule in remap_rules: + plugin_args = self._build_plugin_args(rule["plugins"]) + + self.ts.Disk.remap_config.AddLine(f'map http://{rule["from"]} http://{rule["to"]} {plugin_args}') + if not disable_tls: + self.ts.Disk.remap_config.AddLine(f'map https://{rule["from"]} http://{rule["to"]} {plugin_args}') + + def _build_plugin_args(self, plugins): + """ + Build plugin arguments string from plugins list. + """ + if not plugins: + return "" + + return " ".join(f'@plugin={plugin}.so ' + " ".join(f'@pparam={p}' for p in params) for plugin, params in plugins) + + def execute_tests(self, test_runs): + """ + Execute all configured test runs. + """ + for test in test_runs: + if not 'desc' in test: + raise ValueError("Test run must include 'desc' key") + tr = self.Test.AddTestRun(test["desc"]) + + # Start processes before the first test + if not self.started: + tr.Processes.Default.StartBefore(self.server, ready=self.When.PortOpen(self.origin_port)) + tr.Processes.Default.StartBefore(self.ts) + self.started = True + + if curl := test.get("curl"): + tr.MakeCurlCommand(curl, ts=self.ts) + elif multi := test.get("multi_curl"): + tr.MakeCurlCommandMulti(multi, ts=self.ts) + + if gold := test.get("gold"): + tr.Processes.Default.Streams.stderr = gold + + tr.StillRunningAfter = self.server + + def set_traffic_out_content(self, content_file): + """ + Set the traffic.out content file for debugging. + + Args: + content_file (str): Path to the content file + """ + self.ts.Disk.traffic_out.Content = content_file + + def copy_files(self, source, pattern, destination_dir=None): + """ + Copy files using either glob pattern matching or explicit file list. + + This method supports two modes: + 1. Pattern matching: When source is a string directory path, it finds all files + matching the glob pattern and copies them to the destination. + 2. Explicit file list: When source is a list of file paths, it copies each + file directly (pattern parameter is ignored in this case). + """ + if destination_dir is None: + destination_dir = self.run_dir + + if isinstance(source, list): + for file_path in source: + self.ts.Setup.CopyAs(file_path, destination_dir) + elif pattern is not None: + for file_path in glob.glob(os.path.join(self.Test.TestDirectory, source, pattern)): + relative_path = os.path.relpath(file_path, self.Test.TestDirectory) + self.ts.Setup.CopyAs(relative_path, destination_dir) + else: + raise ValueError("Either 'source' must be a list of files or 'pattern' must be provided with a source directory.") diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite-client.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/client-url.gold similarity index 100% rename from tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite-client.gold rename to tests/gold_tests/pluginTest/header_rewrite/gold/client-url.gold diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/cond-elif.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/cond-elif.gold index 47d536e76a2..cb9d993ccf7 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/gold/cond-elif.gold +++ b/tests/gold_tests/pluginTest/header_rewrite/gold/cond-elif.gold @@ -1,5 +1,5 @@ `` -> GET ``/from_path/hrw-sets.png`` +> GET http://www.example.com/from_1/hrw-sets.png`` > Host: www.example.com`` > User-Agent: curl/`` `` diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_cond_cache.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/cond_cache.gold similarity index 59% rename from tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_cond_cache.gold rename to tests/gold_tests/pluginTest/header_rewrite/gold/cond_cache.gold index 34836be3a5a..691e868bb4c 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_cond_cache.gold +++ b/tests/gold_tests/pluginTest/header_rewrite/gold/cond_cache.gold @@ -1,25 +1,11 @@ `` -> GET / HTTP/1.1 +> GET /from_5/ HTTP/1.1 > Host: www.example.com > User-Agent: curl/`` > Accept: */* `` < HTTP/1.1 200 OK -< Cache-Control: max-age=10,public -< Content-Length: 6 -< Date: `` -< Age: `` -< Connection: keep-alive -< Server: ATS/{} -< Cache-Result: miss -`` -> GET / HTTP/1.1 -> Host: www.example.com -> User-Agent: curl/`` -> Accept: */* -`` -< HTTP/1.1 200 OK -< Cache-Control: max-age=10,public +< Cache-Control: max-age=5,public < Content-Length: 6 < Date: `` < Age: `` @@ -27,13 +13,13 @@ < Server: ATS/{} < Cache-Result: hit-fresh `` -> GET / HTTP/1.1 +> GET /from_5/ HTTP/1.1 > Host: www.example.com > User-Agent: curl/`` > Accept: */* `` < HTTP/1.1 200 OK -< Cache-Control: max-age=10,public +< Cache-Control: max-age=5,public < Content-Length: 6 < Date: `` < Age: `` @@ -41,13 +27,13 @@ < Server: ATS/{} < Cache-Result: hit-stale `` -> GET / HTTP/1.1 +> GET /from_5/ HTTP/1.1 > Host: www.example.com > User-Agent: curl/`` > Accept: */* `` < HTTP/1.1 200 OK -< Cache-Control: max-age=10,public +< Cache-Control: max-age=5,public < Content-Length: 6 < Date: `` < Age: `` diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/cond_cache_first.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/cond_cache_first.gold new file mode 100644 index 00000000000..d2187d01b33 --- /dev/null +++ b/tests/gold_tests/pluginTest/header_rewrite/gold/cond_cache_first.gold @@ -0,0 +1,15 @@ +`` +> GET /from_5/ HTTP/1.1 +> Host: www.example.com +> User-Agent: curl/`` +> Accept: */* +`` +< HTTP/1.1 200 OK +< Cache-Control: max-age=5,public +< Content-Length: 6 +< Date: `` +< Age: `` +< Connection: keep-alive +< Server: ATS/{} +< Cache-Result: miss +`` diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_cond_method.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/cond_method.gold similarity index 100% rename from tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_cond_method.gold rename to tests/gold_tests/pluginTest/header_rewrite/gold/cond_method.gold diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_cond_ssn_txn_count.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/cond_ssn_txn_count.gold similarity index 86% rename from tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_cond_ssn_txn_count.gold rename to tests/gold_tests/pluginTest/header_rewrite/gold/cond_ssn_txn_count.gold index 482d736e137..23997b81cb1 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite_cond_ssn_txn_count.gold +++ b/tests/gold_tests/pluginTest/header_rewrite/gold/cond_ssn_txn_count.gold @@ -1,5 +1,5 @@ `` -> GET /hello HTTP/1.1 +> GET /from_4/hello HTTP/1.1 > Host: www.example.com > User-Agent: curl/`` > Accept: */* @@ -13,7 +13,7 @@ < Connection: keep-alive < `` -> GET /hello HTTP/1.1 +> GET /from_4/hello HTTP/1.1 > Host: www.example.com > User-Agent: curl/`` > Accept: */* @@ -27,7 +27,7 @@ < Connection: keep-alive < `` -> GET /hello HTTP/1.1 +> GET /from_4/hello HTTP/1.1 > Host: www.example.com > User-Agent: curl/`` > Accept: */* @@ -41,7 +41,7 @@ < Connection: keep-alive < `` -> GET /hello HTTP/1.1 +> GET /from_4/hello HTTP/1.1 > Host: www.example.com > User-Agent: curl/`` > Accept: */* @@ -55,7 +55,7 @@ < Connection: close < `` -> GET /world HTTP/1.1 +> GET /from_4/world HTTP/1.1 > Host: www.example.com > User-Agent: curl/`` > Accept: */* @@ -68,4 +68,4 @@ < Age: `` < Connection: close < -`` \ No newline at end of file +`` diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/ext-sets.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/ext-sets.gold index 24bcc106a6a..b3072467056 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/gold/ext-sets.gold +++ b/tests/gold_tests/pluginTest/header_rewrite/gold/ext-sets.gold @@ -1,5 +1,5 @@ `` -> GET ``/from_path/hrw-sets.png`` +> GET http://www.example.com/from_1/hrw-sets.png`` > Host: www.example.com`` > User-Agent: curl/`` `` diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite-502.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite-502.gold deleted file mode 100644 index 27ca4f0d608..00000000000 --- a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite-502.gold +++ /dev/null @@ -1,5 +0,0 @@ -`` -> GET ``503`` -`` -< ``502`` -`` diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite-l_value.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/l_value.gold similarity index 100% rename from tests/gold_tests/pluginTest/header_rewrite/gold/header_rewrite-l_value.gold rename to tests/gold_tests/pluginTest/header_rewrite/gold/l_value.gold diff --git a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite.test.py b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite.test.py deleted file mode 100644 index b8c6477ca09..00000000000 --- a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite.test.py +++ /dev/null @@ -1,95 +0,0 @@ -''' -''' -# 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. - -import os - -Test.Summary = ''' -Test a basic remap of a http connection -''' - -Test.ContinueOnFail = True -# Define default ATS -ts = Test.MakeATSProcess("ts") -server = Test.MakeOriginServer("server") - -Test.testName = "" -request_header = {"headers": "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""} -response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""} -server.addResponse("sessionfile.log", request_header, response_header) - -request_header = {"headers": "GET /503 HTTP/1.1\r\nHost: www.example.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""} -response_header = { - "headers": "HTTP/1.1 503 Service Unavailable\r\nConnection: close\r\n\r\n", - "timestamp": "1469733493.993", - "body": "" -} -server.addResponse("sessionfile.log", request_header, response_header) - -ts.Disk.records_config.update( - { - 'proxy.config.diags.debug.enabled': 1, - 'proxy.config.diags.show_location': 0, - 'proxy.config.diags.debug.tags': 'header|http', - }) -# The following rule changes the status code returned from origin server to 303 -ts.Setup.CopyAs('rules/rule.conf', Test.RunDirectory) -ts.Disk.plugin_config.AddLine('header_rewrite.so {0}/rule.conf'.format(Test.RunDirectory)) -ts.Disk.remap_config.AddLine('map http://www.example.com http://127.0.0.1:{0}'.format(server.Variables.Port)) -ts.Disk.remap_config.AddLine('map http://www.example.com:8080 http://127.0.0.1:{0}'.format(server.Variables.Port)) - -# Add logging configuration to test the new plugin tag field -ts.Disk.logging_yaml.AddLines( - ''' -logging: - formats: - - name: plugin_status - format: '% % % %' - logs: - - filename: plugin-status-test - format: plugin_status -'''.split("\n")) - -plugin_status_log = os.path.join(ts.Variables.LOGDIR, 'plugin-status-test.log') -ts.Disk.File(plugin_status_log, exists=True, content='gold/plugin-status-test.gold') - -# call localhost straight -tr = Test.AddTestRun("Header Rewrite 200 to 303") -tr.MakeCurlCommand( - '--proxy 127.0.0.1:{0} "http://www.example.com" -H "Proxy-Connection: keep-alive" --verbose'.format(ts.Variables.port), ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.StartBefore(server, ready=When.PortOpen(server.Variables.Port)) -tr.Processes.Default.StartBefore(Test.Processes.ts) -tr.Processes.Default.Streams.stderr = "gold/header_rewrite-303.gold" -tr.StillRunningAfter = server - -tr = Test.AddTestRun("Header Rewrite 503 to 502") -tr.MakeCurlCommand( - '--proxy 127.0.0.1:{0} "http://www.example.com/503" -H "Proxy-Connection: keep-alive" --verbose'.format(ts.Variables.port), - ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.Streams.stderr = "gold/header_rewrite-502.gold" -tr.StillRunningAfter = server - -ts.Disk.traffic_out.Content = "gold/header_rewrite-tag.gold" - -# Verify the plugin status log file contains the expected plugin tag - -# Wait for log file to appear, then wait one extra second to make sure TS is done writing it. -tr = Test.AddTestRun() -tr.Processes.Default.Command = (os.path.join(Test.Variables.AtsTestToolsDir, 'condwait') + f' 60 1 -f {plugin_status_log}') -tr.Processes.Default.ReturnCode = 0 diff --git a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_bundle.test.py b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_bundle.test.py new file mode 100644 index 00000000000..e5528762e67 --- /dev/null +++ b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_bundle.test.py @@ -0,0 +1,246 @@ +''' +Test header_rewrite with URL conditions and operators. +''' +# 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. + +import ats_autest + +Test.Summary = ''' +A set of remap rules and tests for header_rewrite. +''' +Test.ContinueOnFail = True + +# Setup ATS and origin, define some convenience variables +mgr = ats_autest.ATSTestManager(Test, When) + +# Common debug logging config +mgr.enable_diagnostics(tags="header_rewrite") +mgr.ts.Disk.records_config.update( + { + 'proxy.config.http.insert_response_via_str': 0, + 'proxy.config.http.auth_server_session_private': 1, + 'proxy.config.http.server_session_sharing.pool': 'global', + 'proxy.config.http.server_session_sharing.match': 'both' + }) + +# mgr.ts.Disk.traffic_out.Content = "gold/header_rewrite-tag.gold" + +############################################################################# +# Setup all the remap rules +# +url_base = "www.example.com/from" +origin_base = f'127.0.0.1:{mgr.origin_port}/to' + +remap_rules = [ + { + "from": "no_path.com/", + "to": "no_path.com?name=brian/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/set_redirect.conf"])] + }, { + "from": f"{url_base}_1/", + "to": f"{origin_base}_1/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/rule_client.conf"])] + }, { + "from": f"{url_base}_2/", + "to": f"{origin_base}_2/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/rule_cond_method.conf"])] + }, { + "from": f"{url_base}_3/", + "to": f"{origin_base}_3/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/rule_l_value.conf"])] + }, { + "from": f"{url_base}_4/", + "to": f"{origin_base}_4/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/rule_set_header_after_ssn_txn_count.conf"])] + }, { + "from": f"{url_base}_5/", + "to": f"{origin_base}_5/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/rule_add_cache_result_header.conf"])] + }, { + "from": f"{url_base}_6/", + "to": f"{origin_base}_6/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/rule_effective_address.conf"])] + }, { + "from": f"{url_base}_7/", + "to": f"{origin_base}_7/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/rule.conf"])] + } +] + +mgr.copy_files('rules/', pattern='*.conf') +mgr.add_remap_rules(remap_rules) + +############################################################################# +# Setup the origin server rquest/response pairs +# +def_resp = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""} +origin_rules = [ + ({ + "headers": "GET / HTTP/1.1\r\nHost: no_path.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "", + }, def_resp), + ( + { + "headers": "GET /to_1/hello?=foo=bar HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "", + }, def_resp), + ( + { + "headers": "GET /to_1/hrw-sets.png HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }, def_resp), + ({ + "headers": "GET /to_2/ HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }, def_resp), + ({ + "headers": "GET /to_3/ HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }, def_resp), + ( + { + "headers": "GET /to_4/hello HTTP/1.1\r\nHost: www.example.com\r\nContent-Length: 0\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }, { + "headers": "HTTP/1.1 200 OK\r\nServer: microserver\r\n" + "Content-Length: 0\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }), + ( + { + "headers": "GET /to_4/world HTTP/1.1\r\nContent-Length: 0\r\n" + "Host: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "a\r\na\r\na\r\n\r\n" + }, { + "headers": "HTTP/1.1 200 OK\r\nServer: microserver\r\n" + "Connection: close\r\nContent-Length: 0\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }), + ( + { + "headers": "GET /to_5/ HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }, { + "headers": "HTTP/1.1 200 OK\r\nConnection: close\r\nCache-Control: max-age=5,public\r\n\r\n", + "timestamp": "1469733493.993", + "body": "CACHED" + }), + ({ + "headers": "GET /to_6/ HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }, def_resp), + ({ + "headers": "GET /to_7/ HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }, def_resp), +] +mgr.add_server_responses(origin_rules) + +# Create all the test cases +curl_proxy = f'--proxy {mgr.localhost} --verbose' +expected_log = "gold/header_rewrite-tag.gold" + +test_runs = [ + { + "desc": "Setup cache hit for tests later (cache hit /miss)", + "curl": f'-s -v -H "{mgr.host_example}" {mgr.localhost}/from_5/', + "gold": "gold/cond_cache_first.gold", + }, + { + "desc": "TO-URL redirect test", + "curl": f'--head http://{mgr.localhost} -H "Host: no_path.com" --verbose', + "gold": "gold/set-redirect.gold", + }, + { + "desc": "CLIENT-URL test", + "curl": f'{curl_proxy} "http://{url_base}_1/hello?=foo=bar"', + "gold": "gold/client-url.gold", + }, + { + "desc": "sets matching", + "curl": f'{curl_proxy} "http://{url_base}_1/hrw-sets.png" -H "X-Testing: foo,bar"', + "gold": "gold/ext-sets.gold", + }, + { + "desc": "elif condition", + "curl": f'{curl_proxy} "http://{url_base}_1/hrw-sets.png" -H "X-Testing: elif"', + "gold": "gold/cond-elif.gold", + }, + { + "desc": "cond method GET", + "curl": f'{curl_proxy} "http://{url_base}_2/"', + "gold": "gold/cond_method.gold", + }, + { + "desc": "cond method DELETE", + "curl": f'--request DELETE {curl_proxy} "http://{url_base}_2/"', + "gold": "gold/cond_method.gold", + }, + { + "desc": "End [L] #5423", + "curl": f'{curl_proxy} "http://{url_base}_3/"', + "gold": "gold/l_value.gold", + }, + { + "desc": "SSN-TXN-COUNT condition", + + # Force last one with close connection header, this is also reflected in the response ^. + # if I do not do this, then the microserver will fail to close and when shutting down the process will + # fail with -9. + "multi_curl": + ( + f'{{curl}} -v -H "{mgr.host_example}" -H "{mgr.conn_keepalive}" {mgr.localhost}/from_4/hello &&' + f'{{curl}} -v -H "{mgr.host_example}" -H "{mgr.conn_keepalive}" {mgr.localhost}/from_4/hello &&' + f'{{curl}} -v -H "{mgr.host_example}" -H "{mgr.conn_keepalive}" {mgr.localhost}/from_4/hello &&' + f'{{curl}} -v -H "{mgr.host_example}" -H "{mgr.conn_keepalive}" {mgr.localhost}/from_4/hello &&' + f'{{curl}} -v -H "{mgr.host_example}" -H "Connection: close" {mgr.localhost}/from_4/world'), + "gold": "gold/cond_ssn_txn_count.gold" + }, + { + "desc": "Cache condition test - miss, hit-fresh, hit-stale, hit-fresh", + "multi_curl": + ( + f'{{curl}} -s -v -H "{mgr.host_example}" {mgr.localhost}/from_5/ && ' + f'sleep 8 && {{curl}} -s -v -H "{mgr.host_example}" {mgr.localhost}/from_5/ && ' + f'{{curl}} -s -v -H "{mgr.host_example}" {mgr.localhost}/from_5/'), + "gold": "gold/cond_cache.gold", + }, + { + "desc": "Effective address test", + "curl": f'{curl_proxy} "http://{url_base}_6/" -H "Real-IP: 1.2.3.4"', + "gold": "gold/header_rewrite_effective_address.gold", + }, + { + "desc": "Status change test (200 to 303)", + "curl": f'{curl_proxy} "http://{url_base}_7/" -H "Proxy-Connection: keep-alive"', + "gold": "gold/header_rewrite-303.gold", + }, +] + +mgr.execute_tests(test_runs) diff --git a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_cache.test.py b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_cache.test.py deleted file mode 100644 index 28d29b3a567..00000000000 --- a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_cache.test.py +++ /dev/null @@ -1,67 +0,0 @@ -''' -Test cache lookup results in CACHE condition -''' -# 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.ContinueOnFail = True -ts = Test.MakeATSProcess("ts") -server = Test.MakeOriginServer("server") - -Test.testName = "CACHE" - -# Request from client -request_header = {"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_header = { - "headers": "HTTP/1.1 200 OK\r\nConnection: close\r\nCache-Control: max-age=10,public\r\n\r\n", - "timestamp": "1469733493.993", - "body": "CACHED" -} - -# add request/response -server.addResponse("sessionlog.log", request_header, response_header) -ts.Disk.records_config.update({ - 'proxy.config.diags.debug.enabled': 1, - 'proxy.config.diags.debug.tags': 'http', -}) - -# This rule adds the cache header with results of the cache lookup results -# (ie. "hit-fresh", "hit-stale", "miss", "none") -ts.Setup.CopyAs('rules/rule_add_cache_result_header.conf', Test.RunDirectory) - -ts.Disk.plugin_config.AddLine('header_rewrite.so {0}/rule_add_cache_result_header.conf'.format(Test.RunDirectory)) -ts.Disk.remap_config.AddLine('map http://www.example.com http://127.0.0.1:{0}'.format(server.Variables.Port)) -ts.Disk.remap_config.AddLine('map / http://127.0.0.1:{0}'.format(server.Variables.Port)) - -# Commands to get the following response headers -# 1. miss (empty cache) -# 2. hit-fresh (content served within 10s cache) -# 3. hit-stale (waited 15s, after 10s cache) -# 2. hit-fresh (content served within 10s cache) -curlRequest = ( - '{{curl}} -s -v -H "Host: www.example.com" http://127.0.0.1:{0};' - '{{curl}} -v -H "Host: www.example.com" http://127.0.0.1:{0};' - 'sleep 15; {{curl}} -s -v -H "Host: www.example.com" http://127.0.0.1:{0};' - '{{curl}} -s -v -H "Host: www.example.com" http://127.0.0.1:{0}') - -# Test Case -tr = Test.AddTestRun() -tr.MakeCurlCommandMulti(curlRequest.format(ts.Variables.port), ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.StartBefore(server) -tr.Processes.Default.StartBefore(ts) -tr.Processes.Default.Streams.stderr = "gold/header_rewrite_cond_cache.gold" -tr.StillRunningAfter = server diff --git a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_method.test.py b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_method.test.py deleted file mode 100644 index a3e3babce23..00000000000 --- a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_method.test.py +++ /dev/null @@ -1,73 +0,0 @@ -''' -''' -# 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 with METHOD conditions and operators. -''' - -Test.ContinueOnFail = True -# Define default ATS -ts = Test.MakeATSProcess("ts") -server = Test.MakeOriginServer("server") - -Test.testName = "header_rewrite_method_condition" -request_get = {"headers": "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""} -request_delete = {"headers": "DELETE / 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) -server.addResponse(session_file, request_delete, response) -ts.Disk.records_config.update( - { - 'proxy.config.diags.debug.enabled': 1, - 'proxy.config.diags.show_location': 0, - 'proxy.config.diags.debug.tags': 'header.*', - 'proxy.config.http.insert_response_via_str': 0, - }) -# The following rule inserts a via header if the request method is a GET or DELETE -conf_name = "rule_cond_method.conf" -ts.Setup.CopyAs('rules/{0}'.format(conf_name), Test.RunDirectory) -ts.Disk.plugin_config.AddLine('header_rewrite.so {0}/{1}'.format(Test.RunDirectory, conf_name)) -ts.Disk.remap_config.AddLine('map http://www.example.com http://127.0.0.1:{0}'.format(server.Variables.Port)) - -# Test method in READ_REQUEST_HDR_HOOK. -expected_output = "gold/header_rewrite_cond_method.gold" -expected_log = "gold/header_rewrite-tag.gold" -tr = Test.AddTestRun() -tr.MakeCurlCommand( - '--proxy 127.0.0.1:{0} "http://www.example.com" -H "Proxy-Connection: keep-alive" --verbose'.format(ts.Variables.port), ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.StartBefore(server, ready=When.PortOpen(server.Variables.Port)) -tr.Processes.Default.StartBefore(Test.Processes.ts) -tr.Processes.Default.Streams.stderr = expected_output -tr.StillRunningAfter = server -ts.Disk.traffic_out.Content = expected_log - -# Test method in SEND_REQUEST_HDR_HOOK. -tr = Test.AddTestRun() -tr.MakeCurlCommand( - '--request DELETE --proxy 127.0.0.1:{0} "http://www.example.com" -H "Proxy-Connection: keep-alive" --verbose'.format( - ts.Variables.port), - ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.Streams.stderr = expected_output -tr.StillRunningAfter = server -ts.Disk.traffic_out.Content = expected_log diff --git a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_ssn_txn_count.test.py b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_ssn_txn_count.test.py deleted file mode 100644 index 363ae29796a..00000000000 --- a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_cond_ssn_txn_count.test.py +++ /dev/null @@ -1,101 +0,0 @@ -''' -Test adding a close connection header when SSN-TXN-COUNT reach a limit -''' -# 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. - -ts = Test.MakeATSProcess("ts") -server = Test.MakeOriginServer("server") - -Test.testName = "SSN-TXN-COUNT" - -# Test SSN-TXN-COUNT condition. -request_header_hello = { - "headers": "GET /hello HTTP/1.1\r\nHost: www.example.com\r\nContent-Length: 0\r\n\r\n", - "timestamp": "1469733493.993", - "body": "" -} -response_header_hello = { - "headers": "HTTP/1.1 200 OK\r\nServer: microserver\r\n" - "Content-Length: 0\r\n\r\n", - "timestamp": "1469733493.993", - "body": "" -} - -request_header_world = { - "headers": "GET /world HTTP/1.1\r\nContent-Length: 0\r\n" - "Host: www.example.com\r\n\r\n", - "timestamp": "1469733493.993", - "body": "a\r\na\r\na\r\n\r\n" -} -response_header_world = { - "headers": "HTTP/1.1 200 OK\r\nServer: microserver\r\n" - "Connection: close\r\nContent-Length: 0\r\n\r\n", - "timestamp": "1469733493.993", - "body": "" -} - -# add request/response -server.addResponse("sessionlog.log", request_header_hello, response_header_hello) -server.addResponse("sessionlog.log", request_header_world, response_header_world) - -ts.Disk.records_config.update( - { - 'proxy.config.diags.debug.enabled': 1, - 'proxy.config.diags.debug.tags': 'header.*', - 'proxy.config.http.auth_server_session_private': 1, - 'proxy.config.http.server_session_sharing.pool': 'global', - 'proxy.config.http.server_session_sharing.match': 'both', - }) - -# In case we need this in the future, just remove the comments. -# ts.Disk.logging_yaml.AddLines( -# ''' -# logging: -# formats: -# - name: long -# format: "SSTC:%" -# logs: -# - filename: rewrite.log.txt -# format: long -# '''.split("\n") -# ) - -# This rule adds the connection header to close it after the number of transactions from a single -# session is > 2. This test the new SSN-TXN-COUNT condition. -ts.Setup.CopyAs('rules/rule_set_header_after_ssn_txn_count.conf', Test.RunDirectory) - -ts.Disk.remap_config.AddLine( - 'map / http://127.0.0.1:{0} @plugin=header_rewrite.so @pparam={1}/rule_set_header_after_ssn_txn_count.conf'.format( - server.Variables.Port, Test.RunDirectory)) - -curlRequest = ( - '{{curl}} -v -H\'Host: www.example.com\' -H\'Connection: keep-alive\' http://127.0.0.1:{0}/hello &&' - '{{curl}} -v -H\'Host: www.example.com\' -H\'Connection: keep-alive\' http://127.0.0.1:{0}/hello &&' - '{{curl}} -v -H\'Host: www.example.com\' -H\'Connection: keep-alive\' http://127.0.0.1:{0}/hello &&' - '{{curl}} -v -H\'Host: www.example.com\' -H\'Connection: keep-alive\' http://127.0.0.1:{0}/hello &&' - # I have to force last one with close connection header, this is also reflected in the response ^. - # if I do not do this, then the microserver will fail to close and when shutting down the process will - # fail with -9. - '{{curl}} -v -H\'Host: www.example.com\' -H\'Connection: close\' http://127.0.0.1:{0}/world') - -tr = Test.AddTestRun("Add connection close header when ssn-txn-count > 2") -tr.MakeCurlCommandMulti(curlRequest.format(ts.Variables.port), ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.StartBefore(server) -tr.Processes.Default.StartBefore(ts) -tr.Processes.Default.Streams.stderr = "gold/header_rewrite_cond_ssn_txn_count.gold" -tr.StillRunningAfter = server 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 deleted file mode 100644 index 47aa54002d7..00000000000 --- a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_effective_address.test.py +++ /dev/null @@ -1,56 +0,0 @@ -''' -''' -# 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/header_rewrite_l_value.test.py b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_l_value.test.py deleted file mode 100644 index 5c04f72570f..00000000000 --- a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_l_value.test.py +++ /dev/null @@ -1,60 +0,0 @@ -''' -''' -# 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 for a regression of the issue fixed in -https://github.com/apache/trafficserver/pull/5423 -Insertion of header rewrite directives in to the output -''' - -Test.ContinueOnFail = True -# Define default ATS -ts = Test.MakeATSProcess("ts") -server = Test.MakeOriginServer("server") - -Test.testName = "" -request_header = {"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_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""} - -# add response to the server dictionary -server.addResponse("sessionfile.log", request_header, response_header) -ts.Disk.records_config.update( - { - 'proxy.config.diags.debug.enabled': 1, - 'proxy.config.diags.show_location': 0, - 'proxy.config.diags.debug.tags': 'header.*', - }) - -# The following rule adds X-First and X-Last headers -ts.Setup.CopyAs('rules/rule_l_value.conf', Test.RunDirectory) - -ts.Disk.plugin_config.AddLine('header_rewrite.so {0}/rule_l_value.conf'.format(Test.RunDirectory)) -ts.Disk.remap_config.AddLine('map http://www.example.com http://127.0.0.1:{0}'.format(server.Variables.Port)) -ts.Disk.remap_config.AddLine('map http://www.example.com:8080 http://127.0.0.1:{0}'.format(server.Variables.Port)) - -# [L] test -tr = Test.AddTestRun("Header Rewrite End [L]") -tr.MakeCurlCommand( - '--proxy 127.0.0.1:{0} "http://www.example.com" -H "Proxy-Connection: keep-alive" --verbose'.format(ts.Variables.port), ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.StartBefore(server, ready=When.PortOpen(server.Variables.Port)) -tr.Processes.Default.StartBefore(Test.Processes.ts) -tr.Processes.Default.Streams.stderr = "gold/header_rewrite-l_value.gold" -tr.StillRunningAfter = server -ts.Disk.traffic_out.Content = "gold/header_rewrite-tag.gold" diff --git a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_url.test.py b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_url.test.py deleted file mode 100644 index b4bbf900cb1..00000000000 --- a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_url.test.py +++ /dev/null @@ -1,112 +0,0 @@ -''' -Test header_rewrite with URL conditions and operators. -''' -# 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 with URL conditions and operators. -''' - -Test.ContinueOnFail = True -ts = Test.MakeATSProcess("ts") -server = Test.MakeOriginServer("server") - -# Configure the server to return 200 responses. The rewrite rules below set a -# non-200 status, so if curl gets a 200 response something went wrong. -Test.testName = "" -response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""} -request_header = { - "headers": "GET /to_path/hello?=foo=bar HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - "timestamp": "1469733493.993", - "body": "" -} -server.addResponse("sessionfile.log", request_header, response_header) -request_header = { - "headers": "GET /to_path/hrw-sets.png HTTP/1.1\r\nHost: www.example.com\r\n\r\n", - "timestamp": "1469733493.993", - "body": "" -} -server.addResponse("sessionfile.log", request_header, response_header) -request_header = {"headers": "GET / HTTP/1.1\r\nHost: no_path.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""} -server.addResponse("sessionfile.log", request_header, response_header) - -ts.Disk.records_config.update( - { - 'proxy.config.diags.debug.enabled': 1, - 'proxy.config.diags.show_location': 0, - 'proxy.config.diags.debug.tags': 'header.*', - }) -# The following rule changes the status code returned from origin server to 303 -ts.Setup.CopyAs('rules/rule_client.conf', Test.RunDirectory) -ts.Setup.CopyAs('rules/set_redirect.conf', Test.RunDirectory) - -# This configuration makes use of CLIENT-URL in conditions. -ts.Disk.remap_config.AddLine( - 'map http://www.example.com/from_path/ http://127.0.0.1:{0}/to_path/ ' - '@plugin=header_rewrite.so @pparam={1}/rule_client.conf'.format(server.Variables.Port, Test.RunDirectory)) -ts.Disk.remap_config.AddLine( - 'map http://www.example.com:8080/from_path/ http://127.0.0.1:{0}/to_path/ ' - '@plugin=header_rewrite.so @pparam={1}/rule_client.conf'.format(server.Variables.Port, Test.RunDirectory)) -# This configuration makes use of TO-URL in a set-redirect operator. -ts.Disk.remap_config.AddLine( - 'map http://no_path.com http://no_path.com?name=brian/ ' - '@plugin=header_rewrite.so @pparam={0}/set_redirect.conf'.format(Test.RunDirectory)) - -# Test CLIENT-URL. -tr = Test.AddTestRun() -tr.MakeCurlCommand( - '--proxy 127.0.0.1:{0} "http://www.example.com/from_path/hello?=foo=bar" ' - '-H "Proxy-Connection: keep-alive" --verbose'.format(ts.Variables.port), - ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.StartBefore(server, ready=When.PortOpen(server.Variables.Port)) -tr.Processes.Default.StartBefore(Test.Processes.ts) -tr.Processes.Default.Streams.stderr = "gold/header_rewrite-client.gold" -tr.StillRunningAfter = server -ts.Disk.traffic_out.Content = "gold/header_rewrite-tag.gold" - -# Test TO-URL in a set-redirect operator. -tr = Test.AddTestRun() -tr.MakeCurlCommand('--head 127.0.0.1:{0} -H "Host: no_path.com" --verbose'.format(ts.Variables.port), ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.Streams.stderr = "gold/set-redirect.gold" -tr.StillRunningAfter = server -ts.Disk.traffic_out.Content = "gold/header_rewrite-tag.gold" - -# Test HRW sets matching -tr = Test.AddTestRun() -tr.MakeCurlCommand( - '--proxy 127.0.0.1:{0} "http://www.example.com/from_path/hrw-sets.png" ' - '-H "Proxy-Connection: keep-alive" -H "X-Testing: foo,bar" ' - '--verbose'.format(ts.Variables.port), - ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.Streams.stderr = "gold/ext-sets.gold" -tr.StillRunningAfter = server -ts.Disk.traffic_out.Content = "gold/header_rewrite-tag.gold" - -# Test HRW elif -tr = Test.AddTestRun() -tr.MakeCurlCommand( - '--proxy 127.0.0.1:{0} "http://www.example.com/from_path/hrw-sets.png" ' - '-H "Proxy-Connection: keep-alive" -H "X-Testing: elif" ' - '--verbose'.format(ts.Variables.port), - ts=ts) -tr.Processes.Default.ReturnCode = 0 -tr.Processes.Default.Streams.stderr = "gold/cond-elif.gold" -tr.StillRunningAfter = server -ts.Disk.traffic_out.Content = "gold/header_rewrite-tag.gold" diff --git a/tests/gold_tests/pluginTest/header_rewrite/rules/rule.conf b/tests/gold_tests/pluginTest/header_rewrite/rules/rule.conf index 982ef6a4fa9..3a472618f9d 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/rules/rule.conf +++ b/tests/gold_tests/pluginTest/header_rewrite/rules/rule.conf @@ -15,6 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +cond %{READ_RESPONSE_HDR_HOOK} [AND] cond %{STATUS} =200 set-status 303 elif diff --git a/tests/gold_tests/pluginTest/header_rewrite/rules/rule_client.conf b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_client.conf index 6d38d810597..e298a8bed1c 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/rules/rule_client.conf +++ b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_client.conf @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cond %{CLIENT-URL:PATH} /^from_path/ +cond %{CLIENT-URL:PATH} /^from_1\// cond %{CLIENT-URL:SCHEME} =http cond %{CLIENT-URL:HOST} =www.example.com cond %{CLIENT-URL:QUERY} /foo=bar/ diff --git a/tests/gold_tests/pluginTest/header_rewrite/rules/rule_cond_method.conf b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_cond_method.conf index 0b600f45605..a244509bd0b 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/rules/rule_cond_method.conf +++ b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_cond_method.conf @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -cond %{READ_REQUEST_HDR_HOOK} +cond %{REMAP_PSEUDO_HOOK} cond %{METHOD} (GET,PUSH) set-config proxy.config.http.insert_response_via_str 1 [L] 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 index 143a2c3b43d..f7c84b18a5c 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/rules/rule_effective_address.conf +++ b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_effective_address.conf @@ -15,9 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -cond %{READ_REQUEST_HDR_HOOK} +cond %{REMAP_PSEUDO_HOOK} set-effective-address %{HEADER:Real-IP} cond %{SEND_RESPONSE_HDR_HOOK} set-header Effective-IP %{INBOUND:REMOTE-ADDR} - diff --git a/tests/gold_tests/pluginTest/header_rewrite/rules/rule_l_value.conf b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_l_value.conf index e80a8e4f7fa..82e530a7771 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/rules/rule_l_value.conf +++ b/tests/gold_tests/pluginTest/header_rewrite/rules/rule_l_value.conf @@ -19,3 +19,5 @@ cond %{SEND_RESPONSE_HDR_HOOK} set-header X-First "First" set-header X-Last "Last" [L] +cond %{SEND_RESPONSE_HDR_HOOK} + set-header X-Not-Here "Stop" From 18f10410bdbdfba548f36e95faa258fde2911c76 Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Fri, 10 Oct 2025 13:38:16 -0600 Subject: [PATCH 2/2] Added a few more tests around recent fixes --- .../gold/implicit_hook_fie.gold | 16 +++++++++ .../gold/implicit_hook_no_fie.gold | 15 ++++++++ .../gold/implicit_hook_prefix.gold | 16 +++++++++ .../header_rewrite_bundle.test.py | 26 +++++++++++++- .../header_rewrite/rules/implicit_hook.conf | 36 +++++++++++++++++++ 5 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_fie.gold create mode 100644 tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_no_fie.gold create mode 100644 tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_prefix.gold create mode 100644 tests/gold_tests/pluginTest/header_rewrite/rules/implicit_hook.conf diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_fie.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_fie.gold new file mode 100644 index 00000000000..523bc694cbf --- /dev/null +++ b/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_fie.gold @@ -0,0 +1,16 @@ +`` +> GET `` +> Host: www.example.com`` +> User-Agent: curl/`` +> Accept: */* +> Proxy-Connection: Keep-Alive +> X-Fie: Fie +`` +< HTTP/1.1 200 OK +< Date: `` +< Age: `` +< Transfer-Encoding: chunked +< Proxy-Connection: keep-alive +< Server: ATS/`` +< X-Response-Foo: Yes +`` diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_no_fie.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_no_fie.gold new file mode 100644 index 00000000000..4b3f6bba11f --- /dev/null +++ b/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_no_fie.gold @@ -0,0 +1,15 @@ +`` +> GET `` +> Host: www.example.com`` +> User-Agent: curl/`` +> Accept: */* +> Proxy-Connection: Keep-Alive +`` +< HTTP/1.1 200 OK +< Date: `` +< Age: `` +< Transfer-Encoding: chunked +< Proxy-Connection: keep-alive +< Server: ATS/`` +< X-Response-Foo: No +`` diff --git a/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_prefix.gold b/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_prefix.gold new file mode 100644 index 00000000000..4f7e6ea5886 --- /dev/null +++ b/tests/gold_tests/pluginTest/header_rewrite/gold/implicit_hook_prefix.gold @@ -0,0 +1,16 @@ +`` +> GET `` +> Host: www.example.com`` +> User-Agent: curl/`` +> Accept: */* +> Proxy-Connection: Keep-Alive +> X-Client-Foo: fOoBar +`` +< HTTP/1.1 200 OK +< Date: `` +< Age: `` +< Transfer-Encoding: chunked +< Proxy-Connection: keep-alive +< Server: ATS/`` +< X-Response-Foo: Prefix +`` diff --git a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_bundle.test.py b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_bundle.test.py index e5528762e67..4e7d0fbd499 100644 --- a/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_bundle.test.py +++ b/tests/gold_tests/pluginTest/header_rewrite/header_rewrite_bundle.test.py @@ -78,6 +78,10 @@ "from": f"{url_base}_7/", "to": f"{origin_base}_7/", "plugins": [("header_rewrite", [f"{mgr.run_dir}/rule.conf"])] + }, { + "from": f"{url_base}_8/", + "to": f"{origin_base}_8/", + "plugins": [("header_rewrite", [f"{mgr.run_dir}/implicit_hook.conf"])] } ] @@ -159,6 +163,11 @@ "timestamp": "1469733493.993", "body": "" }, def_resp), + ({ + "headers": "GET /to_8/ HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", + "body": "" + }, def_resp), ] mgr.add_server_responses(origin_rules) @@ -238,9 +247,24 @@ }, { "desc": "Status change test (200 to 303)", - "curl": f'{curl_proxy} "http://{url_base}_7/" -H "Proxy-Connection: keep-alive"', + "curl": f'{curl_proxy} "http://{url_base}_7/"', "gold": "gold/header_rewrite-303.gold", }, + { + "desc": "Implicit hook test - no X-Fie header (expect X-Response-Foo: No)", + "curl": f'{curl_proxy} "http://{url_base}_8/"', + "gold": "gold/implicit_hook_no_fie.gold", + }, + { + "desc": "Implicit hook test - X-Fie: Fie (expect X-Response-Foo: Yes)", + "curl": f'{curl_proxy} "http://{url_base}_8/" -H "X-Fie: Fie"', + "gold": "gold/implicit_hook_fie.gold", + }, + { + "desc": "Implicit hook test - X-Client-Foo: fOoBar (expect X-Response-Foo: Prefix)", + "curl": f'{curl_proxy} "http://{url_base}_8/" -H "X-Client-Foo: fOoBar"', + "gold": "gold/implicit_hook_prefix.gold", + }, ] mgr.execute_tests(test_runs) diff --git a/tests/gold_tests/pluginTest/header_rewrite/rules/implicit_hook.conf b/tests/gold_tests/pluginTest/header_rewrite/rules/implicit_hook.conf new file mode 100644 index 00000000000..0f909f1046c --- /dev/null +++ b/tests/gold_tests/pluginTest/header_rewrite/rules/implicit_hook.conf @@ -0,0 +1,36 @@ +# +# 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 %{SEND_RESPONSE_HDR_HOOK} [AND] +cond %{CLIENT-HEADER:X-Client-Foo} ="foo" [NOCASE,PRE] + set-header X-Response-Foo "Prefix" +elif + cond %{CLIENT-HEADER:X-Client-Foo} ="bar" + set-header X-Response-Foo "Never" +elif + cond %{CLIENT-HEADER:X-Client-Foo} ="" [NOT] + set-header X-Response-Foo "Yes" +else + set-header X-Response-Foo "No" + +# ToDo: This should use the implicit hook of %{REMAP_PSEUDO_HOOK}, needs #12557 +cond %{REMAP_PSEUDO_HOOK} [AND] +cond %{CLIENT-HEADER:X-Fie} ="fie" [NOCASE] + add-header X-Client-Foo "Yes" +elif + cond %{CLIENT-HEADER:X-Fie} ="nope" + add-header X-client-Foo "Yes"