From 777f01d7862a026d6f6a45653ed66c1c869a512f Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Mon, 19 Dec 2022 10:15:39 +0100 Subject: [PATCH] Fix path within mapping when pattern contains ".*" Prior to this commit, extracting the path within handler mapping would result in "" if the matching path element would be a Regex and contain ".*". This could cause issues with resource handling if the handler mapping pattern was similar to `"/folder/file.*.extension"`. This commit introduces a new `isLiteral()` method in the `PathElement` abstract class that expresses whether the path element can be compared as a String for path matching or if it requires a more elaborate matching process. Using this method for extracting the path within handler mapping avoids relying on wildcard count or other properties. See gh-29712 Fixes gh-29716 --- .../web/util/pattern/LiteralPathElement.java | 4 ++++ .../springframework/web/util/pattern/PathElement.java | 9 +++++++++ .../springframework/web/util/pattern/PathPattern.java | 2 +- .../web/util/pattern/SeparatorPathElement.java | 4 ++++ .../web/util/pattern/PathPatternTests.java | 1 + 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java index 6c6249df130..16af8d8ed78 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/LiteralPathElement.java @@ -118,6 +118,10 @@ class LiteralPathElement extends PathElement { return this.text; } + @Override + public boolean isLiteral() { + return true; + } @Override public String toString() { diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java index df433017264..699b7bec14b 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/PathElement.java @@ -25,6 +25,7 @@ import org.springframework.web.util.pattern.PathPattern.MatchingContext; * Common supertype for the Ast nodes created to represent a path pattern. * * @author Andy Clement + * @author Brian Clozel * @since 5.0 */ abstract class PathElement { @@ -99,6 +100,14 @@ abstract class PathElement { return 0; } + /** + * Return whether this PathElement can be strictly {@link String#compareTo(String) compared} + * against another element for matching. + */ + public boolean isLiteral() { + return false; + } + /** * Return if the there are no more PathElements in the pattern. * @return {@code true} if the there are no more elements diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java b/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java index 8b5aee9223c..dcf7382bd52 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/PathPattern.java @@ -303,7 +303,7 @@ public class PathPattern implements Comparable { // Find first path element that is not a separator or a literal (i.e. the first pattern based element) PathElement elem = this.head; while (elem != null) { - if (elem.getWildcardCount() != 0 || elem.getCaptureCount() != 0) { + if (!elem.isLiteral()) { break; } elem = elem.next; diff --git a/spring-web/src/main/java/org/springframework/web/util/pattern/SeparatorPathElement.java b/spring-web/src/main/java/org/springframework/web/util/pattern/SeparatorPathElement.java index b140e88b44e..b6ba087bfb6 100644 --- a/spring-web/src/main/java/org/springframework/web/util/pattern/SeparatorPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/pattern/SeparatorPathElement.java @@ -67,6 +67,10 @@ class SeparatorPathElement extends PathElement { return new char[] {this.separator}; } + @Override + public boolean isLiteral() { + return true; + } @Override public String toString() { diff --git a/spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternTests.java b/spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternTests.java index 97aad62e622..eab9bfd7bcc 100644 --- a/spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/pattern/PathPatternTests.java @@ -684,6 +684,7 @@ public class PathPatternTests { checkExtractPathWithinPattern("/docs/commit.html", "/docs/commit.html", ""); checkExtractPathWithinPattern("/docs/*", "/docs/cvs/commit", "cvs/commit"); checkExtractPathWithinPattern("/docs/cvs/*.html", "/docs/cvs/commit.html", "commit.html"); + checkExtractPathWithinPattern("/docs/cvs/file.*.html", "/docs/cvs/file.sha.html", "file.sha.html"); checkExtractPathWithinPattern("/docs/**", "/docs/cvs/commit", "cvs/commit"); checkExtractPathWithinPattern("/doo/{*foobar}", "/doo/customer.html", "customer.html"); checkExtractPathWithinPattern("/doo/{*foobar}", "/doo/daa/customer.html", "daa/customer.html");