You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2026/10/08 16:12:23 UTC
(tomcat) 03/22: Give && higher precedence than || in SSI conditional expressions
This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit cf48b8562150674ee8097c29e3a838fbe500909d
Author: opencode <re...@apache.org>
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 594998c0de..792dd44af7 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -1920,6 +1920,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 0f518b9bf5..973f4af9a8 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: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org