diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java index c29ed83201d9..11f68d94e5d9 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java @@ -268,15 +268,19 @@ public enum SpelMessage { /** @since 5.2.23 */ MAX_REPEATED_TEXT_SIZE_EXCEEDED(Kind.ERROR, 1076, - "Repeated text results in too many characters, exceeding the threshold of ''{0}''"), + "Repeated text is too long, exceeding the threshold of ''{0}'' characters"), /** @since 5.2.23 */ MAX_REGEX_LENGTH_EXCEEDED(Kind.ERROR, 1077, - "Regular expression contains too many characters, exceeding the threshold of ''{0}''"), + "Regular expression is too long, exceeding the threshold of ''{0}'' characters"), /** @since 5.2.24 */ MAX_CONCATENATED_STRING_LENGTH_EXCEEDED(Kind.ERROR, 1078, - "Concatenated string is too long, exceeding the threshold of ''{0}'' characters"); + "Concatenated string is too long, exceeding the threshold of ''{0}'' characters"), + + /** @since 5.2.24 */ + MAX_EXPRESSION_LENGTH_EXCEEDED(Kind.ERROR, 1079, + "SpEL expression is too long, exceeding the threshold of ''{0}'' characters"); private final Kind kind; diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java index 748f8e6bd524..b8b4b68c38f2 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java @@ -29,6 +29,7 @@ import org.springframework.expression.ParserContext; import org.springframework.expression.common.TemplateAwareExpressionParser; import org.springframework.expression.spel.InternalParseException; +import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.SpelParseException; import org.springframework.expression.spel.SpelParserConfiguration; @@ -92,6 +93,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { private static final Pattern VALID_QUALIFIED_ID_PATTERN = Pattern.compile("[\\p{L}\\p{N}_$]+"); + /** + * Maximum length permitted for a SpEL expression. + * @since 5.2.24 + */ + private static final int MAX_EXPRESSION_LENGTH = 10_000; + private final SpelParserConfiguration configuration; @@ -127,6 +134,8 @@ public InternalSpelExpressionParser(SpelParserConfiguration configuration) { protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException { + checkExpressionLength(expressionString); + try { this.expressionString = expressionString; Tokenizer tokenizer = new Tokenizer(expressionString); @@ -148,6 +157,12 @@ protected SpelExpression doParseExpression(String expressionString, @Nullable Pa } } + private void checkExpressionLength(String string) { + if (string.length() > MAX_EXPRESSION_LENGTH) { + throw new SpelEvaluationException(SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED, MAX_EXPRESSION_LENGTH); + } + } + // expression // : logicalOrExpression // ( (ASSIGN^ logicalOrExpression) diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java index 60b2ae22f5f8..e81e2a43f713 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java @@ -60,6 +60,20 @@ class EvaluationTests extends AbstractExpressionTests { @Nested class MiscellaneousTests { + @Test + void expressionLength() { + String expression = "'X' + '%s'".formatted(" ".repeat(9_992)); + assertThat(expression).hasSize(10_000); + Expression expr = parser.parseExpression(expression); + String result = expr.getValue(context, String.class); + assertThat(result).hasSize(9_993); + assertThat(result.trim()).isEqualTo("X"); + + expression = "'X' + '%s'".formatted(" ".repeat(9_993)); + assertThat(expression).hasSize(10_001); + evaluateAndCheckError(expression, String.class, SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED); + } + @Test void createListsOnAttemptToIndexNull01() throws EvaluationException, ParseException { ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));