diff --git a/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java b/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java index 606cecada7be..26f874aa33dc 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/reactive/function/server/MockServerRequest.java @@ -41,7 +41,6 @@ import org.springframework.http.MediaType; import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.multipart.Part; -import org.springframework.http.server.PathContainer; import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.lang.Nullable; @@ -69,7 +68,7 @@ public final class MockServerRequest implements ServerRequest { private final URI uri; - private final RequestPath pathContainer; + private final RequestPath requestPath; private final MockHeaders headers; @@ -88,7 +87,7 @@ public final class MockServerRequest implements ServerRequest { private final WebSession session; @Nullable - private Principal principal; + private final Principal principal; @Nullable private final InetSocketAddress remoteAddress; @@ -111,7 +110,7 @@ private MockServerRequest(HttpMethod method, URI uri, String contextPath, MockHe this.method = method; this.uri = uri; - this.pathContainer = RequestPath.parse(uri, contextPath); + this.requestPath = RequestPath.parse(uri, contextPath); this.headers = headers; this.cookies = cookies; this.body = body; @@ -148,8 +147,8 @@ public UriBuilder uriBuilder() { } @Override - public PathContainer pathContainer() { - return this.pathContainer; + public RequestPath requestPath() { + return this.requestPath; } @Override 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 ece992b7a6f7..042d48a78684 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 @@ -249,7 +249,7 @@ else if (!hasLength(pathContainer)) { @Nullable public PathRemainingMatchInfo matchStartOfPath(PathContainer pathContainer) { if (this.head == null) { - return new PathRemainingMatchInfo(pathContainer); + return new PathRemainingMatchInfo(EMPTY_PATH, pathContainer); } else if (!hasLength(pathContainer)) { return null; @@ -262,15 +262,17 @@ else if (!hasLength(pathContainer)) { return null; } else { - PathRemainingMatchInfo info; + PathContainer pathMatched; + PathContainer pathRemaining; if (matchingContext.remainingPathIndex == pathContainer.elements().size()) { - info = new PathRemainingMatchInfo(EMPTY_PATH, matchingContext.getPathMatchResult()); + pathMatched = pathContainer; + pathRemaining = EMPTY_PATH; } else { - info = new PathRemainingMatchInfo(pathContainer.subPath(matchingContext.remainingPathIndex), - matchingContext.getPathMatchResult()); + pathMatched = pathContainer.subPath(0, matchingContext.remainingPathIndex); + pathRemaining = pathContainer.subPath(matchingContext.remainingPathIndex); } - return info; + return new PathRemainingMatchInfo(pathMatched, pathRemaining, matchingContext.getPathMatchResult()); } } @@ -592,20 +594,32 @@ public String toString() { */ public static class PathRemainingMatchInfo { + private final PathContainer pathMatched; + private final PathContainer pathRemaining; private final PathMatchInfo pathMatchInfo; - PathRemainingMatchInfo(PathContainer pathRemaining) { - this(pathRemaining, PathMatchInfo.EMPTY); + PathRemainingMatchInfo(PathContainer pathMatched, PathContainer pathRemaining) { + this(pathMatched, pathRemaining, PathMatchInfo.EMPTY); } - PathRemainingMatchInfo(PathContainer pathRemaining, PathMatchInfo pathMatchInfo) { + PathRemainingMatchInfo(PathContainer pathMatched, PathContainer pathRemaining, + PathMatchInfo pathMatchInfo) { this.pathRemaining = pathRemaining; + this.pathMatched = pathMatched; this.pathMatchInfo = pathMatchInfo; } + /** + * Return the part of a path that was matched by a pattern. + * @since 5.3 + */ + public PathContainer getPathMatched() { + return this.pathMatched; + } + /** * Return the part of a path that was not matched by a pattern. */ 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 b90836aab4aa..707809b07d63 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 @@ -557,6 +557,7 @@ public void pathRemainingEnhancements_spr15419() { pp = parse("/{this}/{one}/{here}"); pri = getPathRemaining(pp, "/foo/bar/goo/boo"); assertThat(pri.getPathRemaining().value()).isEqualTo("/boo"); + assertThat(pri.getPathMatched().value()).isEqualTo("/foo/bar/goo"); assertThat(pri.getUriVariables().get("this")).isEqualTo("foo"); assertThat(pri.getUriVariables().get("one")).isEqualTo("bar"); assertThat(pri.getUriVariables().get("here")).isEqualTo("goo"); @@ -564,11 +565,13 @@ public void pathRemainingEnhancements_spr15419() { pp = parse("/aaa/{foo}"); pri = getPathRemaining(pp, "/aaa/bbb"); assertThat(pri.getPathRemaining().value()).isEqualTo(""); + assertThat(pri.getPathMatched().value()).isEqualTo("/aaa/bbb"); assertThat(pri.getUriVariables().get("foo")).isEqualTo("bbb"); pp = parse("/aaa/bbb"); pri = getPathRemaining(pp, "/aaa/bbb"); assertThat(pri.getPathRemaining().value()).isEqualTo(""); + assertThat(pri.getPathMatched().value()).isEqualTo("/aaa/bbb"); assertThat(pri.getUriVariables().size()).isEqualTo(0); pp = parse("/*/{foo}/b*"); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java index c98f151fac26..7e7d8b4bf1d7 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java @@ -43,7 +43,7 @@ import org.springframework.http.MediaType; import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.multipart.Part; -import org.springframework.http.server.PathContainer; +import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.lang.Nullable; @@ -123,7 +123,7 @@ public UriBuilder uriBuilder() { } @Override - public PathContainer pathContainer() { + public RequestPath requestPath() { return request().getPath(); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java index eb4109c22361..e17cca7906e4 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java @@ -56,7 +56,7 @@ public PathResourceLookupFunction(String pattern, Resource location) { @Override public Mono apply(ServerRequest request) { - PathContainer pathContainer = request.pathContainer(); + PathContainer pathContainer = request.requestPath().pathWithinApplication(); if (!this.pattern.matches(pathContainer)) { return Mono.empty(); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java index b7b4174a49da..6b72b545d934 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java @@ -19,7 +19,6 @@ import java.net.InetSocketAddress; import java.net.URI; import java.security.Principal; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; @@ -47,6 +46,7 @@ import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.multipart.Part; import org.springframework.http.server.PathContainer; +import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; @@ -492,7 +492,7 @@ public PathPatternPredicate(PathPattern pattern) { @Override public boolean test(ServerRequest request) { - PathContainer pathContainer = request.pathContainer(); + PathContainer pathContainer = request.requestPath().pathWithinApplication(); PathPattern.PathMatchInfo info = this.pattern.matchAndExtract(pathContainer); traceMatch("Pattern", this.pattern.getPatternString(), request.path(), info != null); if (info != null) { @@ -518,7 +518,7 @@ private static void mergeAttributes(ServerRequest request, Map v @Override public Optional nest(ServerRequest request) { - return Optional.ofNullable(this.pattern.matchStartOfPath(request.pathContainer())) + return Optional.ofNullable(this.pattern.matchStartOfPath(request.requestPath().pathWithinApplication())) .map(info -> new SubPathServerRequestWrapper(request, info, this.pattern)); } @@ -926,17 +926,27 @@ private static class SubPathServerRequestWrapper implements ServerRequest { private final ServerRequest request; - private final PathContainer pathContainer; + private final RequestPath requestPath; private final Map attributes; public SubPathServerRequestWrapper(ServerRequest request, PathPattern.PathRemainingMatchInfo info, PathPattern pattern) { this.request = request; - this.pathContainer = new SubPathContainer(info.getPathRemaining()); + this.requestPath = requestPath(request.requestPath(), info); this.attributes = mergeAttributes(request, info.getUriVariables(), pattern); } + private static RequestPath requestPath(RequestPath original, PathPattern.PathRemainingMatchInfo info) { + StringBuilder contextPath = new StringBuilder(original.contextPath().value()); + contextPath.append(info.getPathMatched().value()); + int length = contextPath.length(); + if (length > 0 && contextPath.charAt(length - 1) == '/') { + contextPath.setLength(length - 1); + } + return original.modifyContextPath(contextPath.toString()); + } + private static Map mergeAttributes(ServerRequest request, Map pathVariables, PathPattern pattern) { Map result = new ConcurrentHashMap<>(request.attributes()); @@ -972,13 +982,8 @@ public UriBuilder uriBuilder() { } @Override - public String path() { - return this.pathContainer.value(); - } - - @Override - public PathContainer pathContainer() { - return this.pathContainer; + public RequestPath requestPath() { + return this.requestPath; } @Override @@ -1089,46 +1094,6 @@ public String toString() { return method() + " " + path(); } - private static class SubPathContainer implements PathContainer { - - private static final PathContainer.Separator SEPARATOR = () -> "/"; - - - private final String value; - - private final List elements; - - public SubPathContainer(PathContainer original) { - this.value = prefixWithSlash(original.value()); - this.elements = prependWithSeparator(original.elements()); - } - - private static String prefixWithSlash(String path) { - if (!path.startsWith("/")) { - path = "/" + path; - } - return path; - } - - private static List prependWithSeparator(List elements) { - List result = new ArrayList<>(elements); - if (result.isEmpty() || !(result.get(0) instanceof Separator)) { - result.add(0, SEPARATOR); - } - return Collections.unmodifiableList(result); - } - - - @Override - public String value() { - return this.value; - } - - @Override - public List elements() { - return this.elements; - } - } } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java index 1aeb4b917ec0..5376269f2417 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/ServerRequest.java @@ -42,6 +42,7 @@ import org.springframework.http.codec.json.Jackson2CodecSupport; import org.springframework.http.codec.multipart.Part; import org.springframework.http.server.PathContainer; +import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -100,14 +101,24 @@ default HttpMethod method() { * Get the request path. */ default String path() { - return uri().getRawPath(); + return requestPath().pathWithinApplication().value(); } /** * Get the request path as a {@code PathContainer}. + * @deprecated as of 5.3, in favor on {@link #requestPath()} */ + @Deprecated default PathContainer pathContainer() { - return PathContainer.parsePath(path()); + return requestPath(); + } + + /** + * Get the request path as a {@code PathContainer}. + * @since 5.3 + */ + default RequestPath requestPath() { + return exchange().getRequest().getPath(); } /** diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java index 9b92d77cd1bc..20127d8a6345 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerRequestWrapper.java @@ -38,6 +38,7 @@ import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.multipart.Part; import org.springframework.http.server.PathContainer; +import org.springframework.http.server.RequestPath; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.util.Assert; import org.springframework.util.MultiValueMap; @@ -104,10 +105,16 @@ public String path() { } @Override + @Deprecated public PathContainer pathContainer() { return this.delegate.pathContainer(); } + @Override + public RequestPath requestPath() { + return this.delegate.requestPath(); + } + @Override public Headers headers() { return this.delegate.headers(); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RequestPredicatesTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RequestPredicatesTests.java index 3a8536cdf79b..1c65981b6055 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RequestPredicatesTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/RequestPredicatesTests.java @@ -29,7 +29,6 @@ import org.springframework.web.testfixture.server.MockServerWebExchange; import org.springframework.web.util.pattern.PathPatternParser; -import static java.util.Collections.emptyList; import static org.assertj.core.api.Assertions.assertThat; /** @@ -141,7 +140,7 @@ public void path() { URI uri = URI.create("https://localhost/path"); RequestPredicate predicate = RequestPredicates.path("/p*"); MockServerHttpRequest mockRequest = MockServerHttpRequest.get(uri.toString()).build(); - ServerRequest request = new DefaultServerRequest(MockServerWebExchange.from(mockRequest), emptyList()); + ServerRequest request = new DefaultServerRequest(MockServerWebExchange.from(mockRequest), Collections.emptyList()); assertThat(predicate.test(request)).isTrue(); mockRequest = MockServerHttpRequest.head("https://example.com").build(); @@ -178,6 +177,15 @@ public void pathPredicates() { assertThat(predicate.test(request)).isTrue(); } + @Test + public void pathWithContext() { + RequestPredicate predicate = RequestPredicates.path("/p*"); + MockServerHttpRequest mockRequest = MockServerHttpRequest.get("https://localhost/context/path") + .contextPath("/context").build(); + ServerRequest request = new DefaultServerRequest(MockServerWebExchange.from(mockRequest), Collections.emptyList()); + assertThat(predicate.test(request)).isTrue(); + } + @Test public void headers() { String name = "MyHeader"; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java index 67addf8f16a4..f0fba03886b0 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java @@ -51,7 +51,6 @@ import org.springframework.http.MediaType; import org.springframework.http.converter.GenericHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.server.PathContainer; import org.springframework.http.server.RequestPath; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.lang.Nullable; @@ -132,13 +131,8 @@ public UriBuilder uriBuilder() { } @Override - public String path() { - return pathContainer().value(); - } - - @Override - public PathContainer pathContainer() { - return this.requestPath.pathWithinApplication(); + public RequestPath requestPath() { + return this.requestPath; } @Override diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/PathResourceLookupFunction.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/PathResourceLookupFunction.java index d1965518add9..7079290f30a0 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/PathResourceLookupFunction.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/PathResourceLookupFunction.java @@ -55,7 +55,7 @@ public PathResourceLookupFunction(String pattern, Resource location) { @Override public Optional apply(ServerRequest request) { - PathContainer pathContainer = request.pathContainer(); + PathContainer pathContainer = request.requestPath().pathWithinApplication(); if (!this.pattern.matches(pathContainer)) { return Optional.empty(); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java index 0b33c63b8d2a..a83a40d618e4 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RequestPredicates.java @@ -21,7 +21,6 @@ import java.net.URI; import java.security.Principal; import java.time.Instant; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; @@ -51,6 +50,7 @@ import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.PathContainer; +import org.springframework.http.server.RequestPath; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -490,7 +490,7 @@ public PathPatternPredicate(PathPattern pattern) { @Override public boolean test(ServerRequest request) { - PathContainer pathContainer = request.pathContainer(); + PathContainer pathContainer = request.requestPath().pathWithinApplication(); PathPattern.PathMatchInfo info = this.pattern.matchAndExtract(pathContainer); traceMatch("Pattern", this.pattern.getPatternString(), request.path(), info != null); if (info != null) { @@ -516,7 +516,7 @@ private static void mergeAttributes(ServerRequest request, Map v @Override public Optional nest(ServerRequest request) { - return Optional.ofNullable(this.pattern.matchStartOfPath(request.pathContainer())) + return Optional.ofNullable(this.pattern.matchStartOfPath(request.requestPath().pathWithinApplication())) .map(info -> new SubPathServerRequestWrapper(request, info, this.pattern)); } @@ -924,17 +924,27 @@ private static class SubPathServerRequestWrapper implements ServerRequest { private final ServerRequest request; - private final PathContainer pathContainer; + private RequestPath requestPath; private final Map attributes; public SubPathServerRequestWrapper(ServerRequest request, PathPattern.PathRemainingMatchInfo info, PathPattern pattern) { this.request = request; - this.pathContainer = new SubPathContainer(info.getPathRemaining()); + this.requestPath = requestPath(request.requestPath(), info); this.attributes = mergeAttributes(request, info.getUriVariables(), pattern); } + private static RequestPath requestPath(RequestPath original, PathPattern.PathRemainingMatchInfo info) { + StringBuilder contextPath = new StringBuilder(original.contextPath().value()); + contextPath.append(info.getPathMatched().value()); + int length = contextPath.length(); + if (length > 0 && contextPath.charAt(length - 1) == '/') { + contextPath.setLength(length - 1); + } + return original.modifyContextPath(contextPath.toString()); + } + private static Map mergeAttributes(ServerRequest request, Map pathVariables, PathPattern pattern) { Map result = new ConcurrentHashMap<>(request.attributes()); @@ -970,13 +980,8 @@ public UriBuilder uriBuilder() { } @Override - public String path() { - return this.pathContainer.value(); - } - - @Override - public PathContainer pathContainer() { - return this.pathContainer; + public RequestPath requestPath() { + return this.requestPath; } @Override @@ -1084,46 +1089,6 @@ public String toString() { return method() + " " + path(); } - private static class SubPathContainer implements PathContainer { - - private static final PathContainer.Separator SEPARATOR = () -> "/"; - - - private final String value; - - private final List elements; - - public SubPathContainer(PathContainer original) { - this.value = prefixWithSlash(original.value()); - this.elements = prependWithSeparator(original.elements()); - } - - private static String prefixWithSlash(String path) { - if (!path.startsWith("/")) { - path = "/" + path; - } - return path; - } - - private static List prependWithSeparator(List elements) { - List result = new ArrayList<>(elements); - if (result.isEmpty() || !(result.get(0) instanceof Separator)) { - result.add(0, SEPARATOR); - } - return Collections.unmodifiableList(result); - } - - - @Override - public String value() { - return this.value; - } - - @Override - public List elements() { - return this.elements; - } - } } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/ServerRequest.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/ServerRequest.java index a76a1cab4202..00beac0420c8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/ServerRequest.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/ServerRequest.java @@ -43,10 +43,12 @@ import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.PathContainer; +import org.springframework.http.server.RequestPath; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.MultiValueMap; +import org.springframework.web.util.ServletRequestPathUtils; import org.springframework.web.util.UriBuilder; /** @@ -92,14 +94,24 @@ default HttpMethod method() { * Get the request path. */ default String path() { - return uri().getRawPath(); + return requestPath().pathWithinApplication().value(); } /** * Get the request path as a {@code PathContainer}. + * @deprecated as of 5.3, in favor on {@link #requestPath()} */ + @Deprecated default PathContainer pathContainer() { - return PathContainer.parsePath(path()); + return requestPath(); + } + + /** + * Get the request path as a {@code PathContainer}. + * @since 5.3 + */ + default RequestPath requestPath() { + return ServletRequestPathUtils.getParsedRequestPath(servletRequest()); } /** diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/RequestPredicatesTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/RequestPredicatesTests.java index 1cf7a57f0b0b..f030776ef905 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/function/RequestPredicatesTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/function/RequestPredicatesTests.java @@ -148,6 +148,13 @@ void pathPredicates() { assertThat(predicate.test(initRequest("GET", "/path"))).isTrue(); } + @Test + public void pathWithContext() { + RequestPredicate predicate = RequestPredicates.path("/p*"); + ServerRequest request = initRequest("GET", "/context/path", + servletRequest -> servletRequest.setContextPath("/context")); + assertThat(predicate.test(request)).isTrue(); + } @Test void headers() {