diff --git a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java index 9f7a70af3f0..70bdbe0a104 100644 --- a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java +++ b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java @@ -725,7 +725,7 @@ public class AntPathMatcher implements PathMatcher { return this.caseSensitive ? this.rawPattern.equals(str) : this.rawPattern.equalsIgnoreCase(str); } else if (this.pattern != null) { - Matcher matcher = this.pattern.matcher(str); + Matcher matcher = this.pattern.matcher(new MaxAttemptsCharSequence(str)); if (matcher.matches()) { if (uriTemplateVariables != null) { if (this.variableNames.size() != matcher.groupCount()) { @@ -750,6 +750,60 @@ public class AntPathMatcher implements PathMatcher { return false; } + + private static class MaxAttemptsCharSequence implements CharSequence { + + private static final int MAX_ATTEMPTS = 1_000_000; + + private final String text; + + private final Counter counter; + + + MaxAttemptsCharSequence(String text) { + this(text, new Counter()); + } + + private MaxAttemptsCharSequence(String text, Counter counter) { + this.text = text; + this.counter = counter; + } + + + @Override + public int length() { + return this.text.length(); + } + + @Override + public char charAt(int index) { + if (this.counter.value++ >= MAX_ATTEMPTS) { + throw new IllegalStateException( + "Too many character access attempts encountered during pattern matching"); + } + return this.text.charAt(index); + } + + @Override + public boolean isEmpty() { + return this.text.isEmpty(); + } + + @Override + public CharSequence subSequence(int start, int end) { + return new MaxAttemptsCharSequence(this.text.substring(start, end), this.counter); + } + + @Override + public String toString() { + return this.text; + } + + + private static class Counter { + private int value; + } + } }