Improve separator support in PathContainer
To make the switching of separators complete, it is also important to know whether the decoding of path segment values and the parsing of path param should be done as those are applied transparently. This commit replaces the recently added separator argument to PathContainer.parsePath with an Options type with two predefined constants. One for HTTP URLs with automatic decoding and parsing of path params, and another for "." separated message routes without decoding except for encoded sequences of the separator itself. See gh-23310
This commit is contained in:
@@ -27,7 +27,6 @@ import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultPathContainer}.
|
||||
@@ -36,7 +35,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
public class DefaultPathContainerTests {
|
||||
|
||||
@Test
|
||||
public void pathSegment() throws Exception {
|
||||
public void pathSegment() {
|
||||
// basic
|
||||
testPathSegment("cars", "cars", new LinkedMultiValueMap<>());
|
||||
|
||||
@@ -92,7 +91,7 @@ public class DefaultPathContainerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void path() throws Exception {
|
||||
public void path() {
|
||||
// basic
|
||||
testPath("/a/b/c", "/a/b/c", Arrays.asList("/", "a", "/", "b", "/", "c"));
|
||||
|
||||
@@ -112,20 +111,20 @@ public class DefaultPathContainerTests {
|
||||
testPath("//%20/%20", "//%20/%20", Arrays.asList("/", "/", "%20", "/", "%20"));
|
||||
}
|
||||
|
||||
private void testPath(String input, String separator, String value, List<String> expectedElements) {
|
||||
PathContainer path = PathContainer.parsePath(input, separator);
|
||||
private void testPath(String input, PathContainer.Options options, String value, List<String> expectedElements) {
|
||||
PathContainer path = PathContainer.parsePath(input, options);
|
||||
|
||||
assertThat(path.value()).as("value: '" + input + "'").isEqualTo(value);
|
||||
assertThat(path.elements().stream()
|
||||
.map(PathContainer.Element::value).collect(Collectors.toList())).as("elements: " + input).isEqualTo(expectedElements);
|
||||
assertThat(path.elements().stream().map(PathContainer.Element::value).collect(Collectors.toList()))
|
||||
.as("elements: " + input).isEqualTo(expectedElements);
|
||||
}
|
||||
|
||||
private void testPath(String input, String value, List<String> expectedElements) {
|
||||
testPath(input, "/", value, expectedElements);
|
||||
testPath(input, PathContainer.Options.HTTP_PATH, value, expectedElements);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subPath() throws Exception {
|
||||
public void subPath() {
|
||||
// basic
|
||||
PathContainer path = PathContainer.parsePath("/a/b/c");
|
||||
assertThat(path.subPath(0)).isSameAs(path);
|
||||
@@ -141,14 +140,16 @@ public class DefaultPathContainerTests {
|
||||
assertThat(path.subPath(2).value()).isEqualTo("/b/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathWithCustomSeparator() throws Exception {
|
||||
testPath("a.b.c", ".", "a.b.c", Arrays.asList("a", ".", "b", ".", "c"));
|
||||
}
|
||||
@Test // gh-23310
|
||||
public void pathWithCustomSeparator() {
|
||||
PathContainer path = PathContainer.parsePath("a.b%2Eb.c", PathContainer.Options.MESSAGE_ROUTE);
|
||||
|
||||
@Test
|
||||
public void emptySeparator() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> PathContainer.parsePath("path", ""));
|
||||
List<String> decodedSegments = path.elements().stream()
|
||||
.filter(e -> e instanceof PathSegment)
|
||||
.map(e -> ((PathSegment) e).valueToMatch())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
assertThat(decodedSegments).isEqualTo(Arrays.asList("a", "b.b", "c"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -411,7 +411,7 @@ public class PathPatternParserTests {
|
||||
@Test
|
||||
public void separatorTests() {
|
||||
PathPatternParser parser = new PathPatternParser();
|
||||
parser.setSeparator('.');
|
||||
parser.setPathOptions(PathContainer.Options.HTTP_PATH);
|
||||
String rawPattern = "first.second.{last}";
|
||||
PathPattern pattern = parser.parse(rawPattern);
|
||||
assertThat(pattern.computePatternString()).isEqualTo(rawPattern);
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
|
||||
package org.springframework.web.util.pattern;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.server.PathContainer;
|
||||
import org.springframework.util.RouteMatcher;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -32,18 +35,33 @@ public class PathPatternRouteMatcherTests {
|
||||
|
||||
@Test
|
||||
public void matchRoute() {
|
||||
PathPatternRouteMatcher routeMatcher = new PathPatternRouteMatcher(new PathPatternParser());
|
||||
RouteMatcher.Route route = routeMatcher.parseRoute("/projects/spring-framework");
|
||||
assertThat(routeMatcher.match("/projects/{name}", route)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchRouteWithCustomSeparator() {
|
||||
PathPatternParser pathPatternParser = new PathPatternParser();
|
||||
pathPatternParser.setSeparator('.');
|
||||
PathPatternRouteMatcher routeMatcher = new PathPatternRouteMatcher(pathPatternParser);
|
||||
PathPatternRouteMatcher routeMatcher = new PathPatternRouteMatcher();
|
||||
RouteMatcher.Route route = routeMatcher.parseRoute("projects.spring-framework");
|
||||
assertThat(routeMatcher.match("projects.{name}", route)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchRouteWithCustomSeparator() {
|
||||
PathPatternParser parser = new PathPatternParser();
|
||||
parser.setPathOptions(PathContainer.Options.create('/', false));
|
||||
PathPatternRouteMatcher routeMatcher = new PathPatternRouteMatcher(parser);
|
||||
RouteMatcher.Route route = routeMatcher.parseRoute("/projects/spring-framework");
|
||||
assertThat(routeMatcher.match("/projects/{name}", route)).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-23310
|
||||
public void noDecodingAndNoParamParsing() {
|
||||
PathPatternRouteMatcher routeMatcher = new PathPatternRouteMatcher();
|
||||
RouteMatcher.Route route = routeMatcher.parseRoute("projects.spring%20framework;p=1");
|
||||
assertThat(routeMatcher.match("projects.spring%20framework;p=1", route)).isTrue();
|
||||
}
|
||||
|
||||
@Test // gh-23310
|
||||
public void separatorOnlyDecoded() {
|
||||
PathPatternRouteMatcher routeMatcher = new PathPatternRouteMatcher();
|
||||
RouteMatcher.Route route = routeMatcher.parseRoute("projects.spring%2Eframework");
|
||||
Map<String, String> vars = routeMatcher.matchAndExtract("projects.{project}", route);
|
||||
assertThat(vars).containsEntry("project", "spring.framework");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -710,9 +710,10 @@ public class PathPatternTests {
|
||||
@Test
|
||||
public void extractPathWithinPatternCustomSeparator() {
|
||||
PathPatternParser ppp = new PathPatternParser();
|
||||
ppp.setSeparator('.');
|
||||
ppp.setPathOptions(PathContainer.Options.create('.', true));
|
||||
PathPattern pp = ppp.parse("test.**");
|
||||
PathContainer pathContainer = PathContainer.parsePath("test.projects..spring-framework", ".");
|
||||
PathContainer pathContainer = PathContainer.parsePath(
|
||||
"test.projects..spring-framework", PathContainer.Options.create('.', true));
|
||||
PathContainer result = pp.extractPathWithinPattern(pathContainer);
|
||||
assertThat(result.value()).isEqualTo("projects.spring-framework");
|
||||
assertThat(result.elements()).hasSize(3);
|
||||
|
||||
Reference in New Issue
Block a user