Skip to content

Commit aefcb9d

Browse files
committed
Make maximum SpEL expression length configurable
Closes gh-30380
1 parent 120c228 commit aefcb9d

File tree

4 files changed

+77
-10
lines changed

4 files changed

+77
-10
lines changed

Diff for: spring-expression/src/main/java/org/springframework/expression/spel/SpelParserConfiguration.java

+36-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,12 @@
3030
*/
3131
public class SpelParserConfiguration {
3232

33+
/**
34+
* Default maximum length permitted for a SpEL expression.
35+
* @since 5.2.24
36+
*/
37+
private static final int DEFAULT_MAX_EXPRESSION_LENGTH = 10_000;
38+
3339
/** System property to configure the default compiler mode for SpEL expression parsers: {@value}. */
3440
public static final String SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME = "spring.expression.compiler.mode";
3541

@@ -54,6 +60,8 @@ public class SpelParserConfiguration {
5460

5561
private final int maximumAutoGrowSize;
5662

63+
private final int maximumExpressionLength;
64+
5765

5866
/**
5967
* Create a new {@code SpelParserConfiguration} instance with default settings.
@@ -102,11 +110,30 @@ public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowC
102110
public SpelParserConfiguration(@Nullable SpelCompilerMode compilerMode, @Nullable ClassLoader compilerClassLoader,
103111
boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize) {
104112

113+
this(compilerMode, compilerClassLoader, autoGrowNullReferences, autoGrowCollections,
114+
maximumAutoGrowSize, DEFAULT_MAX_EXPRESSION_LENGTH);
115+
}
116+
117+
/**
118+
* Create a new {@code SpelParserConfiguration} instance.
119+
* @param compilerMode the compiler mode that parsers using this configuration object should use
120+
* @param compilerClassLoader the ClassLoader to use as the basis for expression compilation
121+
* @param autoGrowNullReferences if null references should automatically grow
122+
* @param autoGrowCollections if collections should automatically grow
123+
* @param maximumAutoGrowSize the maximum size that a collection can auto grow
124+
* @param maximumExpressionLength the maximum length of a SpEL expression;
125+
* must be a positive number
126+
* @since 5.2.25
127+
*/
128+
public SpelParserConfiguration(@Nullable SpelCompilerMode compilerMode, @Nullable ClassLoader compilerClassLoader,
129+
boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize, int maximumExpressionLength) {
130+
105131
this.compilerMode = (compilerMode != null ? compilerMode : defaultCompilerMode);
106132
this.compilerClassLoader = compilerClassLoader;
107133
this.autoGrowNullReferences = autoGrowNullReferences;
108134
this.autoGrowCollections = autoGrowCollections;
109135
this.maximumAutoGrowSize = maximumAutoGrowSize;
136+
this.maximumExpressionLength = maximumExpressionLength;
110137
}
111138

112139

@@ -146,4 +173,12 @@ public int getMaximumAutoGrowSize() {
146173
return this.maximumAutoGrowSize;
147174
}
148175

176+
/**
177+
* Return the maximum number of characters that a SpEL expression can contain.
178+
* @since 5.2.25
179+
*/
180+
public int getMaximumExpressionLength() {
181+
return this.maximumExpressionLength;
182+
}
183+
149184
}

Diff for: spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java

+3-9
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,6 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
9393

9494
private static final Pattern VALID_QUALIFIED_ID_PATTERN = Pattern.compile("[\\p{L}\\p{N}_$]+");
9595

96-
/**
97-
* Maximum length permitted for a SpEL expression.
98-
* @since 5.2.24
99-
*/
100-
private static final int MAX_EXPRESSION_LENGTH = 10_000;
101-
102-
10396
private final SpelParserConfiguration configuration;
10497

10598
// For rules that build nodes, they are stacked here for return
@@ -158,8 +151,9 @@ protected SpelExpression doParseExpression(String expressionString, @Nullable Pa
158151
}
159152

160153
private void checkExpressionLength(String string) {
161-
if (string.length() > MAX_EXPRESSION_LENGTH) {
162-
throw new SpelEvaluationException(SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED, MAX_EXPRESSION_LENGTH);
154+
int maxLength = this.configuration.getMaximumExpressionLength();
155+
if (string.length() > maxLength) {
156+
throw new SpelEvaluationException(SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED, maxLength);
163157
}
164158
}
165159

Diff for: spring-expression/src/test/java/org/springframework/expression/spel/AbstractExpressionTests.java

+18
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,24 @@ protected void evaluateAndCheckError(String expression, SpelMessage expectedMess
164164
*/
165165
protected void evaluateAndCheckError(String expression, Class<?> expectedReturnType, SpelMessage expectedMessage,
166166
Object... otherProperties) {
167+
168+
evaluateAndCheckError(this.parser, expression, expectedReturnType, expectedMessage, otherProperties);
169+
}
170+
171+
/**
172+
* Evaluate the specified expression and ensure the expected message comes out.
173+
* The message may have inserts and they will be checked if otherProperties is specified.
174+
* The first entry in otherProperties should always be the position.
175+
* @param parser the expression parser to use
176+
* @param expression the expression to evaluate
177+
* @param expectedReturnType ask the expression return value to be of this type if possible
178+
* ({@code null} indicates don't ask for conversion)
179+
* @param expectedMessage the expected message
180+
* @param otherProperties the expected inserts within the message
181+
*/
182+
protected void evaluateAndCheckError(ExpressionParser parser, String expression, Class<?> expectedReturnType, SpelMessage expectedMessage,
183+
Object... otherProperties) {
184+
167185
assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() -> {
168186
Expression expr = parser.parseExpression(expression);
169187
assertThat(expr).as("expression").isNotNull();

Diff for: spring-expression/src/test/java/org/springframework/expression/spel/EvaluationTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,26 @@ void expressionLength() {
7777
evaluateAndCheckError(expression, String.class, SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED);
7878
}
7979

80+
@Test
81+
void maxExpressionLengthIsConfigurable() {
82+
int maximumExpressionLength = 20_000;
83+
84+
String expression = "'%s'".formatted("Y".repeat(19_998));
85+
assertThat(expression).hasSize(maximumExpressionLength);
86+
87+
SpelParserConfiguration configuration =
88+
new SpelParserConfiguration(null, null, false, false, 0, maximumExpressionLength);
89+
ExpressionParser parser = new SpelExpressionParser(configuration);
90+
91+
Expression expr = parser.parseExpression(expression);
92+
String result = expr.getValue(String.class);
93+
assertThat(result).hasSize(19_998);
94+
95+
expression = "'%s'".formatted("Y".repeat(25_000));
96+
assertThat(expression).hasSize(25_002);
97+
evaluateAndCheckError(parser, expression, String.class, SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED);
98+
}
99+
80100
@Test
81101
void createListsOnAttemptToIndexNull01() throws EvaluationException, ParseException {
82102
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));

0 commit comments

Comments
 (0)