diff --git a/spring-web/src/main/java/org/springframework/http/server/DefaultRequestPath.java b/spring-web/src/main/java/org/springframework/http/server/DefaultRequestPath.java index afc94bfeb81..72587382134 100644 --- a/spring-web/src/main/java/org/springframework/http/server/DefaultRequestPath.java +++ b/spring-web/src/main/java/org/springframework/http/server/DefaultRequestPath.java @@ -55,8 +55,7 @@ class DefaultRequestPath implements RequestPath { return PathContainer.parseUrlPath(""); } - Assert.isTrue(contextPath.startsWith("/") && !contextPath.endsWith("/") && - path.value().startsWith(contextPath), "Invalid contextPath: " + contextPath); + validateContextPath(path.value(), contextPath); int length = contextPath.length(); int counter = 0; @@ -70,8 +69,24 @@ class DefaultRequestPath implements RequestPath { } // Should not happen.. - throw new IllegalStateException("Failed to initialize contextPath='" + contextPath + "'" + - " given path='" + path.value() + "'"); + throw new IllegalStateException("Failed to initialize contextPath '" + contextPath + "'" + + " for requestPath '" + path.value() + "'"); + } + + private static void validateContextPath(String fullPath, String contextPath) { + int length = contextPath.length(); + if (contextPath.charAt(0) != '/' || contextPath.charAt(length - 1) == '/') { + throw new IllegalArgumentException("Invalid contextPath: '" + contextPath + "': " + + "must start with '/' and not end with '/'"); + } + if (!fullPath.startsWith(contextPath)) { + throw new IllegalArgumentException("Invalid contextPath '" + contextPath + "': " + + "must match the start of requestPath: '" + fullPath + "'"); + } + if (fullPath.length() > length && fullPath.charAt(length) != '/') { + throw new IllegalArgumentException("Invalid contextPath '" + contextPath + "': " + + "must match to full path segments for requestPath: '" + fullPath + "'"); + } } private static PathContainer extractPathWithinApplication(PathContainer fullPath, PathContainer contextPath) { diff --git a/spring-web/src/main/java/org/springframework/http/server/RequestPath.java b/spring-web/src/main/java/org/springframework/http/server/RequestPath.java index d11212cacfb..cef7630018b 100644 --- a/spring-web/src/main/java/org/springframework/http/server/RequestPath.java +++ b/spring-web/src/main/java/org/springframework/http/server/RequestPath.java @@ -46,7 +46,7 @@ public interface RequestPath extends PathContainer { /** * Return a new {@code RequestPath} instance with a modified context path. - * The new context path must match the beginning of this request path. + * The new context path must match 0 or more path segments at the start. * @param contextPath the new context path * @return a new {@code RequestPath} instance */ diff --git a/spring-web/src/test/java/org/springframework/http/server/DefaultRequestPathTests.java b/spring-web/src/test/java/org/springframework/http/server/DefaultRequestPathTests.java index 359cbcfe8c8..51faa4a535e 100644 --- a/spring-web/src/test/java/org/springframework/http/server/DefaultRequestPathTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/DefaultRequestPathTests.java @@ -59,4 +59,19 @@ public class DefaultRequestPathTests { assertEquals(pathWithinApplication, requestPath.pathWithinApplication().value()); } + @Test + public void updateRequestPath() throws Exception { + + URI uri = URI.create("http://localhost:8080/aA/bB/cC"); + RequestPath requestPath = RequestPath.parse(uri, null); + + assertEquals("", requestPath.contextPath().value()); + assertEquals("/aA/bB/cC", requestPath.pathWithinApplication().value()); + + requestPath = requestPath.modifyContextPath("/aA"); + + assertEquals("/aA", requestPath.contextPath().value()); + assertEquals("/bB/cC", requestPath.pathWithinApplication().value()); + } + }