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 fbccde0ceb Hrw4U: Multi cond fixes + allow conds to have a default
expression of !="" (#12346)
fbccde0ceb is described below
commit fbccde0ceb6679224336379ccd055fc601aa7da3
Author: Leif Hedstrom <[email protected]>
AuthorDate: Thu Jul 10 11:32:06 2025 -0500
Hrw4U: Multi cond fixes + allow conds to have a default expression of
!="" (#12346)
* Fixes conditions with > 2 expressions
* Enable some conds to have a default expression of !=""
---
tools/hrw4u/src/symbols.py | 70 +++++++++++------------
tools/hrw4u/src/visitor.py | 32 +++++++----
tools/hrw4u/tests/data/conds/cookie.output.txt | 2 +-
tools/hrw4u/tests/data/conds/impl-expr.ast.txt | 1 +
tools/hrw4u/tests/data/conds/impl-expr.input.txt | 5 ++
tools/hrw4u/tests/data/conds/impl-expr.output.txt | 4 ++
tools/hrw4u/tests/data/conds/long-if.ast.txt | 1 +
tools/hrw4u/tests/data/conds/long-if.input.txt | 11 ++++
tools/hrw4u/tests/data/conds/long-if.output.txt | 15 +++++
9 files changed, 93 insertions(+), 48 deletions(-)
diff --git a/tools/hrw4u/src/symbols.py b/tools/hrw4u/src/symbols.py
index bdcfeb7531..a44d50d486 100644
--- a/tools/hrw4u/src/symbols.py
+++ b/tools/hrw4u/src/symbols.py
@@ -74,39 +74,39 @@ class SymbolResolver:
"txn-count": ("TXN-COUNT", Validator.arg_count(0)),
}
- _CONDITION_MAP: Dict[str, Tuple[str, Optional[Callable[[str], None]],
bool, Optional[Set[str]]]] = {
+ _CONDITION_MAP: Dict[str, Tuple[str, Optional[Callable[[str], None]],
bool, Optional[Set[str]], bool]] = {
# Exact matches
- "inbound.ip": ("%{IP:CLIENT}", None, False, None),
- "inbound.method": ("%{METHOD}", None, False, None),
- "inbound.server": ("%{IP:INBOUND}", None, False, None),
- "inbound.status": ("%{STATUS}", None, False, None),
- "now": ("%{NOW}", None, False, None),
- "outbound.ip": ("%{IP:SERVER}", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST"}),
- "outbound.method": ("%{METHOD}", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST"}),
- "outbound.server": ("%{IP:OUTBOUND}", None, False, {"PRE_REMAP",
"REMAP", "READ_REQUEST"}),
- "outbound.status": ("%{STATUS}", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST"}),
- "tcp.info": ("%{TCP-INFO}", None, False, None),
+ "inbound.ip": ("%{IP:CLIENT}", None, False, None, False),
+ "inbound.method": ("%{METHOD}", None, False, None, False),
+ "inbound.server": ("%{IP:INBOUND}", None, False, None, False),
+ "inbound.status": ("%{STATUS}", None, False, None, False),
+ "now": ("%{NOW}", None, False, None, False),
+ "outbound.ip": ("%{IP:SERVER}", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST"}, False),
+ "outbound.method": ("%{METHOD}", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST"}, False),
+ "outbound.server": ("%{IP:OUTBOUND}", None, False, {"PRE_REMAP",
"REMAP", "READ_REQUEST"}, False),
+ "outbound.status": ("%{STATUS}", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST"}, False),
+ "tcp.info": ("%{TCP-INFO}", None, False, None, False),
# Prefix matches
- "capture.": ("LAST-CAPTURE", Validator.range(0, 9), False, None),
- "client.cert.": ("CLIENT-CERT", None, True, None),
- "from.url.": ("FROM-URL",
Validator.suffix_group(types.SuffixGroup.URL_FIELDS), True, None),
- "geo.": ("GEO", Validator.suffix_group(types.SuffixGroup.GEO_FIELDS),
True, None),
- "http.cntl.": ("HTTP-CNTL",
Validator.suffix_group(types.SuffixGroup.HTTP_CNTL_FIELDS), True, None),
- "id.": ("ID", Validator.suffix_group(types.SuffixGroup.ID_FIELDS),
True, None),
- "inbound.conn.": ("INBOUND",
Validator.suffix_group(types.SuffixGroup.CONN_FIELDS), True, None),
- "inbound.cookie.": ("COOKIE", Validator.quoted_or_simple(), False,
None),
- "inbound.req.": ("CLIENT-HEADER", None, False, None),
- "inbound.resp.": ("HEADER", None, False, None),
- "inbound.url.": ("CLIENT-URL",
Validator.suffix_group(types.SuffixGroup.URL_FIELDS), True, None),
- "now.": ("NOW", Validator.suffix_group(types.SuffixGroup.DATE_FIELDS),
True, None),
- "outbound.conn.": ("OUTBOUND",
Validator.suffix_group(types.SuffixGroup.CONN_FIELDS), True, None),
- "outbound.cookie.": ("COOKIE", Validator.quoted_or_simple(), False,
None),
- "outbound.req.": ("HEADER", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST"}),
- "outbound.resp.": ("HEADER", None, False, {"PRE_REMAP", "REMAP",
"READ_REQUEST", "SEND_REQUEST"}),
+ "capture.": ("LAST-CAPTURE", Validator.range(0, 9), False, None, True),
+ "client.cert.": ("CLIENT-CERT", None, True, None, True),
+ "from.url.": ("FROM-URL",
Validator.suffix_group(types.SuffixGroup.URL_FIELDS), True, None, True),
+ "geo.": ("GEO", Validator.suffix_group(types.SuffixGroup.GEO_FIELDS),
True, None, True),
+ "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.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.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.":
- ("NEXT-HOP", Validator.suffix_group(types.SuffixGroup.URL_FIELDS),
True, {"PRE_REMAP", "REMAP", "READ_REQUEST"}),
- "to.url.": ("TO-URL",
Validator.suffix_group(types.SuffixGroup.URL_FIELDS), True, None),
+ ("NEXT-HOP", Validator.suffix_group(types.SuffixGroup.URL_FIELDS),
True, {"PRE_REMAP", "REMAP", "READ_REQUEST"}, True),
+ "to.url.": ("TO-URL",
Validator.suffix_group(types.SuffixGroup.URL_FIELDS), True, None, True),
}
_SECTION_MAP = {
@@ -206,23 +206,23 @@ class SymbolResolver:
self._debug_exit("=> not found")
raise SymbolResolutionError(name, "Unknown assignment symbol")
- def resolve_condition(self, name: str, section: Optional[str] = None) ->
str:
+ def resolve_condition(self, name: str, section: Optional[str] = None) ->
Tuple[str, bool]:
self._debug_enter(f"resolve_condition: {name} (section={section})")
symbol = self.symbol_for(name)
if symbol:
self._debug_exit(f"=> symbol_table: {symbol.as_cond()}")
- return symbol.as_cond()
+ return symbol.as_cond(), False
# Exact match
if name in self._CONDITION_MAP:
- tag, _, _, restricted = self._CONDITION_MAP[name]
+ tag, _, _, restricted, default_expr = self._CONDITION_MAP[name]
self.check_section(name, section, restricted)
self._debug_exit(f"=> exact condition_map: {tag}")
- return tag
+ return tag, default_expr
# Prefix match
- for prefix, (tag, validator, uppercase, restricted) in
self._CONDITION_MAP.items():
+ for prefix, (tag, validator, uppercase, restricted, default_expr) in
self._CONDITION_MAP.items():
if prefix.endswith(".") and name.startswith(prefix):
self.check_section(name, section, restricted)
suffix = name[len(prefix):]
@@ -231,7 +231,7 @@ class SymbolResolver:
validator(suf_norm)
resolved = f"%{{{tag}:{suf_norm}}}"
self._debug_exit(f"=> prefix condition_map: {resolved}")
- return resolved
+ return resolved, default_expr
self._debug_exit("=> not found")
raise SymbolResolutionError(name, "Unknown condition symbol")
diff --git a/tools/hrw4u/src/visitor.py b/tools/hrw4u/src/visitor.py
index cf51c5ec4c..38f089a55f 100644
--- a/tools/hrw4u/src/visitor.py
+++ b/tools/hrw4u/src/visitor.py
@@ -114,7 +114,7 @@ class HRW4UVisitor(hrw4uVisitor):
self._debug(f"substitute: {{{func_name}({arg_str})}} ->
{replacement}")
elif m.group("var"):
var_name = m.group("var").strip()
- replacement =
self.symbol_resolver.resolve_condition(var_name, self.current_section)
+ replacement, _ =
self.symbol_resolver.resolve_condition(var_name, self.current_section)
self._debug(f"substitute: {{{var_name}}} -> {replacement}")
else:
raise SymbolResolutionError(m.group(0), "Unrecognized
substitution format")
@@ -306,7 +306,7 @@ class HRW4UVisitor(hrw4uVisitor):
comp = ctx.comparable()
try:
if comp.ident:
- lhs = self.symbol_resolver.resolve_condition(comp.ident.text,
self.current_section)
+ lhs, _ =
self.symbol_resolver.resolve_condition(comp.ident.text, self.current_section)
else:
lhs = self.visitFunctionCall(comp.functionCall())
operator = ctx.getChild(1)
@@ -382,25 +382,22 @@ class HRW4UVisitor(hrw4uVisitor):
self._flush_condition()
self.output.append(" " * (self._stmt_indent * self.INDENT_SPACES) +
line)
- def emit_expression(self, ctx, *, nested: bool = False, last: bool =
False):
+ def emit_expression(self, ctx, *, nested: bool = False, last: bool =
False, grouped: bool = False):
self._debug_enter("emit_expression")
if ctx.OR():
self._debug("`OR' detected")
- if nested:
+ if grouped:
self._debug("GROUP-START")
self.emit_condition("cond %{GROUP}", final=True)
self._cond_indent += 1
- self.emit_expression(ctx.expression(), nested=True, last=False)
-
+ self.emit_expression(ctx.expression(), nested=False, last=False)
if self._queued:
- self._queued.indent = self._cond_indent
self._queued.state.and_or = True
self._flush_condition()
-
self.emit_term(ctx.term(), last=last)
- if nested:
+ if grouped:
self._flush_condition()
self._cond_indent -= 1
self.emit_condition("cond %{GROUP:END}")
@@ -434,7 +431,7 @@ class HRW4UVisitor(hrw4uVisitor):
self._debug("GROUP-START")
self.emit_condition("cond %{GROUP}", final=True)
self._cond_indent += 1
- self.emit_expression(ctx.expression(), nested=False, last=True)
+ self.emit_expression(ctx.expression(), nested=False,
last=True, grouped=True)
self._cond_indent -= 1
self._cond_state.last = last
self.emit_condition("cond %{GROUP:END}")
@@ -461,9 +458,20 @@ class HRW4UVisitor(hrw4uVisitor):
entry = self.symbol_resolver.symbol_for(name)
if entry:
symbol = entry.as_cond()
+ default_expr = False
else:
- symbol = self.symbol_resolver.resolve_condition(name,
self.current_section)
- cond = self._make_condition(symbol, last=last)
+ symbol, default_expr =
self.symbol_resolver.resolve_condition(name, self.current_section)
+
+ if default_expr:
+ cond_txt = f"{symbol} =\"\""
+ negate = not self._cond_state.not_
+ else:
+ cond_txt = symbol
+ negate = self._cond_state.not_
+
+ self._cond_state.not_ = False
+ self._debug(f"{'implicit' if default_expr else 'explicit'}
comparison: {cond_txt} negate={negate}")
+ cond = self._make_condition(cond_txt, last=last, negate=negate)
self.emit_condition(cond)
except Exception as e:
diff --git a/tools/hrw4u/tests/data/conds/cookie.output.txt
b/tools/hrw4u/tests/data/conds/cookie.output.txt
index f96ccc8faa..9a111d31a0 100644
--- a/tools/hrw4u/tests/data/conds/cookie.output.txt
+++ b/tools/hrw4u/tests/data/conds/cookie.output.txt
@@ -3,5 +3,5 @@ cond %{COOKIE:bar} /bar/
set-cookie mybar "1"
cond %{SEND_RESPONSE_HDR_HOOK} [AND]
-cond %{COOKIE:bar} [NOT]
+cond %{COOKIE:bar} =""
set-cookie mybar "1"
diff --git a/tools/hrw4u/tests/data/conds/impl-expr.ast.txt
b/tools/hrw4u/tests/data/conds/impl-expr.ast.txt
new file mode 100644
index 0000000000..bfc47f0e98
--- /dev/null
+++ b/tools/hrw4u/tests/data/conds/impl-expr.ast.txt
@@ -0,0 +1 @@
+(program (section REMAP { (sectionBody (conditional (ifStatement if (condition
(expression (expression (term (factor inbound.req.X-Foo))) || (term (factor
inbound.req.X-Bar)))) (block { (statement inbound.req.X-fie = (value "123") ;)
})))) }) <EOF>)
diff --git a/tools/hrw4u/tests/data/conds/impl-expr.input.txt
b/tools/hrw4u/tests/data/conds/impl-expr.input.txt
new file mode 100644
index 0000000000..ac95b57c49
--- /dev/null
+++ b/tools/hrw4u/tests/data/conds/impl-expr.input.txt
@@ -0,0 +1,5 @@
+REMAP {
+ if inbound.req.X-Foo || inbound.req.X-Bar {
+ inbound.req.X-fie = "123";
+ }
+}
diff --git a/tools/hrw4u/tests/data/conds/impl-expr.output.txt
b/tools/hrw4u/tests/data/conds/impl-expr.output.txt
new file mode 100644
index 0000000000..6b73c0abef
--- /dev/null
+++ b/tools/hrw4u/tests/data/conds/impl-expr.output.txt
@@ -0,0 +1,4 @@
+cond %{REMAP_PSEUDO_HOOK} [AND]
+cond %{CLIENT-HEADER:X-Foo} ="" [OR,NOT]
+cond %{CLIENT-HEADER:X-Bar} ="" [NOT]
+ set-header X-fie "123"
diff --git a/tools/hrw4u/tests/data/conds/long-if.ast.txt
b/tools/hrw4u/tests/data/conds/long-if.ast.txt
new file mode 100644
index 0000000000..4711c03ed9
--- /dev/null
+++ b/tools/hrw4u/tests/data/conds/long-if.ast.txt
@@ -0,0 +1 @@
+(program (section REMAP { (sectionBody (conditional (ifStatement if (condition
(expression (expression (expression (term (factor (comparison (comparable
inbound.req.xfoo) != (value ""))))) || (term (factor (comparison (comparable
inbound.req.xBar) != (value ""))))) || (term (term (factor (comparison
(comparable inbound.req.X-Foo) != (value "")))) && (factor (comparison
(comparable inbound.req.X-Fie) == (value "")))))) (block { (statement
inbound.req.X-fie = (value "123") ;) })))) }) (sec [...]
diff --git a/tools/hrw4u/tests/data/conds/long-if.input.txt
b/tools/hrw4u/tests/data/conds/long-if.input.txt
new file mode 100644
index 0000000000..8dc1dc9246
--- /dev/null
+++ b/tools/hrw4u/tests/data/conds/long-if.input.txt
@@ -0,0 +1,11 @@
+REMAP {
+ if inbound.req.xfoo != "" || inbound.req.xBar != "" || inbound.req.X-Foo
!= "" && inbound.req.X-Fie == "" {
+ inbound.req.X-fie = "123";
+ }
+}
+
+REMAP {
+ if inbound.req.xfoo != "" || inbound.req.xBar != "" || (inbound.req.X-Foo
!= "" && inbound.req.X-Fie == "") {
+ inbound.req.X-fie = "123";
+ }
+}
diff --git a/tools/hrw4u/tests/data/conds/long-if.output.txt
b/tools/hrw4u/tests/data/conds/long-if.output.txt
new file mode 100644
index 0000000000..ed2051a5ec
--- /dev/null
+++ b/tools/hrw4u/tests/data/conds/long-if.output.txt
@@ -0,0 +1,15 @@
+cond %{REMAP_PSEUDO_HOOK} [AND]
+cond %{CLIENT-HEADER:xfoo} ="" [OR,NOT]
+cond %{CLIENT-HEADER:xBar} ="" [OR,NOT]
+cond %{CLIENT-HEADER:X-Foo} ="" [AND,NOT]
+cond %{CLIENT-HEADER:X-Fie} =""
+ set-header X-fie "123"
+
+cond %{REMAP_PSEUDO_HOOK} [AND]
+cond %{CLIENT-HEADER:xfoo} ="" [OR,NOT]
+cond %{CLIENT-HEADER:xBar} ="" [OR,NOT]
+cond %{GROUP}
+ cond %{CLIENT-HEADER:X-Foo} ="" [AND,NOT]
+ cond %{CLIENT-HEADER:X-Fie} =""
+cond %{GROUP:END}
+ set-header X-fie "123"