Browse Source

AntPathMatcher allows for case-insensitive matching

Issue: SPR-13286
pull/849/merge
Juergen Hoeller 11 years ago
parent
commit
291550a484
  1. 47
      spring-core/src/main/java/org/springframework/util/AntPathMatcher.java
  2. 25
      spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java

47
spring-core/src/main/java/org/springframework/util/AntPathMatcher.java

@ -79,6 +79,8 @@ public class AntPathMatcher implements PathMatcher { @@ -79,6 +79,8 @@ public class AntPathMatcher implements PathMatcher {
private PathSeparatorPatternCache pathSeparatorPatternCache;
private boolean caseSensitive = true;
private boolean trimTokens = true;
private volatile Boolean cachePatterns;
@ -117,6 +119,15 @@ public class AntPathMatcher implements PathMatcher { @@ -117,6 +119,15 @@ public class AntPathMatcher implements PathMatcher {
this.pathSeparatorPatternCache = new PathSeparatorPatternCache(this.pathSeparator);
}
/**
* Specify whether to perform pattern matching in a case-sensitive fashion.
* <p>Default is {@code true}. Switch this to {@code false} for case-insensitive matching.
* @since 4.2
*/
public void setCaseSensitive(boolean caseSensitive) {
this.caseSensitive = caseSensitive;
}
/**
* Specify whether to trim tokenized paths and patterns.
* <p>Default is {@code true}.
@ -134,6 +145,7 @@ public class AntPathMatcher implements PathMatcher { @@ -134,6 +145,7 @@ public class AntPathMatcher implements PathMatcher {
* turn it off when encountering too many patterns to cache at runtime
* (the threshold is 65536), assuming that arbitrary permutations of patterns
* are coming in, with little chance for encountering a recurring pattern.
* @since 4.0.1
* @see #getStringMatcher(String)
*/
public void setCachePatterns(boolean cachePatterns) {
@ -363,7 +375,7 @@ public class AntPathMatcher implements PathMatcher { @@ -363,7 +375,7 @@ public class AntPathMatcher implements PathMatcher {
matcher = this.stringMatcherCache.get(pattern);
}
if (matcher == null) {
matcher = new AntPathStringMatcher(pattern);
matcher = new AntPathStringMatcher(pattern, 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...
@ -418,7 +430,9 @@ public class AntPathMatcher implements PathMatcher { @@ -418,7 +430,9 @@ public class AntPathMatcher implements PathMatcher {
public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
Map<String, String> variables = new LinkedHashMap<String, String>();
boolean result = doMatch(pattern, path, true, variables);
Assert.state(result, "Pattern \"" + pattern + "\" is not a match for \"" + path + "\"");
if (!result) {
throw new IllegalStateException("Pattern \"" + pattern + "\" is not a match for \"" + path + "\"");
}
return variables;
}
@ -553,12 +567,16 @@ public class AntPathMatcher implements PathMatcher { @@ -553,12 +567,16 @@ public class AntPathMatcher implements PathMatcher {
private final List<String> variableNames = new LinkedList<String>();
public AntPathStringMatcher(String pattern) {
this(pattern, true);
}
public AntPathStringMatcher(String pattern, boolean caseSensitive) {
StringBuilder patternBuilder = new StringBuilder();
Matcher m = GLOB_PATTERN.matcher(pattern);
Matcher matcher = GLOB_PATTERN.matcher(pattern);
int end = 0;
while (m.find()) {
patternBuilder.append(quote(pattern, end, m.start()));
String match = m.group();
while (matcher.find()) {
patternBuilder.append(quote(pattern, end, matcher.start()));
String match = matcher.group();
if ("?".equals(match)) {
patternBuilder.append('.');
}
@ -569,7 +587,7 @@ public class AntPathMatcher implements PathMatcher { @@ -569,7 +587,7 @@ public class AntPathMatcher implements PathMatcher {
int colonIdx = match.indexOf(':');
if (colonIdx == -1) {
patternBuilder.append(DEFAULT_VARIABLE_PATTERN);
this.variableNames.add(m.group(1));
this.variableNames.add(matcher.group(1));
}
else {
String variablePattern = match.substring(colonIdx + 1, match.length() - 1);
@ -580,10 +598,11 @@ public class AntPathMatcher implements PathMatcher { @@ -580,10 +598,11 @@ public class AntPathMatcher implements PathMatcher {
this.variableNames.add(variableName);
}
}
end = m.end();
end = matcher.end();
}
patternBuilder.append(quote(pattern, end, pattern.length()));
this.pattern = Pattern.compile(patternBuilder.toString());
this.pattern = (caseSensitive ? Pattern.compile(patternBuilder.toString()) :
Pattern.compile(patternBuilder.toString(), Pattern.CASE_INSENSITIVE));
}
private String quote(String s, int start, int end) {
@ -602,10 +621,12 @@ public class AntPathMatcher implements PathMatcher { @@ -602,10 +621,12 @@ public class AntPathMatcher implements PathMatcher {
if (matcher.matches()) {
if (uriTemplateVariables != null) {
// SPR-8455
Assert.isTrue(this.variableNames.size() == matcher.groupCount(),
"The number of capturing groups in the pattern segment " + this.pattern +
" does not match the number of URI template variables it defines, which can occur if " +
" capturing groups are used in a URI template regex. Use non-capturing groups instead.");
if (this.variableNames.size() != matcher.groupCount()) {
throw new IllegalArgumentException("The number of capturing groups in the pattern segment " +
this.pattern + " does not match the number of URI template variables it defines, " +
"which can occur if capturing groups are used in a URI template regex. " +
"Use non-capturing groups instead.");
}
for (int i = 1; i <= matcher.groupCount(); i++) {
String name = this.variableNames.get(i - 1);
String value = matcher.group(i);

25
spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java

@ -298,7 +298,7 @@ public class AntPathMatcherTests { @@ -298,7 +298,7 @@ public class AntPathMatcherTests {
assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("*.html", "/docs/commit.html"));
assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("**/*.*", "/docs/commit.html"));
assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("*", "/docs/commit.html"));
//SPR-10515
// SPR-10515
assertEquals("/docs/cvs/other/commit.html", pathMatcher.extractPathWithinPattern("**/commit.html", "/docs/cvs/other/commit.html"));
assertEquals("cvs/other/commit.html", pathMatcher.extractPathWithinPattern("/docs/**/commit.html", "/docs/cvs/other/commit.html"));
assertEquals("cvs/other/commit.html", pathMatcher.extractPathWithinPattern("/docs/**/**/**/**", "/docs/cvs/other/commit.html"));
@ -452,7 +452,7 @@ public class AntPathMatcherTests { @@ -452,7 +452,7 @@ public class AntPathMatcherTests {
assertEquals(-1, comparator.compare("/hotels/{hotel}/booking", "/hotels/{hotel}/bookings/{booking}"));
assertEquals(1, comparator.compare("/hotels/{hotel}/bookings/{booking}", "/hotels/{hotel}/booking"));
//SPR-10550
// SPR-10550
assertEquals(-1, comparator.compare("/hotels/{hotel}/bookings/{booking}/cutomers/{customer}", "/**"));
assertEquals(1, comparator.compare("/**","/hotels/{hotel}/bookings/{booking}/cutomers/{customer}"));
assertEquals(0, comparator.compare("/**","/**"));
@ -466,7 +466,7 @@ public class AntPathMatcherTests { @@ -466,7 +466,7 @@ public class AntPathMatcherTests {
assertEquals(-1, comparator.compare("/hotels/new", "/hotels/new.*"));
assertEquals(2, comparator.compare("/hotels/{hotel}", "/hotels/{hotel}.*"));
//SPR-6741
// SPR-6741
assertEquals(-1, comparator.compare("/hotels/{hotel}/bookings/{booking}/cutomers/{customer}", "/hotels/**"));
assertEquals(1, comparator.compare("/hotels/**", "/hotels/{hotel}/bookings/{booking}/cutomers/{customer}"));
assertEquals(1, comparator.compare("/hotels/foo/bar/**", "/hotels/{hotel}"));
@ -474,13 +474,13 @@ public class AntPathMatcherTests { @@ -474,13 +474,13 @@ public class AntPathMatcherTests {
assertEquals(2, comparator.compare("/hotels/**/bookings/**", "/hotels/**"));
assertEquals(-2, comparator.compare("/hotels/**", "/hotels/**/bookings/**"));
//SPR-8683
// SPR-8683
assertEquals(1, comparator.compare("/**", "/hotels/{hotel}"));
// longer is better
assertEquals(1, comparator.compare("/hotels", "/hotels2"));
//SPR-13139
// SPR-13139
assertEquals(-1, comparator.compare("*", "*/**"));
assertEquals(1, comparator.compare("*/**", "*"));
}
@ -581,15 +581,22 @@ public class AntPathMatcherTests { @@ -581,15 +581,22 @@ public class AntPathMatcherTests {
paths.clear();
}
/**
* SPR-8687
*/
@Test
@Test // SPR-8687
public void trimTokensOff() {
pathMatcher.setTrimTokens(false);
assertTrue(pathMatcher.match("/group/{groupName}/members", "/group/sales/members"));
assertTrue(pathMatcher.match("/group/{groupName}/members", "/group/ sales/members"));
assertFalse(pathMatcher.match("/group/{groupName}/members", "/Group/ Sales/Members"));
}
@Test // SPR-13286
public void caseInsensitive() {
pathMatcher.setCaseSensitive(false);
assertTrue(pathMatcher.match("/group/{groupName}/members", "/group/sales/members"));
assertTrue(pathMatcher.match("/group/{groupName}/members", "/Group/Sales/Members"));
assertTrue(pathMatcher.match("/Group/{groupName}/Members", "/group/Sales/members"));
}
@Test

Loading…
Cancel
Save