Merge branch '6.1.x'
This commit is contained in:
		
						commit
						25b57d4808
					
				| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright 2002-2023 the original author or authors.
 | 
			
		||||
 * Copyright 2002-2024 the original author or authors.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
| 
						 | 
				
			
			@ -41,6 +41,7 @@ import org.springframework.util.StringUtils;
 | 
			
		|||
 * {@link org.springframework.util.PathMatcher} otherwise.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Rossen Stoyanchev
 | 
			
		||||
 * @author Stephane Nicoll
 | 
			
		||||
 * @since 5.3
 | 
			
		||||
 */
 | 
			
		||||
public abstract class ServletRequestPathUtils {
 | 
			
		||||
| 
						 | 
				
			
			@ -186,14 +187,16 @@ public abstract class ServletRequestPathUtils {
 | 
			
		|||
	 */
 | 
			
		||||
	private static final class ServletRequestPath implements RequestPath {
 | 
			
		||||
 | 
			
		||||
		private final PathElements pathElements;
 | 
			
		||||
 | 
			
		||||
		private final RequestPath requestPath;
 | 
			
		||||
 | 
			
		||||
		private final PathContainer contextPath;
 | 
			
		||||
 | 
			
		||||
		private ServletRequestPath(String rawPath, @Nullable String contextPath, String servletPathPrefix) {
 | 
			
		||||
			Assert.notNull(servletPathPrefix, "`servletPathPrefix` is required");
 | 
			
		||||
			this.requestPath = RequestPath.parse(rawPath, contextPath + servletPathPrefix);
 | 
			
		||||
			this.contextPath = PathContainer.parsePath(StringUtils.hasText(contextPath) ? contextPath : "");
 | 
			
		||||
		private ServletRequestPath(PathElements pathElements) {
 | 
			
		||||
			this.pathElements = pathElements;
 | 
			
		||||
			this.requestPath = pathElements.createRequestPath();
 | 
			
		||||
			this.contextPath = pathElements.createContextPath();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		@Override
 | 
			
		||||
| 
						 | 
				
			
			@ -218,7 +221,7 @@ public abstract class ServletRequestPathUtils {
 | 
			
		|||
 | 
			
		||||
		@Override
 | 
			
		||||
		public RequestPath modifyContextPath(String contextPath) {
 | 
			
		||||
			throw new UnsupportedOperationException();
 | 
			
		||||
			return new ServletRequestPath(this.pathElements.withContextPath(contextPath));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +252,7 @@ public abstract class ServletRequestPathUtils {
 | 
			
		|||
			requestUri = (requestUri != null ? requestUri : request.getRequestURI());
 | 
			
		||||
			String servletPathPrefix = getServletPathPrefix(request);
 | 
			
		||||
			return (StringUtils.hasText(servletPathPrefix) ?
 | 
			
		||||
					new ServletRequestPath(requestUri, request.getContextPath(), servletPathPrefix) :
 | 
			
		||||
					new ServletRequestPath(new PathElements(requestUri, request.getContextPath(), servletPathPrefix)) :
 | 
			
		||||
					RequestPath.parse(requestUri, request.getContextPath()));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -265,6 +268,38 @@ public abstract class ServletRequestPathUtils {
 | 
			
		|||
			}
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		record PathElements(String rawPath, @Nullable String contextPath, String servletPathPrefix) {
 | 
			
		||||
 | 
			
		||||
			PathElements {
 | 
			
		||||
				Assert.notNull(servletPathPrefix, "`servletPathPrefix` is required");
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			private RequestPath createRequestPath() {
 | 
			
		||||
				return RequestPath.parse(this.rawPath, this.contextPath + this.servletPathPrefix);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			private PathContainer createContextPath() {
 | 
			
		||||
				return PathContainer.parsePath(StringUtils.hasText(this.contextPath) ? this.contextPath : "");
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			PathElements withContextPath(String contextPath) {
 | 
			
		||||
				if (!contextPath.startsWith("/") || contextPath.endsWith("/")) {
 | 
			
		||||
					throw new IllegalArgumentException("Invalid contextPath '" + contextPath + "': " +
 | 
			
		||||
							"must start with '/' and not end with '/'");
 | 
			
		||||
				}
 | 
			
		||||
				String contextPathToUse = this.servletPathPrefix + contextPath;
 | 
			
		||||
				if (StringUtils.hasText(this.contextPath())) {
 | 
			
		||||
					throw new IllegalStateException("Could not change context path to '" + contextPathToUse +
 | 
			
		||||
							"': a context path is already specified");
 | 
			
		||||
				}
 | 
			
		||||
				if (!this.rawPath.startsWith(contextPathToUse)) {
 | 
			
		||||
					throw new IllegalArgumentException("Invalid contextPath '" + contextPathToUse + "': " +
 | 
			
		||||
							"must match the start of requestPath: '" + this.rawPath + "'");
 | 
			
		||||
				}
 | 
			
		||||
				return new PathElements(this.rawPath, contextPathToUse, "");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,11 +24,14 @@ import org.springframework.web.testfixture.servlet.MockHttpServletMapping;
 | 
			
		|||
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for {@link ServletRequestPathUtils}.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Rossen Stoyanchev
 | 
			
		||||
 * @author Stephane Nicoll
 | 
			
		||||
 */
 | 
			
		||||
class ServletRequestPathUtilsTests {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,19 +50,63 @@ class ServletRequestPathUtilsTests {
 | 
			
		|||
		testParseAndCache("/app/servlet/a//", "/app", "/servlet", "/a//");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void modifyPathContextWithExistingContextPath() {
 | 
			
		||||
		RequestPath requestPath = createRequestPath("/app/api/persons/42", "/app", "/api", "/persons/42");
 | 
			
		||||
		assertThatIllegalStateException().isThrownBy(() -> requestPath.modifyContextPath("/persons"))
 | 
			
		||||
				.withMessage("Could not change context path to '/api/persons': a context path is already specified");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void modifyPathContextWhenContextPathIsNotInThePath() {
 | 
			
		||||
		RequestPath requestPath = createRequestPath("/api/persons/42", "", "/api", "/persons/42");
 | 
			
		||||
		assertThatIllegalArgumentException().isThrownBy(() -> requestPath.modifyContextPath("/something"))
 | 
			
		||||
				.withMessage("Invalid contextPath '/api/something': " +
 | 
			
		||||
						"must match the start of requestPath: '/api/persons/42'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void modifyPathContextReplacesServletPath() {
 | 
			
		||||
		RequestPath requestPath = createRequestPath("/api/persons/42", "", "/api", "/persons/42");
 | 
			
		||||
		RequestPath updatedRequestPath = requestPath.modifyContextPath("/persons");
 | 
			
		||||
		assertThat(updatedRequestPath.contextPath().value()).isEqualTo("/api/persons");
 | 
			
		||||
		assertThat(updatedRequestPath.pathWithinApplication().value()).isEqualTo("/42");
 | 
			
		||||
		assertThat(updatedRequestPath.value()).isEqualTo("/api/persons/42");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void modifyPathContextWithContextPathNotStartingWithSlash() {
 | 
			
		||||
		RequestPath requestPath = createRequestPath("/api/persons/42", "", "/api", "/persons/42");
 | 
			
		||||
		assertThatIllegalArgumentException().isThrownBy(() -> requestPath.modifyContextPath("persons"))
 | 
			
		||||
				.withMessage("Invalid contextPath 'persons': must start with '/' and not end with '/'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	void modifyPathContextWithContextPathEndingWithSlash() {
 | 
			
		||||
		RequestPath requestPath = createRequestPath("/api/persons/42", "", "/api", "/persons/42");
 | 
			
		||||
		assertThatIllegalArgumentException().isThrownBy(() -> requestPath.modifyContextPath("/persons/"))
 | 
			
		||||
				.withMessage("Invalid contextPath '/persons/': must start with '/' and not end with '/'");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void testParseAndCache(
 | 
			
		||||
			String requestUri, String contextPath, String servletPath, String pathWithinApplication) {
 | 
			
		||||
 | 
			
		||||
		RequestPath requestPath = createRequestPath(requestUri, contextPath, servletPath, pathWithinApplication);
 | 
			
		||||
 | 
			
		||||
		assertThat(requestPath.contextPath().value()).isEqualTo(contextPath);
 | 
			
		||||
		assertThat(requestPath.pathWithinApplication().value()).isEqualTo(pathWithinApplication);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private static RequestPath createRequestPath(
 | 
			
		||||
			String requestUri, String contextPath, String servletPath, String pathWithinApplication) {
 | 
			
		||||
 | 
			
		||||
		MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
 | 
			
		||||
		request.setContextPath(contextPath);
 | 
			
		||||
		request.setServletPath(servletPath);
 | 
			
		||||
		request.setHttpServletMapping(new MockHttpServletMapping(
 | 
			
		||||
				pathWithinApplication, contextPath, "myServlet", MappingMatch.PATH));
 | 
			
		||||
 | 
			
		||||
		RequestPath requestPath = ServletRequestPathUtils.parseAndCache(request);
 | 
			
		||||
 | 
			
		||||
		assertThat(requestPath.contextPath().value()).isEqualTo(contextPath);
 | 
			
		||||
		assertThat(requestPath.pathWithinApplication().value()).isEqualTo(pathWithinApplication);
 | 
			
		||||
		return ServletRequestPathUtils.parseAndCache(request);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue