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 76ffacca2c hrw4u: Check operators, add http header validation, url
validation (#12389)
76ffacca2c is described below
commit 76ffacca2c8dff322a50016ee9338018e4542acb
Author: Leif Hedstrom <[email protected]>
AuthorDate: Tue Jul 29 01:19:20 2025 +0200
hrw4u: Check operators, add http header validation, url validation (#12389)
---
tools/hrw4u/src/symbols.py | 22 +++++++++++-----------
tools/hrw4u/src/validation.py | 16 +++++++++++++++-
tools/hrw4u/tests/data/ops/bad_path.fail.error.txt | 3 +++
tools/hrw4u/tests/data/ops/bad_path.fail.input.txt | 3 +++
4 files changed, 32 insertions(+), 12 deletions(-)
diff --git a/tools/hrw4u/src/symbols.py b/tools/hrw4u/src/symbols.py
index a44d50d486..9ee2957ec9 100644
--- a/tools/hrw4u/src/symbols.py
+++ b/tools/hrw4u/src/symbols.py
@@ -29,19 +29,17 @@ class SymbolResolver:
"http.status.reason": ("set-status-reason",
Validator.quoted_or_simple(), False, None),
"http.status": ("set-status", Validator.range(0, 999), False, None),
"inbound.conn.dscp": ("set-conn-dscp", Validator.nbit_int(6), False,
None),
- "inbound.cookie.": (["rm-cookie", "set-cookie"],
Validator.quoted_or_simple(), False, None),
- "inbound.req.": (["rm-header", "set-header"],
Validator.quoted_or_simple(), False, None),
+ "inbound.cookie.": (["rm-cookie", "set-cookie"],
Validator.http_token(), False, None),
+ "inbound.req.": (["rm-header", "set-header"], Validator.http_token(),
False, None),
"inbound.resp.body": ("set-body", Validator.quoted_or_simple(), False,
None),
- "inbound.resp.": (["rm-header", "set-header"],
Validator.quoted_or_simple(), False, None),
+ "inbound.resp.": (["rm-header", "set-header"], Validator.http_token(),
False, None),
"inbound.status.reason": ("set-status-reason", Validator.range(0,
999), False, None),
"inbound.status": ("set-status", Validator.range(0, 999), False, None),
- "inbound.url.": (["rm-destination", "set-destination"],
Validator.quoted_or_simple(), True, None),
- "outbound.cookie.": (["rm-cookie", "set-cookie"],
Validator.quoted_or_simple(), False, None),
- "outbound.req.": (["rm-header", "set-header"],
Validator.quoted_or_simple(), False, {"PRE_REMAP", "REMAP", "READ_REQUEST"}),
+ "inbound.url.": (["rm-destination", "set-destination"],
Validator.suffix_group(types.SuffixGroup.URL_FIELDS), True, None),
+ "outbound.cookie.": (["rm-cookie", "set-cookie"],
Validator.http_token(), False, None),
+ "outbound.req.": (["rm-header", "set-header"], Validator.http_token(),
False, {"PRE_REMAP", "REMAP", "READ_REQUEST"}),
"outbound.resp.":
- (
- ["rm-header",
- "set-header"], Validator.quoted_or_simple(), False,
{"PRE_REMAP", "REMAP", "READ_REQUEST", "SEND_REQUEST"}),
+ (["rm-header", "set-header"], Validator.http_token(), False,
{"PRE_REMAP", "REMAP", "READ_REQUEST", "SEND_REQUEST"}),
"outbound.status.reason": ("set-status-reason", Validator.range(0,
999), False, {"PRE_REMAP", "REMAP", "READ_REQUEST"}),
"outbound.status": ("set-status", Validator.range(0, 999), False,
{"PRE_REMAP", "REMAP", "READ_REQUEST"}),
}
@@ -95,13 +93,13 @@ class SymbolResolver:
"http.cntl.": ("HTTP-CNTL",
Validator.suffix_group(types.SuffixGroup.HTTP_CNTL_FIELDS), True, None, False),
"id.": ("ID", Validator.suffix_group(types.SuffixGroup.ID_FIELDS),
True, None, False),
"inbound.conn.": ("INBOUND",
Validator.suffix_group(types.SuffixGroup.CONN_FIELDS), True, None, False),
- "inbound.cookie.": ("COOKIE", Validator.quoted_or_simple(), False,
None, True),
+ "inbound.cookie.": ("COOKIE", Validator.http_token(), False, None,
True),
"inbound.req.": ("CLIENT-HEADER", None, False, None, True),
"inbound.resp.": ("HEADER", None, False, None, True),
"inbound.url.": ("CLIENT-URL",
Validator.suffix_group(types.SuffixGroup.URL_FIELDS), True, None, True),
"now.": ("NOW", Validator.suffix_group(types.SuffixGroup.DATE_FIELDS),
True, None, False),
"outbound.conn.": ("OUTBOUND",
Validator.suffix_group(types.SuffixGroup.CONN_FIELDS), True, None, False),
- "outbound.cookie.": ("COOKIE", Validator.quoted_or_simple(), False,
None, True),
+ "outbound.cookie.": ("COOKIE", Validator.http_token(), False, None,
True),
"outbound.req.": ("HEADER", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST"}, True),
"outbound.resp.": ("HEADER", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST", "SEND_REQUEST"}, True),
"outbound.url.":
@@ -178,6 +176,8 @@ class SymbolResolver:
qualifier = name[len(op_key):]
if uppercase:
qualifier = qualifier.upper()
+ if validator:
+ validator(qualifier)
if isinstance(commands, list): # rm- / -set- operator
if value == '""':
result = f"{commands[0]} {qualifier}"
diff --git a/tools/hrw4u/src/validation.py b/tools/hrw4u/src/validation.py
index d206667492..aa590f7abe 100644
--- a/tools/hrw4u/src/validation.py
+++ b/tools/hrw4u/src/validation.py
@@ -75,6 +75,9 @@ class ValidatorChain:
def quoted_or_simple(self) -> 'ValidatorChain':
return self._add(self._wrap_args(Validator.quoted_or_simple()))
+ def http_token(self) -> 'ValidatorChain':
+ return self._add(self._wrap_args(Validator.http_token()))
+
def nbit_int(self, nbits: int) -> 'ValidatorChain':
return self._add(self._wrap_args(Validator.nbit_int(nbits)))
@@ -134,7 +137,7 @@ class Validator:
@staticmethod
def quoted_or_simple() -> Callable[[str], None]:
- simple_re = re.compile(r'^[a-zA-Z0-9_-]+$')
+ simple_re = re.compile(r'^[@a-zA-Z0-9_-]+$')
def validator(value: str) -> None:
if (value.startswith('"') and value.endswith('"')) or
simple_re.fullmatch(value):
@@ -144,6 +147,17 @@ class Validator:
return validator
+ @staticmethod
+ def http_token() -> Callable[[str], None]:
+ header_re = re.compile(r'^[@!#$%&\'*+\-.0-9A-Z^_`a-z|~]+$')
+
+ def validator(value: str) -> None:
+ if header_re.fullmatch(value):
+ return
+ raise SymbolResolutionError(value, "HTTP token/header not valid,
illegal characters or format.")
+
+ return validator
+
@staticmethod
def suffix_group(group: types.SuffixGroup) -> Callable[[str], None]:
diff --git a/tools/hrw4u/tests/data/ops/bad_path.fail.error.txt
b/tools/hrw4u/tests/data/ops/bad_path.fail.error.txt
new file mode 100644
index 0000000000..d5ab37f64f
--- /dev/null
+++ b/tools/hrw4u/tests/data/ops/bad_path.fail.error.txt
@@ -0,0 +1,3 @@
+tests/data/ops/bad_path.fail.input.txt:2:2: error: Invalid suffix 'ATH' for
group 'URL_FIELDS'. Must be one of: HOST, PATH, PORT, QUERY, SCHEME, URL
+ 2 | inbound.url.ath="foo";
+ | ^
diff --git a/tools/hrw4u/tests/data/ops/bad_path.fail.input.txt
b/tools/hrw4u/tests/data/ops/bad_path.fail.input.txt
new file mode 100644
index 0000000000..f0ba09ac15
--- /dev/null
+++ b/tools/hrw4u/tests/data/ops/bad_path.fail.input.txt
@@ -0,0 +1,3 @@
+REMAP {
+ inbound.url.ath="foo";
+}