This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit ea6775810b515eb5ca99e90e7dbf019b6c6352da Author: opencode <[email protected]> AuthorDate: Thu Oct 8 13:44:22 2026 +0200 Fix StringIndexOutOfBoundsException for unterminated regular expression in SSI expressions When an SSI conditional expression contained a regular expression literal without a closing slash, ExpressionTokenizer.nextToken() computed an end offset one past the end of the expression, and building the token string threw a StringIndexOutOfBoundsException. Since this is not a ParseException, it bypassed the error handling of SSIConditional and SSIProcessor and surfaced as a 500 error for the whole request. Cap the token at the end of the expression when the closing slash is missing, mirroring the pre-existing behavior for unterminated quoted strings. The resulting token (e.g. "/x") is not recognized as a regular expression by ExpressionParseTree and is compared as a plain string. Also harden the end-of-input check against the index past the end that both unterminated cases leave behind, and add a tokenizer test case for the unterminated regular expression. --- java/org/apache/catalina/ssi/ExpressionTokenizer.java | 6 ++++-- test/org/apache/catalina/ssi/TestExpressionTokenizer.java | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/java/org/apache/catalina/ssi/ExpressionTokenizer.java b/java/org/apache/catalina/ssi/ExpressionTokenizer.java index 36c0d519cd..825b82c30a 100644 --- a/java/org/apache/catalina/ssi/ExpressionTokenizer.java +++ b/java/org/apache/catalina/ssi/ExpressionTokenizer.java @@ -109,7 +109,7 @@ public class ExpressionTokenizer { } // Clear the current token val tokenVal = null; - if (index == length) { + if (index >= length) { return TOKEN_END; // End of string } int start = index; @@ -191,7 +191,9 @@ public class ExpressionTokenizer { } escaped = false; } - end = ++index; + // If the regular expression was not terminated, the token is the + // remainder of the expression, otherwise it includes the closing slash + end = Math.min(++index, length); } else { // End is the next whitespace character for (; index < length; index++) { diff --git a/test/org/apache/catalina/ssi/TestExpressionTokenizer.java b/test/org/apache/catalina/ssi/TestExpressionTokenizer.java index eafa517b49..e4f78cdb55 100644 --- a/test/org/apache/catalina/ssi/TestExpressionTokenizer.java +++ b/test/org/apache/catalina/ssi/TestExpressionTokenizer.java @@ -101,6 +101,11 @@ public class TestExpressionTokenizer { // Escaped slash inside a regular expression parameterSets.add(new Object[] { "/a\\/b/", new int[] { ExpressionTokenizer.TOKEN_STRING }, new String[] { "/a\\/b/" } }); + // Unterminated regular expression: the token is the remainder + parameterSets.add(new Object[] { "a = /x", + new int[] { ExpressionTokenizer.TOKEN_STRING, ExpressionTokenizer.TOKEN_EQ, + ExpressionTokenizer.TOKEN_STRING }, + new String[] { "a", null, "/x" } }); // Operators mixed with strings parameterSets.add(new Object[] { "a && b", --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
