WebFlux compiles after PathPattern/Container changes
This commit is contained in:
parent
26448a0ebc
commit
8581afa621
|
|
@ -19,10 +19,10 @@ package org.springframework.web.util.pattern;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.http.server.reactive.PathContainer;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
|
@ -79,20 +79,18 @@ public class ParsingPathMatcher implements PathMatcher {
|
|||
@Override
|
||||
public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
|
||||
PathPattern pathPattern = getPathPattern(pattern);
|
||||
Map<String, PathMatchResult> results = pathPattern.matchAndExtract(PathContainer.parse(path, StandardCharsets.UTF_8));
|
||||
// Collapse PathMatchResults to simple value results (path parameters are lost in this translation)
|
||||
Map<String, String> boundVariables = null;
|
||||
if (results.size() == 0) {
|
||||
boundVariables = Collections.emptyMap();
|
||||
PathContainer pathContainer = PathContainer.parse(path, StandardCharsets.UTF_8);
|
||||
PathMatchResult results = pathPattern.matchAndExtract(pathContainer);
|
||||
// Collapse PathMatchResults to simple value results
|
||||
// TODO: (path parameters are lost in this translation)
|
||||
if (results.getUriVariables().size() == 0) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
boundVariables = new LinkedHashMap<>();
|
||||
for (Map.Entry<String,PathMatchResult> entries: results.entrySet()) {
|
||||
boundVariables.put(entries.getKey(), entries.getValue().value());
|
||||
return results.getUriVariables().entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
}
|
||||
return boundVariables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparator<String> getPatternComparator(String path) {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import org.springframework.http.server.reactive.PathContainer.Element;
|
|||
import org.springframework.http.server.reactive.PathContainer.Segment;
|
||||
import org.springframework.http.server.reactive.PathContainer.Separator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
|
@ -155,6 +156,26 @@ public class PathPattern implements Comparable<PathPattern> {
|
|||
return this.patternString;
|
||||
}
|
||||
|
||||
|
||||
// TODO: remove String-variants
|
||||
|
||||
public boolean matches(String path) {
|
||||
return matches(PathContainer.parse(path, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public PathMatchResult matchAndExtract(String path) {
|
||||
return matchAndExtract(PathContainer.parse(path, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PathRemainingMatchInfo getPathRemaining(@Nullable String path) {
|
||||
return getPathRemaining(path != null ?
|
||||
PathContainer.parse(path, StandardCharsets.UTF_8) : null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param pathContainer the candidate path container to attempt to match against this pattern
|
||||
* @return true if the path matches this pattern
|
||||
|
|
@ -199,11 +220,11 @@ public class PathPattern implements Comparable<PathPattern> {
|
|||
else {
|
||||
PathRemainingMatchInfo info;
|
||||
if (matchingContext.remainingPathIndex == pathContainer.elements().size()) {
|
||||
info = new PathRemainingMatchInfo(EMPTY_PATH, matchingContext.getExtractedVariables());
|
||||
info = new PathRemainingMatchInfo(EMPTY_PATH, matchingContext.getPathMatchResult());
|
||||
}
|
||||
else {
|
||||
info = new PathRemainingMatchInfo(PathContainer.subPath(pathContainer, matchingContext.remainingPathIndex),
|
||||
matchingContext.getExtractedVariables());
|
||||
matchingContext.getPathMatchResult());
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
|
@ -230,13 +251,13 @@ public class PathPattern implements Comparable<PathPattern> {
|
|||
* @return a map of extracted variables - an empty map if no variables extracted.
|
||||
* @throws IllegalStateException if the path does not match the pattern
|
||||
*/
|
||||
public Map<String, PathMatchResult> matchAndExtract(PathContainer pathContainer) {
|
||||
public PathMatchResult matchAndExtract(PathContainer pathContainer) {
|
||||
MatchingContext matchingContext = new MatchingContext(pathContainer, true);
|
||||
if (this.head != null && this.head.matches(0, matchingContext)) {
|
||||
return matchingContext.getExtractedVariables();
|
||||
return matchingContext.getPathMatchResult();
|
||||
}
|
||||
else if (!hasLength(pathContainer)) {
|
||||
return Collections.emptyMap();
|
||||
return PathMatchResult.EMPTY;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Pattern \"" + this + "\" is not a match for \"" + pathContainer.value() + "\"");
|
||||
|
|
@ -447,45 +468,46 @@ public class PathPattern implements Comparable<PathPattern> {
|
|||
return this.patternString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents the result of a successful variable match. This holds the key that matched, the
|
||||
* value that was found for that key and, if any, the parameters attached to that path element.
|
||||
* For example: "/{var}" against "/foo;a=b" will return a PathMathResult with 'key=var',
|
||||
* 'value=foo' and parameters 'a=b'.
|
||||
* Represents the result of a successful path match. This holds the keys that matched, the
|
||||
* values that were found for each key and, if any, the path parameters (matrix variables)
|
||||
* attached to that path element.
|
||||
* For example: "/{var}" against "/foo;a=b" will return a PathMathResult with 'foo=bar'
|
||||
* for URI variables and 'a=b' as path parameters for 'foo'.
|
||||
*/
|
||||
public static class PathMatchResult {
|
||||
|
||||
private final String key;
|
||||
private static final PathMatchResult EMPTY =
|
||||
new PathMatchResult(Collections.emptyMap(), Collections.emptyMap());
|
||||
|
||||
private final String value;
|
||||
|
||||
private final MultiValueMap<String,String> parameters;
|
||||
private final Map<String, String> uriVariables;
|
||||
|
||||
public PathMatchResult(String key, String value, MultiValueMap<String, String> parameters) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.parameters = parameters;
|
||||
private final Map<String, MultiValueMap<String, String>> matrixVariables;
|
||||
|
||||
|
||||
public PathMatchResult(Map<String, String> uriVars,
|
||||
@Nullable Map<String, MultiValueMap<String, String>> matrixVars) {
|
||||
|
||||
this.uriVariables = Collections.unmodifiableMap(uriVars);
|
||||
this.matrixVariables = matrixVars != null ?
|
||||
Collections.unmodifiableMap(matrixVars) : Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return match result key
|
||||
*/
|
||||
public String key() {
|
||||
return key;
|
||||
|
||||
public Map<String, String> getUriVariables() {
|
||||
return this.uriVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return match result value
|
||||
*/
|
||||
public String value() {
|
||||
return this.value;
|
||||
public Map<String, MultiValueMap<String, String>> getMatrixVariables() {
|
||||
return this.matrixVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return match result parameters (empty map if no parameters)
|
||||
*/
|
||||
public MultiValueMap<String,String> parameters() {
|
||||
return this.parameters;
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathMatchResult[uriVariables=" + this.uriVariables + ", " +
|
||||
"matrixVariables=" + this.matrixVariables + "]";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -498,15 +520,15 @@ public class PathPattern implements Comparable<PathPattern> {
|
|||
|
||||
private final PathContainer pathRemaining;
|
||||
|
||||
private final Map<String, PathMatchResult> matchingVariables;
|
||||
private final PathMatchResult pathMatchResult;
|
||||
|
||||
PathRemainingMatchInfo(@Nullable PathContainer pathRemaining) {
|
||||
this(pathRemaining, Collections.emptyMap());
|
||||
this(pathRemaining, PathMatchResult.EMPTY);
|
||||
}
|
||||
|
||||
PathRemainingMatchInfo(@Nullable PathContainer pathRemaining, Map<String, PathMatchResult> matchingVariables) {
|
||||
PathRemainingMatchInfo(@Nullable PathContainer pathRemaining, PathMatchResult pathMatchResult) {
|
||||
this.pathRemaining = pathRemaining;
|
||||
this.matchingVariables = matchingVariables;
|
||||
this.pathMatchResult = pathMatchResult;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -520,8 +542,15 @@ public class PathPattern implements Comparable<PathPattern> {
|
|||
* Return variables that were bound in the part of the path that was successfully matched.
|
||||
* Will be an empty map if no variables were bound
|
||||
*/
|
||||
public Map<String, PathMatchResult> getMatchingVariables() {
|
||||
return this.matchingVariables;
|
||||
public Map<String, String> getUriVariables() {
|
||||
return this.pathMatchResult.getUriVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path parameters for each bound variable.
|
||||
*/
|
||||
public Map<String, MultiValueMap<String, String>> getMatrixVariables() {
|
||||
return this.pathMatchResult.getMatrixVariables();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -595,7 +624,10 @@ public class PathPattern implements Comparable<PathPattern> {
|
|||
boolean isMatchStartMatching = false;
|
||||
|
||||
@Nullable
|
||||
private Map<String, PathMatchResult> extractedVariables;
|
||||
private Map<String, String> extractedUriVariables;
|
||||
|
||||
@Nullable
|
||||
private Map<String, MultiValueMap<String, String>> extractedMatrixVariables;
|
||||
|
||||
boolean extractingVariables;
|
||||
|
||||
|
|
@ -626,18 +658,25 @@ public class PathPattern implements Comparable<PathPattern> {
|
|||
}
|
||||
|
||||
public void set(String key, String value, MultiValueMap<String,String> parameters) {
|
||||
if (this.extractedVariables == null) {
|
||||
extractedVariables = new HashMap<>();
|
||||
if (this.extractedUriVariables == null) {
|
||||
this.extractedUriVariables = new HashMap<>();
|
||||
}
|
||||
this.extractedUriVariables.put(key, value);
|
||||
|
||||
if (!parameters.isEmpty()) {
|
||||
if (this.extractedMatrixVariables == null) {
|
||||
this.extractedMatrixVariables = new HashMap<>();
|
||||
}
|
||||
this.extractedMatrixVariables.put(key, CollectionUtils.unmodifiableMultiValueMap(parameters));
|
||||
}
|
||||
extractedVariables.put(key, new PathMatchResult(key, value, parameters));
|
||||
}
|
||||
|
||||
public Map<String, PathMatchResult> getExtractedVariables() {
|
||||
if (this.extractedVariables == null) {
|
||||
return Collections.emptyMap();
|
||||
public PathMatchResult getPathMatchResult() {
|
||||
if (this.extractedUriVariables == null) {
|
||||
return PathMatchResult.EMPTY;
|
||||
}
|
||||
else {
|
||||
return this.extractedVariables;
|
||||
return new PathMatchResult(this.extractedUriVariables, this.extractedMatrixVariables);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,17 +29,20 @@ import org.junit.Ignore;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.http.server.reactive.PathContainer;
|
||||
import org.springframework.http.server.reactive.PathContainer.Element;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.util.pattern.ParsingPathMatcher;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPattern.PathMatchResult;
|
||||
import org.springframework.web.util.pattern.PathPattern.PathRemainingMatchInfo;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Exercise matching of {@link PathPattern} objects.
|
||||
|
|
@ -125,26 +128,26 @@ public class PathPatternMatcherTests {
|
|||
// CaptureVariablePathElement
|
||||
pp = parse("/{var}");
|
||||
assertMatches(pp,"/resource");
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource")).get("var").value());
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource")).getUriVariables().get("var"));
|
||||
assertMatches(pp,"/resource/");
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
|
||||
assertNoMatch(pp,"/resource//");
|
||||
pp = parse("/{var}/");
|
||||
assertNoMatch(pp,"/resource");
|
||||
assertMatches(pp,"/resource/");
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
|
||||
assertNoMatch(pp,"/resource//");
|
||||
|
||||
// CaptureTheRestPathElement
|
||||
pp = parse("/{*var}");
|
||||
assertMatches(pp,"/resource");
|
||||
assertEquals("/resource",pp.matchAndExtract(toPathContainer("/resource")).get("var").value());
|
||||
assertEquals("/resource",pp.matchAndExtract(toPathContainer("/resource")).getUriVariables().get("var"));
|
||||
assertMatches(pp,"/resource/");
|
||||
assertEquals("/resource/",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
|
||||
assertEquals("/resource/",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
|
||||
assertMatches(pp,"/resource//");
|
||||
assertEquals("/resource//",pp.matchAndExtract(toPathContainer("/resource//")).get("var").value());
|
||||
assertEquals("/resource//",pp.matchAndExtract(toPathContainer("/resource//")).getUriVariables().get("var"));
|
||||
assertMatches(pp,"//resource//");
|
||||
assertEquals("//resource//",pp.matchAndExtract(toPathContainer("//resource//")).get("var").value());
|
||||
assertEquals("//resource//",pp.matchAndExtract(toPathContainer("//resource//")).getUriVariables().get("var"));
|
||||
|
||||
// WildcardTheRestPathElement
|
||||
pp = parse("/**");
|
||||
|
|
@ -166,17 +169,17 @@ public class PathPatternMatcherTests {
|
|||
// RegexPathElement
|
||||
pp = parse("/{var1}_{var2}");
|
||||
assertMatches(pp,"/res1_res2");
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2")).get("var1").value());
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2")).get("var2").value());
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2")).getUriVariables().get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2")).getUriVariables().get("var2"));
|
||||
assertMatches(pp,"/res1_res2/");
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var1").value());
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var2").value());
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var2"));
|
||||
assertNoMatch(pp,"/res1_res2//");
|
||||
pp = parse("/{var1}_{var2}/");
|
||||
assertNoMatch(pp,"/res1_res2");
|
||||
assertMatches(pp,"/res1_res2/");
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var1").value());
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var2").value());
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var2"));
|
||||
assertNoMatch(pp,"/res1_res2//");
|
||||
pp = parse("/{var1}*");
|
||||
assertMatches(pp,"/a");
|
||||
|
|
@ -210,25 +213,25 @@ public class PathPatternMatcherTests {
|
|||
// CaptureVariablePathElement
|
||||
pp = parser.parse("/{var}");
|
||||
assertMatches(pp,"/resource");
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource")).get("var").value());
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource")).getUriVariables().get("var"));
|
||||
assertNoMatch(pp,"/resource/");
|
||||
assertNoMatch(pp,"/resource//");
|
||||
pp = parser.parse("/{var}/");
|
||||
assertNoMatch(pp,"/resource");
|
||||
assertMatches(pp,"/resource/");
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
|
||||
assertEquals("resource",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
|
||||
assertNoMatch(pp,"/resource//");
|
||||
|
||||
// CaptureTheRestPathElement
|
||||
pp = parser.parse("/{*var}");
|
||||
assertMatches(pp,"/resource");
|
||||
assertEquals("/resource",pp.matchAndExtract(toPathContainer("/resource")).get("var").value());
|
||||
assertEquals("/resource",pp.matchAndExtract(toPathContainer("/resource")).getUriVariables().get("var"));
|
||||
assertMatches(pp,"/resource/");
|
||||
assertEquals("/resource/",pp.matchAndExtract(toPathContainer("/resource/")).get("var").value());
|
||||
assertEquals("/resource/",pp.matchAndExtract(toPathContainer("/resource/")).getUriVariables().get("var"));
|
||||
assertMatches(pp,"/resource//");
|
||||
assertEquals("/resource//",pp.matchAndExtract(toPathContainer("/resource//")).get("var").value());
|
||||
assertEquals("/resource//",pp.matchAndExtract(toPathContainer("/resource//")).getUriVariables().get("var"));
|
||||
assertMatches(pp,"//resource//");
|
||||
assertEquals("//resource//",pp.matchAndExtract(toPathContainer("//resource//")).get("var").value());
|
||||
assertEquals("//resource//",pp.matchAndExtract(toPathContainer("//resource//")).getUriVariables().get("var"));
|
||||
|
||||
// WildcardTheRestPathElement
|
||||
pp = parser.parse("/**");
|
||||
|
|
@ -250,15 +253,15 @@ public class PathPatternMatcherTests {
|
|||
// RegexPathElement
|
||||
pp = parser.parse("/{var1}_{var2}");
|
||||
assertMatches(pp,"/res1_res2");
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2")).get("var1").value());
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2")).get("var2").value());
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2")).getUriVariables().get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2")).getUriVariables().get("var2"));
|
||||
assertNoMatch(pp,"/res1_res2/");
|
||||
assertNoMatch(pp,"/res1_res2//");
|
||||
pp = parser.parse("/{var1}_{var2}/");
|
||||
assertNoMatch(pp,"/res1_res2");
|
||||
assertMatches(pp,"/res1_res2/");
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var1").value());
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).get("var2").value());
|
||||
assertEquals("res1",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var1"));
|
||||
assertEquals("res2",pp.matchAndExtract(toPathContainer("/res1_res2/")).getUriVariables().get("var2"));
|
||||
assertNoMatch(pp,"/res1_res2//");
|
||||
pp = parser.parse("/{var1}*");
|
||||
assertMatches(pp,"/a");
|
||||
|
|
@ -337,23 +340,23 @@ public class PathPatternMatcherTests {
|
|||
|
||||
PathPattern.PathRemainingMatchInfo pri = parse("/aaa/{bbb}/c?d/e*f/*/g").getPathRemaining(toPathContainer("/aaa/b/ccd/ef/x/g/i"));
|
||||
assertEquals("/i",pri.getPathRemaining());
|
||||
assertEquals("b",pri.getMatchingVariables().get("bbb").value());
|
||||
assertEquals("b",pri.getUriVariables().get("bbb"));
|
||||
|
||||
pri = parse("/aaa/{bbb}/c?d/e*f/*/g/").getPathRemaining(toPathContainer("/aaa/b/ccd/ef/x/g/i"));
|
||||
assertEquals("i",pri.getPathRemaining());
|
||||
assertEquals("b",pri.getMatchingVariables().get("bbb").value());
|
||||
assertEquals("b",pri.getUriVariables().get("bbb"));
|
||||
|
||||
pri = parse("/{aaa}_{bbb}/e*f/{x}/g").getPathRemaining(toPathContainer("/aa_bb/ef/x/g/i"));
|
||||
assertEquals("/i",pri.getPathRemaining());
|
||||
assertEquals("aa",pri.getMatchingVariables().get("aaa").value());
|
||||
assertEquals("bb",pri.getMatchingVariables().get("bbb").value());
|
||||
assertEquals("x",pri.getMatchingVariables().get("x").value());
|
||||
assertEquals("aa",pri.getUriVariables().get("aaa"));
|
||||
assertEquals("bb",pri.getUriVariables().get("bbb"));
|
||||
assertEquals("x",pri.getUriVariables().get("x"));
|
||||
|
||||
assertNull(parse("/a/b").getPathRemaining(toPathContainer("")));
|
||||
assertNull(parse("/a/b").getPathRemaining(null));
|
||||
assertNull(parse("/a/b").getPathRemaining((String) null));
|
||||
assertEquals("/a/b",parse("").getPathRemaining(toPathContainer("/a/b")).getPathRemaining());
|
||||
assertEquals("",parse("").getPathRemaining(toPathContainer("")).getPathRemaining());
|
||||
assertNull(parse("").getPathRemaining(null).getPathRemaining());
|
||||
assertNull(parse("").getPathRemaining((String) null).getPathRemaining());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -550,30 +553,30 @@ public class PathPatternMatcherTests {
|
|||
pp = parse("/{this}/{one}/{here}");
|
||||
pri = getPathRemaining(pp, "/foo/bar/goo/boo");
|
||||
assertEquals("/boo",pri.getPathRemaining());
|
||||
assertEquals("foo",pri.getMatchingVariables().get("this").value());
|
||||
assertEquals("bar",pri.getMatchingVariables().get("one").value());
|
||||
assertEquals("goo",pri.getMatchingVariables().get("here").value());
|
||||
assertEquals("foo",pri.getUriVariables().get("this"));
|
||||
assertEquals("bar",pri.getUriVariables().get("one"));
|
||||
assertEquals("goo",pri.getUriVariables().get("here"));
|
||||
|
||||
pp = parse("/aaa/{foo}");
|
||||
pri = getPathRemaining(pp, "/aaa/bbb");
|
||||
assertEquals("",pri.getPathRemaining());
|
||||
assertEquals("bbb",pri.getMatchingVariables().get("foo").value());
|
||||
assertEquals("bbb",pri.getUriVariables().get("foo"));
|
||||
|
||||
pp = parse("/aaa/bbb");
|
||||
pri = getPathRemaining(pp, "/aaa/bbb");
|
||||
assertEquals("",pri.getPathRemaining());
|
||||
assertEquals(0,pri.getMatchingVariables().size());
|
||||
assertEquals(0,pri.getUriVariables().size());
|
||||
|
||||
pp = parse("/*/{foo}/b*");
|
||||
pri = getPathRemaining(pp, "/foo");
|
||||
assertNull(pri);
|
||||
pri = getPathRemaining(pp, "/abc/def/bhi");
|
||||
assertEquals("",pri.getPathRemaining());
|
||||
assertEquals("def",pri.getMatchingVariables().get("foo").value());
|
||||
assertEquals("def",pri.getUriVariables().get("foo"));
|
||||
|
||||
pri = getPathRemaining(pp, "/abc/def/bhi/jkl");
|
||||
assertEquals("/jkl",pri.getPathRemaining());
|
||||
assertEquals("def",pri.getMatchingVariables().get("foo").value());
|
||||
assertEquals("def",pri.getUriVariables().get("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -953,7 +956,7 @@ public class PathPatternMatcherTests {
|
|||
catch (IllegalStateException e) {
|
||||
assertEquals("Pattern \"\" is not a match for \"/abc\"", e.getMessage());
|
||||
}
|
||||
assertEquals(0, checkCapture("", "").size());
|
||||
assertEquals(0, checkCapture("", "").getUriVariables().size());
|
||||
checkCapture("{id}", "99", "id", "99");
|
||||
checkCapture("/customer/{customerId}", "/customer/78", "customerId", "78");
|
||||
checkCapture("/customer/{customerId}/banana", "/customer/42/banana", "customerId",
|
||||
|
|
@ -962,8 +965,8 @@ public class PathPatternMatcherTests {
|
|||
checkCapture("/foo/{bar}/boo/{baz}", "/foo/plum/boo/apple", "bar", "plum", "baz",
|
||||
"apple");
|
||||
checkCapture("/{bla}.*", "/testing.html", "bla", "testing");
|
||||
Map<String, PathMatchResult> extracted = checkCapture("/abc", "/abc");
|
||||
assertEquals(0, extracted.size());
|
||||
PathMatchResult extracted = checkCapture("/abc", "/abc");
|
||||
assertEquals(0, extracted.getUriVariables().size());
|
||||
checkCapture("/{bla}/foo","/a/foo");
|
||||
}
|
||||
|
||||
|
|
@ -973,14 +976,14 @@ public class PathPatternMatcherTests {
|
|||
PathPattern p = null;
|
||||
|
||||
p = pp.parse("{symbolicName:[\\w\\.]+}-{version:[\\w\\.]+}.jar");
|
||||
Map<String, PathMatchResult> result = matchAndExtract(p, "com.example-1.0.0.jar");
|
||||
assertEquals("com.example", result.get("symbolicName").value());
|
||||
assertEquals("1.0.0", result.get("version").value());
|
||||
PathMatchResult result = matchAndExtract(p, "com.example-1.0.0.jar");
|
||||
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
|
||||
assertEquals("1.0.0", result.getUriVariables().get("version"));
|
||||
|
||||
p = pp.parse("{symbolicName:[\\w\\.]+}-sources-{version:[\\w\\.]+}.jar");
|
||||
result = matchAndExtract(p, "com.example-sources-1.0.0.jar");
|
||||
assertEquals("com.example", result.get("symbolicName").value());
|
||||
assertEquals("1.0.0", result.get("version").value());
|
||||
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
|
||||
assertEquals("1.0.0", result.getUriVariables().get("version"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -988,22 +991,22 @@ public class PathPatternMatcherTests {
|
|||
PathPatternParser pp = new PathPatternParser();
|
||||
|
||||
PathPattern p = pp.parse("{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.]+}.jar");
|
||||
Map<String, PathMatchResult> result = p.matchAndExtract(toPathContainer("com.example-sources-1.0.0.jar"));
|
||||
assertEquals("com.example", result.get("symbolicName").value());
|
||||
assertEquals("1.0.0", result.get("version").value());
|
||||
PathMatchResult result = p.matchAndExtract(toPathContainer("com.example-sources-1.0.0.jar"));
|
||||
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
|
||||
assertEquals("1.0.0", result.getUriVariables().get("version"));
|
||||
|
||||
p = pp.parse("{symbolicName:[\\w\\.]+}-sources-{version:[\\d\\.]+}-{year:\\d{4}}{month:\\d{2}}{day:\\d{2}}.jar");
|
||||
result = matchAndExtract(p,"com.example-sources-1.0.0-20100220.jar");
|
||||
assertEquals("com.example", result.get("symbolicName").value());
|
||||
assertEquals("1.0.0", result.get("version").value());
|
||||
assertEquals("2010", result.get("year").value());
|
||||
assertEquals("02", result.get("month").value());
|
||||
assertEquals("20", result.get("day").value());
|
||||
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
|
||||
assertEquals("1.0.0", result.getUriVariables().get("version"));
|
||||
assertEquals("2010", result.getUriVariables().get("year"));
|
||||
assertEquals("02", result.getUriVariables().get("month"));
|
||||
assertEquals("20", result.getUriVariables().get("day"));
|
||||
|
||||
p = pp.parse("{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.\\{\\}]+}.jar");
|
||||
result = matchAndExtract(p, "com.example-sources-1.0.0.{12}.jar");
|
||||
assertEquals("com.example", result.get("symbolicName").value());
|
||||
assertEquals("1.0.0.{12}", result.get("version").value());
|
||||
assertEquals("com.example", result.getUriVariables().get("symbolicName"));
|
||||
assertEquals("1.0.0.{12}", result.getUriVariables().get("version"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -1137,12 +1140,12 @@ public class PathPatternMatcherTests {
|
|||
PathPatternParser parser = new PathPatternParser();
|
||||
PathPattern p1 = parser.parse("/{foo}");
|
||||
PathPattern p2 = parser.parse("/{foo}.*");
|
||||
Map<String, PathMatchResult> r1 = matchAndExtract(p1, "/file.txt");
|
||||
Map<String, PathMatchResult> r2 = matchAndExtract(p2, "/file.txt");
|
||||
PathMatchResult r1 = matchAndExtract(p1, "/file.txt");
|
||||
PathMatchResult r2 = matchAndExtract(p2, "/file.txt");
|
||||
|
||||
// works fine
|
||||
assertEquals("file.txt", r1.get("foo").value());
|
||||
assertEquals("file", r2.get("foo").value());
|
||||
assertEquals("file.txt", r1.getUriVariables().get("foo"));
|
||||
assertEquals("file", r2.getUriVariables().get("foo"));
|
||||
|
||||
// This produces 2 (see comments in https://jira.spring.io/browse/SPR-14544 )
|
||||
// Comparator<String> patternComparator = new AntPathMatcher().getPatternComparator("");
|
||||
|
|
@ -1269,38 +1272,38 @@ public class PathPatternMatcherTests {
|
|||
@Test
|
||||
public void parameters() {
|
||||
// CaptureVariablePathElement
|
||||
Map<String, PathMatchResult> result = matchAndExtract("/abc/{var}","/abc/one;two=three;four=five");
|
||||
assertEquals("one",result.get("var").value());
|
||||
assertEquals("[three]",result.get("var").parameters().get("two").toString());
|
||||
assertEquals("[five]",result.get("var").parameters().get("four").toString());
|
||||
PathMatchResult result = matchAndExtract("/abc/{var}","/abc/one;two=three;four=five");
|
||||
assertEquals("one",result.getUriVariables().get("var"));
|
||||
assertEquals("three",result.getMatrixVariables().get("var").getFirst("two"));
|
||||
assertEquals("five",result.getMatrixVariables().get("var").getFirst("four"));
|
||||
// RegexPathElement
|
||||
result = matchAndExtract("/abc/{var1}_{var2}","/abc/123_456;a=b;c=d");
|
||||
assertEquals("123",result.get("var1").value());
|
||||
assertEquals("456",result.get("var2").value());
|
||||
assertEquals("123",result.getUriVariables().get("var1"));
|
||||
assertEquals("456",result.getUriVariables().get("var2"));
|
||||
// vars associated with second variable
|
||||
assertNull(result.get("var1").parameters().get("a"));
|
||||
assertNull(result.get("var1").parameters().get("c"));
|
||||
assertEquals("[b]",result.get("var2").parameters().get("a").toString());
|
||||
assertEquals("[d]",result.get("var2").parameters().get("c").toString());
|
||||
assertNull(result.getMatrixVariables().get("var1"));
|
||||
assertNull(result.getMatrixVariables().get("var1"));
|
||||
assertEquals("b",result.getMatrixVariables().get("var2").getFirst("a"));
|
||||
assertEquals("d",result.getMatrixVariables().get("var2").getFirst("c"));
|
||||
// CaptureTheRestPathElement
|
||||
result = matchAndExtract("/{*var}","/abc/123_456;a=b;c=d");
|
||||
assertEquals("/abc/123_456",result.get("var").value());
|
||||
assertEquals("[b]",result.get("var").parameters().get("a").toString());
|
||||
assertEquals("[d]",result.get("var").parameters().get("c").toString());
|
||||
assertEquals("/abc/123_456",result.getUriVariables().get("var"));
|
||||
assertEquals("b",result.getMatrixVariables().get("var").getFirst("a"));
|
||||
assertEquals("d",result.getMatrixVariables().get("var").getFirst("c"));
|
||||
result = matchAndExtract("/{*var}","/abc/123_456;a=b;c=d/789;a=e;f=g");
|
||||
assertEquals("/abc/123_456/789",result.get("var").value());
|
||||
assertEquals("[b, e]",result.get("var").parameters().get("a").toString());
|
||||
assertEquals("[d]",result.get("var").parameters().get("c").toString());
|
||||
assertEquals("[g]",result.get("var").parameters().get("f").toString());
|
||||
assertEquals("/abc/123_456/789",result.getUriVariables().get("var"));
|
||||
assertEquals("[b, e]",result.getMatrixVariables().get("var").get("a").toString());
|
||||
assertEquals("d",result.getMatrixVariables().get("var").getFirst("c"));
|
||||
assertEquals("g",result.getMatrixVariables().get("var").getFirst("f"));
|
||||
|
||||
result = matchAndExtract("/abc/{var}","/abc/one");
|
||||
assertEquals("one",result.get("var").value());
|
||||
assertEquals(0,result.get("var").parameters().size());
|
||||
assertEquals("one",result.getUriVariables().get("var"));
|
||||
assertNull(result.getMatrixVariables().get("var"));
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
private Map<String, PathMatchResult> matchAndExtract(String pattern, String path) {
|
||||
private PathMatchResult matchAndExtract(String pattern, String path) {
|
||||
return parse(pattern).matchAndExtract(PathPatternMatcherTests.toPathContainer(path));
|
||||
}
|
||||
|
||||
|
|
@ -1346,29 +1349,26 @@ public class PathPatternMatcherTests {
|
|||
assertFalse(pattern.matches(PathContainer));
|
||||
}
|
||||
|
||||
private Map<String, PathMatchResult> checkCapture(String uriTemplate, String path, String... keyValues) {
|
||||
private PathMatchResult checkCapture(String uriTemplate, String path, String... keyValues) {
|
||||
PathPatternParser parser = new PathPatternParser();
|
||||
PathPattern pattern = parser.parse(uriTemplate);
|
||||
Map<String, PathMatchResult> matchResults = pattern.matchAndExtract(toPathContainer(path));
|
||||
PathMatchResult matchResult = pattern.matchAndExtract(toPathContainer(path));
|
||||
Map<String, String> expectedKeyValues = new HashMap<>();
|
||||
if (keyValues != null) {
|
||||
for (int i = 0; i < keyValues.length; i += 2) {
|
||||
expectedKeyValues.put(keyValues[i], keyValues[i + 1]);
|
||||
}
|
||||
}
|
||||
Map<String, PathMatchResult> capturedVariables = matchResults;
|
||||
for (Map.Entry<String, String> me : expectedKeyValues.entrySet()) {
|
||||
String value = capturedVariables.get(me.getKey()).value();
|
||||
String value = matchResult.getUriVariables().get(me.getKey());
|
||||
if (value == null) {
|
||||
fail("Did not find key '" + me.getKey() + "' in captured variables: "
|
||||
+ capturedVariables);
|
||||
+ matchResult.getUriVariables());
|
||||
}
|
||||
if (!value.equals(me.getValue())) {
|
||||
fail("Expected value '" + me.getValue() + "' for key '" + me.getKey()
|
||||
+ "' but was '" + value + "'");
|
||||
}
|
||||
}
|
||||
return capturedVariables;
|
||||
return matchResult;
|
||||
}
|
||||
|
||||
private void checkExtractPathWithinPattern(String pattern, String path, String expected) {
|
||||
|
|
@ -1399,7 +1399,7 @@ public class PathPatternMatcherTests {
|
|||
return pattern.getPathRemaining(toPathContainer(path));
|
||||
}
|
||||
|
||||
private Map<String, PathMatchResult> matchAndExtract(PathPattern p, String path) {
|
||||
private PathMatchResult matchAndExtract(PathPattern p, String path) {
|
||||
return p.matchAndExtract(toPathContainer(path));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,14 +19,18 @@ package org.springframework.web.util.pattern;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.server.reactive.PathContainer;
|
||||
import org.springframework.web.util.pattern.PathPattern.PathMatchResult;
|
||||
import org.springframework.web.util.pattern.PatternParseException.PatternMessage;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Exercise the {@link PathPatternParser}.
|
||||
|
|
@ -137,23 +141,23 @@ public class PathPatternParserTests {
|
|||
|
||||
pathPattern = checkStructure("/{var:[^\\/]*}");
|
||||
assertEquals(CaptureVariablePathElement.class.getName(), pathPattern.getHeadSection().next.getClass().getName());
|
||||
Map<String, PathMatchResult> result = matchAndExtract(pathPattern,"/foo");
|
||||
assertEquals("foo", result.get("var").value());
|
||||
PathMatchResult result = matchAndExtract(pathPattern,"/foo");
|
||||
assertEquals("foo", result.getUriVariables().get("var"));
|
||||
|
||||
pathPattern = checkStructure("/{var:\\[*}");
|
||||
assertEquals(CaptureVariablePathElement.class.getName(), pathPattern.getHeadSection().next.getClass().getName());
|
||||
result = matchAndExtract(pathPattern,"/[[[");
|
||||
assertEquals("[[[", result.get("var").value());
|
||||
assertEquals("[[[", result.getUriVariables().get("var"));
|
||||
|
||||
pathPattern = checkStructure("/{var:[\\{]*}");
|
||||
assertEquals(CaptureVariablePathElement.class.getName(), pathPattern.getHeadSection().next.getClass().getName());
|
||||
result = matchAndExtract(pathPattern,"/{{{");
|
||||
assertEquals("{{{", result.get("var").value());
|
||||
assertEquals("{{{", result.getUriVariables().get("var"));
|
||||
|
||||
pathPattern = checkStructure("/{var:[\\}]*}");
|
||||
assertEquals(CaptureVariablePathElement.class.getName(), pathPattern.getHeadSection().next.getClass().getName());
|
||||
result = matchAndExtract(pathPattern,"/}}}");
|
||||
assertEquals("}}}", result.get("var").value());
|
||||
assertEquals("}}}", result.getUriVariables().get("var"));
|
||||
|
||||
pathPattern = checkStructure("*");
|
||||
assertEquals(WildcardPathElement.class.getName(), pathPattern.getHeadSection().getClass().getName());
|
||||
|
|
@ -467,7 +471,7 @@ public class PathPatternParserTests {
|
|||
assertFalse(pp.matches(PathPatternMatcherTests.toPathContainer(path)));
|
||||
}
|
||||
|
||||
private Map<String, PathMatchResult> matchAndExtract(PathPattern pp, String path) {
|
||||
private PathMatchResult matchAndExtract(PathPattern pp, String path) {
|
||||
return pp.matchAndExtract(PathPatternMatcherTests.toPathContainer(path));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ public abstract class RequestPredicates {
|
|||
boolean match = this.pattern.matches(path);
|
||||
traceMatch("Pattern", this.pattern.getPatternString(), path, match);
|
||||
if (match) {
|
||||
mergeTemplateVariables(request, this.pattern.matchAndExtract(request.path()));
|
||||
mergeTemplateVariables(request, this.pattern.matchAndExtract(request.path()).getUriVariables());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
|
@ -355,7 +355,7 @@ public abstract class RequestPredicates {
|
|||
public Optional<ServerRequest> nest(ServerRequest request) {
|
||||
return Optional.ofNullable(this.pattern.getPathRemaining(request.path()))
|
||||
.map(info -> {
|
||||
mergeTemplateVariables(request, info.getMatchingVariables());
|
||||
mergeTemplateVariables(request, info.getUriVariables());
|
||||
String path = info.getPathRemaining();
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
* the "other" instance as follows:
|
||||
* <ul>
|
||||
* <li>If there are patterns in both instances, combine the patterns in "this" with
|
||||
* the patterns in "other" using {@link PathPattern#combine(String)}.
|
||||
* the patterns in "other" using {@link PathPattern#combine(PathPattern)}.
|
||||
* <li>If only one instance has patterns, use them.
|
||||
* <li>If neither instance has patterns, use an empty String (i.e. "").
|
||||
* </ul>
|
||||
|
|
@ -130,8 +130,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
if (!this.patterns.isEmpty() && !other.patterns.isEmpty()) {
|
||||
for (PathPattern pattern1 : this.patterns) {
|
||||
for (PathPattern pattern2 : other.patterns) {
|
||||
String combinedPattern = pattern1.combine(pattern2.getPatternString());
|
||||
combined.add(this.parser.parse(combinedPattern));
|
||||
combined.add(pattern1.combine(pattern2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -166,7 +165,8 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
|||
|
||||
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||
SortedSet<PathPattern> matches = getMatchingPatterns(lookupPath);
|
||||
return matches.isEmpty() ? null : new PatternsRequestCondition(new ArrayList<>(matches), this.parser);
|
||||
return matches.isEmpty() ? null : new PatternsRequestCondition(
|
||||
new ArrayList<PathPattern>(matches), this.parser);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,18 +17,14 @@
|
|||
package org.springframework.web.reactive.result.method;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
|
@ -36,9 +32,7 @@ import org.springframework.http.HttpMethod;
|
|||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.result.condition.NameValueExpression;
|
||||
|
|
@ -113,31 +107,25 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
|
||||
PathPattern bestPattern;
|
||||
Map<String, String> uriVariables;
|
||||
Map<String, MultiValueMap<String, String>> matrixVariables;
|
||||
|
||||
Set<PathPattern> patterns = info.getPatternsCondition().getPatterns();
|
||||
if (patterns.isEmpty()) {
|
||||
bestPattern = getPathPatternParser().parse(lookupPath);
|
||||
uriVariables = Collections.emptyMap();
|
||||
matrixVariables = Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
bestPattern = patterns.iterator().next();
|
||||
uriVariables = bestPattern.matchAndExtract(lookupPath);
|
||||
}
|
||||
|
||||
// Let URI vars be stripped of semicolon content..
|
||||
Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(exchange, uriVariables);
|
||||
exchange.getAttributes().put(MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
|
||||
|
||||
// Now decode URI variables
|
||||
if (!uriVariables.isEmpty()) {
|
||||
uriVariables = uriVariables.entrySet().stream().collect(Collectors.toMap(
|
||||
Entry::getKey, e -> StringUtils.uriDecode(e.getValue(), StandardCharsets.UTF_8)
|
||||
));
|
||||
PathPattern.PathMatchResult result = bestPattern.matchAndExtract(lookupPath);
|
||||
uriVariables = result.getUriVariables();
|
||||
matrixVariables = result.getMatrixVariables();
|
||||
}
|
||||
|
||||
exchange.getAttributes().put(BEST_MATCHING_HANDLER_ATTRIBUTE, handlerMethod);
|
||||
exchange.getAttributes().put(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
|
||||
exchange.getAttributes().put(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
|
||||
exchange.getAttributes().put(MATRIX_VARIABLES_ATTRIBUTE, matrixVariables);
|
||||
|
||||
if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
|
||||
Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
|
||||
|
|
@ -145,62 +133,6 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
|
|||
}
|
||||
}
|
||||
|
||||
private Map<String, MultiValueMap<String, String>> extractMatrixVariables(
|
||||
ServerWebExchange exchange, Map<String, String> uriVariables) {
|
||||
|
||||
Map<String, MultiValueMap<String, String>> result = new LinkedHashMap<>();
|
||||
for (Entry<String, String> uriVar : uriVariables.entrySet()) {
|
||||
String uriVarValue = uriVar.getValue();
|
||||
|
||||
int equalsIndex = uriVarValue.indexOf('=');
|
||||
if (equalsIndex == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String semicolonContent;
|
||||
int semicolonIndex = uriVarValue.indexOf(';');
|
||||
if ((semicolonIndex == -1) || (semicolonIndex == 0) || (equalsIndex < semicolonIndex)) {
|
||||
semicolonContent = uriVarValue;
|
||||
}
|
||||
else {
|
||||
semicolonContent = uriVarValue.substring(semicolonIndex + 1);
|
||||
uriVariables.put(uriVar.getKey(), uriVarValue.substring(0, semicolonIndex));
|
||||
}
|
||||
result.put(uriVar.getKey(), parseMatrixVariables(exchange, semicolonContent));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> parseMatrixVariables(ServerWebExchange exchange,
|
||||
String semicolonContent) {
|
||||
|
||||
MultiValueMap<String, String> vars = new LinkedMultiValueMap<>();
|
||||
if (!StringUtils.hasText(semicolonContent)) {
|
||||
return vars;
|
||||
}
|
||||
StringTokenizer pairs = new StringTokenizer(semicolonContent, ";");
|
||||
while (pairs.hasMoreTokens()) {
|
||||
String pair = pairs.nextToken();
|
||||
int index = pair.indexOf('=');
|
||||
if (index != -1) {
|
||||
String name = pair.substring(0, index);
|
||||
String rawValue = pair.substring(index + 1);
|
||||
for (String value : StringUtils.commaDelimitedListToStringArray(rawValue)) {
|
||||
vars.add(name, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
vars.add(pair, "");
|
||||
}
|
||||
}
|
||||
MultiValueMap<String, String> decoded = new LinkedMultiValueMap<>(vars.size());
|
||||
vars.forEach((key, values) -> values.forEach(value -> {
|
||||
String decodedValue = StringUtils.uriDecode(value, StandardCharsets.UTF_8);
|
||||
decoded.add(key, decodedValue);
|
||||
}));
|
||||
return decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate all RequestMappingInfos once again, look if any match by URL at
|
||||
* least and raise exceptions accordingly.
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ import org.springframework.util.LinkedMultiValueMap;
|
|||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.web.reactive.function.BodyExtractors.toMono;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -294,41 +294,19 @@ public class RequestMappingInfoHandlerMappingTests {
|
|||
assertEquals(Arrays.asList("red", "blue", "green"), matrixVariables.get("colors"));
|
||||
assertEquals("2012", matrixVariables.getFirst("year"));
|
||||
assertEquals("cars", uriVariables.get("cars"));
|
||||
|
||||
exchange = get("/cars;colors=red,blue,green;year=2012").toExchange();
|
||||
handleMatch(exchange, "/{cars:[^;]+}{params}");
|
||||
|
||||
matrixVariables = getMatrixVariables(exchange, "params");
|
||||
uriVariables = getUriTemplateVariables(exchange);
|
||||
|
||||
assertNotNull(matrixVariables);
|
||||
assertEquals(Arrays.asList("red", "blue", "green"), matrixVariables.get("colors"));
|
||||
assertEquals("2012", matrixVariables.getFirst("year"));
|
||||
assertEquals("cars", uriVariables.get("cars"));
|
||||
assertEquals(";colors=red,blue,green;year=2012", uriVariables.get("params"));
|
||||
|
||||
exchange = get("/cars").toExchange();
|
||||
handleMatch(exchange, "/{cars:[^;]+}{params}");
|
||||
|
||||
matrixVariables = getMatrixVariables(exchange, "params");
|
||||
uriVariables = getUriTemplateVariables(exchange);
|
||||
|
||||
assertNull(matrixVariables);
|
||||
assertEquals("cars", uriVariables.get("cars"));
|
||||
assertEquals("", uriVariables.get("params"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleMatchMatrixVariablesDecoding() throws Exception {
|
||||
ServerWebExchange exchange = method(HttpMethod.GET, URI.create("/path;mvar=a%2fb")).toExchange();
|
||||
handleMatch(exchange, "/path{filter}");
|
||||
handleMatch(exchange, "/{filter}");
|
||||
|
||||
MultiValueMap<String, String> matrixVariables = getMatrixVariables(exchange, "filter");
|
||||
Map<String, String> uriVariables = getUriTemplateVariables(exchange);
|
||||
|
||||
assertNotNull(matrixVariables);
|
||||
assertEquals(Collections.singletonList("a/b"), matrixVariables.get("mvar"));
|
||||
assertEquals(";mvar=a/b", uriVariables.get("filter"));
|
||||
assertEquals("path", uriVariables.get("filter"));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue