This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit a19e998728abe83117aaab2896de5956dc8782fd Author: opencode <[email protected]> AuthorDate: Thu Oct 8 13:59:26 2026 +0200 Give && higher precedence than || in SSI conditional expressions The SSI conditional expression parser assigned the same precedence to the logical operators, so mixed chains were evaluated strictly left to right and "$a || $b && $c" grouped as "($a || $b) && $c" instead of the conventionally expected "$a || ($b && $c)", silently inverting the logic of such expressions. Give AndNode and OrNode distinct precedences, with && binding more tightly than ||, consistent with the convention used by the C-like languages and with Apache HTTP Server expressions. Chains of the same operator keep their left-to-right associativity. Note that this changes the evaluation of existing documents using unparenthesized mixed && and || chains. Document the precedence order in the SSI howto. --- java/org/apache/catalina/ssi/ExpressionParseTree.java | 7 ++++--- .../apache/catalina/ssi/TestExpressionParseTree.java | 19 +++++++++++++++++++ webapps/docs/changelog.xml | 12 ++++++++++++ webapps/docs/ssi-howto.xml | 6 ++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/java/org/apache/catalina/ssi/ExpressionParseTree.java b/java/org/apache/catalina/ssi/ExpressionParseTree.java index 2b2d74aca5..cf6dc1afa6 100644 --- a/java/org/apache/catalina/ssi/ExpressionParseTree.java +++ b/java/org/apache/catalina/ssi/ExpressionParseTree.java @@ -310,7 +310,8 @@ public class ExpressionParseTree { private static final int PRECEDENCE_NOT = 5; private static final int PRECEDENCE_COMPARE = 4; - private static final int PRECEDENCE_LOGICAL = 1; + private static final int PRECEDENCE_AND = 2; + private static final int PRECEDENCE_OR = 1; /** * A node implementation that represents an operation. @@ -397,7 +398,7 @@ public class ExpressionParseTree { @Override public int getPrecedence() { - return PRECEDENCE_LOGICAL; + return PRECEDENCE_AND; } @@ -419,7 +420,7 @@ public class ExpressionParseTree { @Override public int getPrecedence() { - return PRECEDENCE_LOGICAL; + return PRECEDENCE_OR; } diff --git a/test/org/apache/catalina/ssi/TestExpressionParseTree.java b/test/org/apache/catalina/ssi/TestExpressionParseTree.java index a635c8258d..4865305a3c 100644 --- a/test/org/apache/catalina/ssi/TestExpressionParseTree.java +++ b/test/org/apache/catalina/ssi/TestExpressionParseTree.java @@ -137,6 +137,25 @@ public class TestExpressionParseTree { } + @Test + public void testAndHasHigherPrecedenceThanOr() throws Exception { + SSIExternalResolver r = new TesterSSIExternalResolver(); + r.setVariableValue("a", "x"); + r.setVariableValue("b", ""); + r.setVariableValue("c", ""); + SSIMediator mediator = new SSIMediator(r, LAST_MODIFIED); + // With conventional precedence, this is true: $a || ($b && $c) + ExpressionParseTree ept = new ExpressionParseTree("$a || $b && $c", mediator); + Assert.assertTrue(ept.evaluateTree()); + // Explicit parentheses give the same result + ept = new ExpressionParseTree("$a || ($b && $c)", mediator); + Assert.assertTrue(ept.evaluateTree()); + // The left-to-right grouping evaluates to false: ($a || $b) && $c + ept = new ExpressionParseTree("($a || $b) && $c", mediator); + Assert.assertFalse(ept.evaluateTree()); + } + + @Test public void testMissingOperand() throws Exception { // Operators missing an operand must produce a parse error rather than diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index b2ead9a74a..2df2c9f857 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -1924,6 +1924,18 @@ now passed to the <code>LoginModule</code> unchanged, consistent with the non-JAAS realms. (remm) </fix> + <fix> + Give the SSI conditional expression operators <code>&&</code> + and <code>||</code> distinct precedences, <code>&&</code> + binding more tightly than <code>||</code>, consistent with the + convention used by the C-like languages and by Apache HTTP Server + expressions. Previously, mixed chains were evaluated strictly left to + right, so <code>$a || $b && $c</code> was evaluated as + <code>($a || $b) && $c</code> rather than the expected + <code>$a || ($b && $c)</code>. Note that this changes the + evaluation of existing documents using unparenthesized mixed + <code>&&</code> and <code>||</code> chains. (remm) + </fix> </changelog> </subsection> <subsection name="Coyote"> diff --git a/webapps/docs/ssi-howto.xml b/webapps/docs/ssi-howto.xml index 899a807f0f..6fc964e338 100644 --- a/webapps/docs/ssi-howto.xml +++ b/webapps/docs/ssi-howto.xml @@ -221,6 +221,12 @@ is used to assign a value to a user-defined variable. <!--#else --> <p>Yoga class at noon.</p> <!--#endif -->]]></source> +Operators in conditional expressions are evaluated from highest to lowest +precedence: parentheses, the <code>!</code> operator, the comparison operators +(<code>=</code>, <code>!=</code>, <code><</code>, <code>></code>, +<code><=</code>, <code>>=</code>), <code>&&</code> and finally +<code>||</code>. For example, <code>$a || $b && $c</code> is evaluated as +<code>$a || ($b && $c)</code>. </li> </ul> <p> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
