From 83fcdfba649498d28e4f4d685a07054ad2d4cfbe Mon Sep 17 00:00:00 2001 From: tafjwr <64597651+tafjwr@users.noreply.github.com> Date: Sat, 22 Jun 2024 18:16:31 +0900 Subject: [PATCH] Fix AntPathMatcher URI template variable extractor See gh-33085 --- .../springframework/util/AntPathMatcher.java | 16 +++++++--------- .../util/AntPathMatcherTests.java | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) 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 7f0544e1395..44faa2faf68 100644 --- a/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java +++ b/spring-core/src/main/java/org/springframework/util/AntPathMatcher.java @@ -462,7 +462,7 @@ public class AntPathMatcher implements PathMatcher { matcher = this.stringMatcherCache.get(pattern); } if (matcher == null) { - matcher = new AntPathStringMatcher(pattern, this.caseSensitive); + matcher = new AntPathStringMatcher(pattern, this.pathSeparator, this.caseSensitive); if (cachePatterns == null && this.stringMatcherCache.size() >= CACHE_TURNOFF_THRESHOLD) { // Try to adapt to the runtime situation that we're encountering: // There are obviously too many different patterns coming in here... @@ -646,8 +646,6 @@ public class AntPathMatcher implements PathMatcher { */ protected static class AntPathStringMatcher { - private static final Pattern GLOB_PATTERN = Pattern.compile("\\?|\\*|\\{((?:\\{[^/]+?\\}|[^/{}]|\\\\[{}])+?)\\}"); - private static final String DEFAULT_VARIABLE_PATTERN = "((?s).*)"; private final String rawPattern; @@ -661,15 +659,11 @@ public class AntPathMatcher implements PathMatcher { private final List variableNames = new ArrayList<>(); - public AntPathStringMatcher(String pattern) { - this(pattern, true); - } - - public AntPathStringMatcher(String pattern, boolean caseSensitive) { + public AntPathStringMatcher(String pattern, String pathSeparator, boolean caseSensitive) { this.rawPattern = pattern; this.caseSensitive = caseSensitive; StringBuilder patternBuilder = new StringBuilder(); - Matcher matcher = GLOB_PATTERN.matcher(pattern); + Matcher matcher = getGlobPattern(pathSeparator).matcher(pattern); int end = 0; while (matcher.find()) { patternBuilder.append(quote(pattern, end, matcher.start())); @@ -710,6 +704,10 @@ public class AntPathMatcher implements PathMatcher { } } + private static Pattern getGlobPattern(String pathSeparator) { + return Pattern.compile(String.format("\\?|\\*|\\{((?:\\{[^%s]+?\\}|[^%s{}]|\\\\[{}])+?)\\}", pathSeparator, pathSeparator)); + } + private String quote(String s, int start, int end) { if (start == end) { return ""; diff --git a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java index ee33545735b..032971e6fe3 100644 --- a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java +++ b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java @@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException class AntPathMatcherTests { private final AntPathMatcher pathMatcher = new AntPathMatcher(); + private final AntPathMatcher dotSeparatedPathMatcher = new AntPathMatcher("."); @Test @@ -357,6 +358,24 @@ class AntPathMatcherTests { assertThat(result).isEqualTo(expected); } + @Test // gh-26264 + void extractUriTemplateVariablesFromDotSeparatedPath() { + Map result = dotSeparatedPathMatcher.extractUriTemplateVariables("price.stock.{tickerSymbol}", "price.stock.aaa"); + assertThat(result).isEqualTo(Collections.singletonMap("tickerSymbol", "aaa")); + + result = dotSeparatedPathMatcher.extractUriTemplateVariables("price.stock.{ticker/symbol}", "price.stock.aaa"); + assertThat(result).isEqualTo(Collections.singletonMap("ticker/symbol", "aaa")); + + result = dotSeparatedPathMatcher.extractUriTemplateVariables("notification.**.{operation}", "notification.foo.update"); + assertThat(result).isEqualTo(Collections.singletonMap("operation", "update")); + + result = dotSeparatedPathMatcher.extractUriTemplateVariables("news.sports.feed/{type}", "news.sports.feed/xml"); + assertThat(result).isEqualTo(Collections.singletonMap("type", "xml")); + + result = dotSeparatedPathMatcher.extractUriTemplateVariables("news.sports.{operation}/*", "news.sports.feed/xml"); + assertThat(result).isEqualTo(Collections.singletonMap("operation", "feed")); + } + @Test void extractUriTemplateVariablesRegex() { Map result = pathMatcher