Merge branch '6.0.x'

This commit is contained in:
Sam Brannen 2023-05-10 14:36:09 +02:00
commit 96fbcb26c9
4 changed files with 77 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,6 +30,12 @@ import org.springframework.lang.Nullable;
*/
public class SpelParserConfiguration {
/**
* Default maximum length permitted for a SpEL expression.
* @since 5.2.24
*/
private static final int DEFAULT_MAX_EXPRESSION_LENGTH = 10_000;
/** System property to configure the default compiler mode for SpEL expression parsers: {@value}. */
public static final String SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME = "spring.expression.compiler.mode";
@ -54,6 +60,8 @@ public class SpelParserConfiguration {
private final int maximumAutoGrowSize;
private final int maximumExpressionLength;
/**
* Create a new {@code SpelParserConfiguration} instance with default settings.
@ -102,11 +110,30 @@ public class SpelParserConfiguration {
public SpelParserConfiguration(@Nullable SpelCompilerMode compilerMode, @Nullable ClassLoader compilerClassLoader,
boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize) {
this(compilerMode, compilerClassLoader, autoGrowNullReferences, autoGrowCollections,
maximumAutoGrowSize, DEFAULT_MAX_EXPRESSION_LENGTH);
}
/**
* Create a new {@code SpelParserConfiguration} instance.
* @param compilerMode the compiler mode that parsers using this configuration object should use
* @param compilerClassLoader the ClassLoader to use as the basis for expression compilation
* @param autoGrowNullReferences if null references should automatically grow
* @param autoGrowCollections if collections should automatically grow
* @param maximumAutoGrowSize the maximum size that a collection can auto grow
* @param maximumExpressionLength the maximum length of a SpEL expression;
* must be a positive number
* @since 5.2.25
*/
public SpelParserConfiguration(@Nullable SpelCompilerMode compilerMode, @Nullable ClassLoader compilerClassLoader,
boolean autoGrowNullReferences, boolean autoGrowCollections, int maximumAutoGrowSize, int maximumExpressionLength) {
this.compilerMode = (compilerMode != null ? compilerMode : defaultCompilerMode);
this.compilerClassLoader = compilerClassLoader;
this.autoGrowNullReferences = autoGrowNullReferences;
this.autoGrowCollections = autoGrowCollections;
this.maximumAutoGrowSize = maximumAutoGrowSize;
this.maximumExpressionLength = maximumExpressionLength;
}
@ -146,4 +173,12 @@ public class SpelParserConfiguration {
return this.maximumAutoGrowSize;
}
/**
* Return the maximum number of characters that a SpEL expression can contain.
* @since 5.2.25
*/
public int getMaximumExpressionLength() {
return this.maximumExpressionLength;
}
}

View File

@ -93,13 +93,6 @@ 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;
// For rules that build nodes, they are stacked here for return
@ -158,8 +151,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
private void checkExpressionLength(String string) {
if (string.length() > MAX_EXPRESSION_LENGTH) {
throw new SpelEvaluationException(SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED, MAX_EXPRESSION_LENGTH);
int maxLength = this.configuration.getMaximumExpressionLength();
if (string.length() > maxLength) {
throw new SpelEvaluationException(SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED, maxLength);
}
}

View File

@ -164,6 +164,24 @@ public abstract class AbstractExpressionTests {
*/
protected void evaluateAndCheckError(String expression, Class<?> expectedReturnType, SpelMessage expectedMessage,
Object... otherProperties) {
evaluateAndCheckError(this.parser, expression, expectedReturnType, expectedMessage, otherProperties);
}
/**
* Evaluate the specified expression and ensure the expected message comes out.
* The message may have inserts and they will be checked if otherProperties is specified.
* The first entry in otherProperties should always be the position.
* @param parser the expression parser to use
* @param expression the expression to evaluate
* @param expectedReturnType ask the expression return value to be of this type if possible
* ({@code null} indicates don't ask for conversion)
* @param expectedMessage the expected message
* @param otherProperties the expected inserts within the message
*/
protected void evaluateAndCheckError(ExpressionParser parser, String expression, Class<?> expectedReturnType, SpelMessage expectedMessage,
Object... otherProperties) {
assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() -> {
Expression expr = parser.parseExpression(expression);
assertThat(expr).as("expression").isNotNull();

View File

@ -77,6 +77,26 @@ class EvaluationTests extends AbstractExpressionTests {
evaluateAndCheckError(expression, String.class, SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED);
}
@Test
void maxExpressionLengthIsConfigurable() {
int maximumExpressionLength = 20_000;
String expression = "'%s'".formatted("Y".repeat(19_998));
assertThat(expression).hasSize(maximumExpressionLength);
SpelParserConfiguration configuration =
new SpelParserConfiguration(null, null, false, false, 0, maximumExpressionLength);
ExpressionParser parser = new SpelExpressionParser(configuration);
Expression expr = parser.parseExpression(expression);
String result = expr.getValue(String.class);
assertThat(result).hasSize(19_998);
expression = "'%s'".formatted("Y".repeat(25_000));
assertThat(expression).hasSize(25_002);
evaluateAndCheckError(parser, expression, String.class, SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED);
}
@Test
void createListsOnAttemptToIndexNull01() throws EvaluationException, ParseException {
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));