From 09b62d3e3b9e18c95a141d607b60d23aac403a04 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 --- .../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 7f0544e13954..44faa2faf68a 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 @@ protected AntPathStringMatcher getStringMatcher(String pattern) { 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 Comparator getPatternComparator(String path) { */ 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 @@ protected static class AntPathStringMatcher { 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 @@ else if (match.startsWith("{") && match.endsWith("}")) { } } + 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 ee33545735b4..032971e6fe3f 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 @@ class AntPathMatcherTests { private final AntPathMatcher pathMatcher = new AntPathMatcher(); + private final AntPathMatcher dotSeparatedPathMatcher = new AntPathMatcher("."); @Test @@ -357,6 +358,24 @@ void extractUriTemplateVariables() { 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