From d9245382112ee7923ba615222b7e6e1f7cfeda21 Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Sun, 19 Feb 2017 17:06:49 -0800 Subject: [PATCH] Fix RegexPathElement when matching variables against a root path The first fix for issue 15264 covered the case of using a single variable (the case mentioned in the bug report). However, when more than one variable is used a different PathElement is built. This RegexPathElement needs a similar change that checks the path includes data to bind. Issue: SPR-15264 --- .../web/util/patterns/RegexPathElement.java | 4 ++- .../patterns/PathPatternMatcherTests.java | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/spring-web/src/main/java/org/springframework/web/util/patterns/RegexPathElement.java b/spring-web/src/main/java/org/springframework/web/util/patterns/RegexPathElement.java index fe6a8a6424..810120a158 100644 --- a/spring-web/src/main/java/org/springframework/web/util/patterns/RegexPathElement.java +++ b/spring-web/src/main/java/org/springframework/web/util/patterns/RegexPathElement.java @@ -125,7 +125,9 @@ class RegexPathElement extends PathElement { if (matches) { if (next == null) { // No more pattern, is there more data? - matches = (p == matchingContext.candidateLength); + // If pattern is capturing variables there must be some actual data to bind to them + matches = (p == matchingContext.candidateLength && + ((this.variableNames.size() == 0) ? true : p > candidateIndex)); } else { if (matchingContext.isMatchStartMatching && p == matchingContext.candidateLength) { diff --git a/spring-web/src/test/java/org/springframework/web/util/patterns/PathPatternMatcherTests.java b/spring-web/src/test/java/org/springframework/web/util/patterns/PathPatternMatcherTests.java index 674d5aba9b..3ea0f60e72 100644 --- a/spring-web/src/test/java/org/springframework/web/util/patterns/PathPatternMatcherTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/patterns/PathPatternMatcherTests.java @@ -26,6 +26,7 @@ import java.util.Map; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.springframework.util.AntPathMatcher; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; @@ -524,12 +525,40 @@ public class PathPatternMatcherTests { assertTrue(pp.matches("/abc/boo")); assertTrue(pp.matches("/a/boo")); assertFalse(pp.matches("//boo")); + + pp = parse("/{foo}*"); + assertTrue(pp.matches("/abc")); + assertFalse(pp.matches("/")); checkCapture("/{word:[a-z]*}", "/abc", "word", "abc"); pp = parse("/{word:[a-z]*}"); assertFalse(pp.matches("/1")); assertTrue(pp.matches("/a")); assertFalse(pp.matches("/")); + + // Two captures mean we use a RegexPathElement + pp = new PathPatternParser().parse("/{foo}{bar}"); + assertTrue(pp.matches("/abcdef")); + assertFalse(pp.matches("/")); + assertFalse(pp.matches("//")); + checkCapture("/{foo:[a-z][a-z]}{bar:[a-z]}", "/abc", "foo", "ab", "bar", "c"); + + // Only patterns not capturing variables cannot match against just / + pp = new PathPatternParser().parse("/****"); + assertTrue(pp.matches("/abcdef")); + assertTrue(pp.matches("/")); + assertTrue(pp.matches("//")); + + // Confirming AntPathMatcher behaviour: + assertFalse(new AntPathMatcher().match("/{foo}", "/")); + assertTrue(new AntPathMatcher().match("/{foo}", "/a")); + assertTrue(new AntPathMatcher().match("/{foo}{bar}", "/a")); + assertFalse(new AntPathMatcher().match("/{foo}*", "/")); + assertTrue(new AntPathMatcher().match("/*", "/")); + assertFalse(new AntPathMatcher().match("/*{foo}", "/")); + Map vars = new AntPathMatcher().extractUriTemplateVariables("/{foo}{bar}", "/a"); + assertEquals("a",vars.get("foo")); + assertEquals("",vars.get("bar")); } @Test