Expose RequestPath in ServerHttpRequest
The new structured getPath() method replaces the existing getContextPath() + getPathWithinApplication(). Issue: SPR-15648
This commit is contained in:
parent
2d17411ec4
commit
38a12ed4ba
|
@ -56,8 +56,6 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
|
|
||||||
private final HttpMethod httpMethod;
|
private final HttpMethod httpMethod;
|
||||||
|
|
||||||
private final String contextPath;
|
|
||||||
|
|
||||||
private final MultiValueMap<String, HttpCookie> cookies;
|
private final MultiValueMap<String, HttpCookie> cookies;
|
||||||
|
|
||||||
private final InetSocketAddress remoteAddress;
|
private final InetSocketAddress remoteAddress;
|
||||||
|
@ -70,9 +68,8 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
InetSocketAddress remoteAddress,
|
InetSocketAddress remoteAddress,
|
||||||
Publisher<? extends DataBuffer> body) {
|
Publisher<? extends DataBuffer> body) {
|
||||||
|
|
||||||
super(uri, headers);
|
super(uri, contextPath, headers);
|
||||||
this.httpMethod = httpMethod;
|
this.httpMethod = httpMethod;
|
||||||
this.contextPath = contextPath;
|
|
||||||
this.cookies = cookies;
|
this.cookies = cookies;
|
||||||
this.remoteAddress = remoteAddress;
|
this.remoteAddress = remoteAddress;
|
||||||
this.body = Flux.from(body);
|
this.body = Flux.from(body);
|
||||||
|
@ -89,11 +86,6 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
return this.httpMethod.name();
|
return this.httpMethod.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getContextPath() {
|
|
||||||
return this.contextPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress getRemoteAddress() {
|
public InetSocketAddress getRemoteAddress() {
|
||||||
return this.remoteAddress;
|
return this.remoteAddress;
|
||||||
|
|
|
@ -41,6 +41,8 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||||
|
|
||||||
private final URI uri;
|
private final URI uri;
|
||||||
|
|
||||||
|
private final RequestPath path;
|
||||||
|
|
||||||
private final HttpHeaders headers;
|
private final HttpHeaders headers;
|
||||||
|
|
||||||
private MultiValueMap<String, String> queryParams;
|
private MultiValueMap<String, String> queryParams;
|
||||||
|
@ -51,10 +53,12 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||||
/**
|
/**
|
||||||
* Constructor with the URI and headers for the request.
|
* Constructor with the URI and headers for the request.
|
||||||
* @param uri the URI for the request
|
* @param uri the URI for the request
|
||||||
|
* @param contextPath the context path for the request
|
||||||
* @param headers the headers for the request
|
* @param headers the headers for the request
|
||||||
*/
|
*/
|
||||||
public AbstractServerHttpRequest(URI uri, HttpHeaders headers) {
|
public AbstractServerHttpRequest(URI uri, String contextPath, HttpHeaders headers) {
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
|
this.path = new DefaultRequestPath(uri, contextPath, StandardCharsets.UTF_8);
|
||||||
this.headers = HttpHeaders.readOnlyHttpHeaders(headers);
|
this.headers = HttpHeaders.readOnlyHttpHeaders(headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +68,11 @@ public abstract class AbstractServerHttpRequest implements ServerHttpRequest {
|
||||||
return this.uri;
|
return this.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestPath getPath() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HttpHeaders getHeaders() {
|
public HttpHeaders getHeaders() {
|
||||||
return this.headers;
|
return this.headers;
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.springframework.util.Assert;
|
||||||
* <p>This is intended as a coarse-grained mechanism for delegating requests to
|
* <p>This is intended as a coarse-grained mechanism for delegating requests to
|
||||||
* one of several applications -- each represented by an {@code HttpHandler}, with
|
* one of several applications -- each represented by an {@code HttpHandler}, with
|
||||||
* the application "context path" (the prefix-based mapping) exposed via
|
* the application "context path" (the prefix-based mapping) exposed via
|
||||||
* {@link ServerHttpRequest#getContextPath()}.
|
* {@link ServerHttpRequest#getPath()}.
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
|
@ -49,12 +49,12 @@ public class ContextPathCompositeHandler implements HttpHandler {
|
||||||
@Override
|
@Override
|
||||||
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
|
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
|
||||||
// Remove underlying context path first (e.g. Servlet container)
|
// Remove underlying context path first (e.g. Servlet container)
|
||||||
String path = request.getPathWithinApplication();
|
String path = request.getPath().pathWithinApplication().value();
|
||||||
return this.handlerMap.entrySet().stream()
|
return this.handlerMap.entrySet().stream()
|
||||||
.filter(entry -> path.startsWith(entry.getKey()))
|
.filter(entry -> path.startsWith(entry.getKey()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.map(entry -> {
|
.map(entry -> {
|
||||||
String contextPath = request.getContextPath() + entry.getKey();
|
String contextPath = request.getPath().contextPath().value() + entry.getKey();
|
||||||
ServerHttpRequest newRequest = request.mutate().contextPath(contextPath).build();
|
ServerHttpRequest newRequest = request.mutate().contextPath(contextPath).build();
|
||||||
return entry.getValue().handle(newRequest, response);
|
return entry.getValue().handle(newRequest, response);
|
||||||
})
|
})
|
||||||
|
|
|
@ -58,6 +58,11 @@ class DefaultRequestPath implements RequestPath {
|
||||||
this.pathWithinApplication = initPathWithinApplication(this.fullPath, this.contextPath);
|
this.pathWithinApplication = initPathWithinApplication(this.fullPath, this.contextPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefaultRequestPath(RequestPath requestPath, String contextPath, Charset charset) {
|
||||||
|
this.fullPath = new DefaultPathSegmentContainer(requestPath.value(), requestPath.pathSegments());
|
||||||
|
this.contextPath = initContextPath(this.fullPath, contextPath);
|
||||||
|
this.pathWithinApplication = initPathWithinApplication(this.fullPath, this.contextPath);
|
||||||
|
}
|
||||||
|
|
||||||
private static PathSegmentContainer parsePath(String path, Charset charset) {
|
private static PathSegmentContainer parsePath(String path, Charset charset) {
|
||||||
path = StringUtils.hasText(path) ? path : "";
|
path = StringUtils.hasText(path) ? path : "";
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.springframework.http.server.reactive;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
|
@ -79,18 +80,51 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ServerHttpRequest build() {
|
public ServerHttpRequest build() {
|
||||||
URI uri = null;
|
URI uriToUse = getUriToUse();
|
||||||
if (this.path != null) {
|
RequestPath path = getRequestPathToUse(uriToUse);
|
||||||
uri = this.delegate.getURI();
|
HttpHeaders headers = getHeadersToUse();
|
||||||
try {
|
return new MutativeDecorator(this.delegate, this.httpMethod, uriToUse, path, headers);
|
||||||
uri = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
|
}
|
||||||
this.path, uri.getQuery(), uri.getFragment());
|
|
||||||
}
|
@Nullable
|
||||||
catch (URISyntaxException ex) {
|
private URI getUriToUse() {
|
||||||
throw new IllegalStateException("Invalid URI path: \"" + this.path + "\"");
|
if (this.path == null) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
URI uri = this.delegate.getURI();
|
||||||
|
try {
|
||||||
|
return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
|
||||||
|
this.path, uri.getQuery(), uri.getFragment());
|
||||||
|
}
|
||||||
|
catch (URISyntaxException ex) {
|
||||||
|
throw new IllegalStateException("Invalid URI path: \"" + this.path + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private RequestPath getRequestPathToUse(@Nullable URI uriToUse) {
|
||||||
|
if (uriToUse == null && this.contextPath == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else if (uriToUse == null) {
|
||||||
|
return new DefaultRequestPath(this.delegate.getPath(), this.contextPath, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new DefaultRequestPath(uriToUse, this.contextPath, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private HttpHeaders getHeadersToUse() {
|
||||||
|
if (this.httpHeaders != null) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.putAll(this.delegate.getHeaders());
|
||||||
|
headers.putAll(this.httpHeaders);
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return new MutativeDecorator(this.delegate, this.httpMethod, uri, this.contextPath, this.httpHeaders);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,25 +138,20 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
|
||||||
|
|
||||||
private final URI uri;
|
private final URI uri;
|
||||||
|
|
||||||
private final String contextPath;
|
private final RequestPath requestPath;
|
||||||
|
|
||||||
private final HttpHeaders httpHeaders;
|
private final HttpHeaders httpHeaders;
|
||||||
|
|
||||||
public MutativeDecorator(ServerHttpRequest delegate, HttpMethod httpMethod,
|
|
||||||
@Nullable URI uri, String contextPath, @Nullable HttpHeaders httpHeaders) {
|
public MutativeDecorator(ServerHttpRequest delegate, HttpMethod method,
|
||||||
|
@Nullable URI uri, @Nullable RequestPath requestPath,
|
||||||
|
@Nullable HttpHeaders httpHeaders) {
|
||||||
|
|
||||||
super(delegate);
|
super(delegate);
|
||||||
this.httpMethod = httpMethod;
|
this.httpMethod = method;
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.contextPath = contextPath;
|
this.requestPath = requestPath;
|
||||||
if (httpHeaders != null) {
|
this.httpHeaders = httpHeaders;
|
||||||
this.httpHeaders = new HttpHeaders();
|
|
||||||
this.httpHeaders.putAll(super.getHeaders());
|
|
||||||
this.httpHeaders.putAll(httpHeaders);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.httpHeaders = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -136,8 +165,8 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getContextPath() {
|
public RequestPath getPath() {
|
||||||
return (this.contextPath != null ? this.contextPath : super.getContextPath());
|
return (this.requestPath != null ? this.requestPath : super.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class ReactorServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
public ReactorServerHttpRequest(HttpServerRequest request, NettyDataBufferFactory bufferFactory)
|
public ReactorServerHttpRequest(HttpServerRequest request, NettyDataBufferFactory bufferFactory)
|
||||||
throws URISyntaxException {
|
throws URISyntaxException {
|
||||||
|
|
||||||
super(initUri(request), initHeaders(request));
|
super(initUri(request), "", initHeaders(request));
|
||||||
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
|
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
|
||||||
this.request = request;
|
this.request = request;
|
||||||
this.bufferFactory = bufferFactory;
|
this.bufferFactory = bufferFactory;
|
||||||
|
|
|
@ -24,7 +24,12 @@ package org.springframework.http.server.reactive;
|
||||||
public interface RequestPath extends PathSegmentContainer {
|
public interface RequestPath extends PathSegmentContainer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The contextPath portion of the request if any.
|
* Returns the portion of the URL path that represents the application.
|
||||||
|
* The context path is always at the beginning of the path and starts but
|
||||||
|
* does not end with "/". It is shared for URLs of the same application.
|
||||||
|
* <p>The context path may come from the underlying runtime API such as
|
||||||
|
* when deploying as a WAR to a Servlet container or it may also be assigned
|
||||||
|
* through the use of {@link ContextPathCompositeHandler} or both.
|
||||||
*/
|
*/
|
||||||
PathSegmentContainer contextPath();
|
PathSegmentContainer contextPath();
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.springframework.http.HttpRequest;
|
||||||
import org.springframework.http.ReactiveHttpInputMessage;
|
import org.springframework.http.ReactiveHttpInputMessage;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a reactive server-side HTTP request
|
* Represents a reactive server-side HTTP request
|
||||||
|
@ -36,35 +35,11 @@ import org.springframework.util.StringUtils;
|
||||||
public interface ServerHttpRequest extends HttpRequest, ReactiveHttpInputMessage {
|
public interface ServerHttpRequest extends HttpRequest, ReactiveHttpInputMessage {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the portion of the URL path that represents the application.
|
* Returns a structured representation of the request path including the
|
||||||
* The context path is always at the beginning of the path and starts but
|
* context path + path within application portions, path segments with
|
||||||
* does not end with "/". It is shared for URLs of the same application.
|
* encoded and decoded values, and path parameters.
|
||||||
* <p>The context path may come from the underlying runtime API such as
|
|
||||||
* when deploying as a WAR to a Servlet container or it may also be assigned
|
|
||||||
* through the use of {@link ContextPathCompositeHandler} or both.
|
|
||||||
* <p>The context path is not decoded.
|
|
||||||
* @return the context path (not decoded) or an empty string
|
|
||||||
*/
|
*/
|
||||||
default String getContextPath() {
|
RequestPath getPath();
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the portion of the URL path after the {@link #getContextPath()
|
|
||||||
* contextPath}. The returned path is not decoded.
|
|
||||||
* @return the path under the contextPath
|
|
||||||
*/
|
|
||||||
default String getPathWithinApplication() {
|
|
||||||
String path = getURI().getRawPath();
|
|
||||||
String contextPath = getContextPath();
|
|
||||||
if (StringUtils.hasText(contextPath)) {
|
|
||||||
int length = contextPath.length();
|
|
||||||
return (path.length() > length ? path.substring(length) : "");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a read-only map with parsed and decoded query parameter values.
|
* Return a read-only map with parsed and decoded query parameter values.
|
||||||
|
@ -104,12 +79,13 @@ public interface ServerHttpRequest extends HttpRequest, ReactiveHttpInputMessage
|
||||||
Builder method(HttpMethod httpMethod);
|
Builder method(HttpMethod httpMethod);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the request URI to return.
|
* Set the path to use instead of the {@code "rawPath"} of
|
||||||
|
* {@link ServerHttpRequest#getURI()}.
|
||||||
*/
|
*/
|
||||||
Builder path(String path);
|
Builder path(String path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the contextPath to return.
|
* Set the contextPath to use.
|
||||||
*/
|
*/
|
||||||
Builder contextPath(String contextPath);
|
Builder contextPath(String contextPath);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,11 @@ public class ServerHttpRequestDecorator implements ServerHttpRequest {
|
||||||
return getDelegate().getURI();
|
return getDelegate().getURI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestPath getPath() {
|
||||||
|
return getDelegate().getPath();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MultiValueMap<String, String> getQueryParams() {
|
public MultiValueMap<String, String> getQueryParams() {
|
||||||
return getDelegate().getQueryParams();
|
return getDelegate().getQueryParams();
|
||||||
|
|
|
@ -72,7 +72,7 @@ public class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
public ServletServerHttpRequest(HttpServletRequest request, AsyncContext asyncContext,
|
public ServletServerHttpRequest(HttpServletRequest request, AsyncContext asyncContext,
|
||||||
DataBufferFactory bufferFactory, int bufferSize) throws IOException {
|
DataBufferFactory bufferFactory, int bufferSize) throws IOException {
|
||||||
|
|
||||||
super(initUri(request), initHeaders(request));
|
super(initUri(request), request.getContextPath(), initHeaders(request));
|
||||||
|
|
||||||
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
|
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
|
||||||
Assert.isTrue(bufferSize > 0, "'bufferSize' must be higher than 0");
|
Assert.isTrue(bufferSize > 0, "'bufferSize' must be higher than 0");
|
||||||
|
@ -154,11 +154,6 @@ public class ServletServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
return getServletRequest().getMethod();
|
return getServletRequest().getMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getContextPath() {
|
|
||||||
return getServletRequest().getContextPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MultiValueMap<String, HttpCookie> initCookies() {
|
protected MultiValueMap<String, HttpCookie> initCookies() {
|
||||||
MultiValueMap<String, HttpCookie> httpCookies = new LinkedMultiValueMap<>();
|
MultiValueMap<String, HttpCookie> httpCookies = new LinkedMultiValueMap<>();
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class UndertowServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
|
|
||||||
|
|
||||||
public UndertowServerHttpRequest(HttpServerExchange exchange, DataBufferFactory bufferFactory) {
|
public UndertowServerHttpRequest(HttpServerExchange exchange, DataBufferFactory bufferFactory) {
|
||||||
super(initUri(exchange), initHeaders(exchange));
|
super(initUri(exchange), "", initHeaders(exchange));
|
||||||
this.exchange = exchange;
|
this.exchange = exchange;
|
||||||
this.body = new RequestBodyPublisher(exchange, bufferFactory);
|
this.body = new RequestBodyPublisher(exchange, bufferFactory);
|
||||||
this.body.registerListeners(exchange);
|
this.body.registerListeners(exchange);
|
||||||
|
|
|
@ -80,7 +80,7 @@ public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CorsConfiguration getCorsConfiguration(ServerWebExchange exchange) {
|
public CorsConfiguration getCorsConfiguration(ServerWebExchange exchange) {
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
for (Map.Entry<String, CorsConfiguration> entry : this.corsConfigurations.entrySet()) {
|
for (Map.Entry<String, CorsConfiguration> entry : this.corsConfigurations.entrySet()) {
|
||||||
if (this.pathMatcher.match(entry.getKey(), lookupPath)) {
|
if (this.pathMatcher.match(entry.getKey(), lookupPath)) {
|
||||||
return entry.getValue();
|
return entry.getValue();
|
||||||
|
|
|
@ -105,7 +105,7 @@ public class ContextPathCompositeHandlerTests {
|
||||||
new ContextPathCompositeHandler(map).handle(request, new MockServerHttpResponse());
|
new ContextPathCompositeHandler(map).handle(request, new MockServerHttpResponse());
|
||||||
|
|
||||||
assertTrue(handler.wasInvoked());
|
assertTrue(handler.wasInvoked());
|
||||||
assertEquals("/yet/another/path", handler.getRequest().getContextPath());
|
assertEquals("/yet/another/path", handler.getRequest().getPath().contextPath().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -133,7 +133,7 @@ public class ContextPathCompositeHandlerTests {
|
||||||
|
|
||||||
private void assertInvoked(TestHttpHandler handler, String contextPath) {
|
private void assertInvoked(TestHttpHandler handler, String contextPath) {
|
||||||
assertTrue(handler.wasInvoked());
|
assertTrue(handler.wasInvoked());
|
||||||
assertEquals(contextPath, handler.getRequest().getContextPath());
|
assertEquals(contextPath, handler.getRequest().getPath().contextPath().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertNotInvoked(TestHttpHandler... handlers) {
|
private void assertNotInvoked(TestHttpHandler... handlers) {
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class RxNettyServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
NettyDataBufferFactory dataBufferFactory, InetSocketAddress remoteAddress)
|
NettyDataBufferFactory dataBufferFactory, InetSocketAddress remoteAddress)
|
||||||
throws URISyntaxException {
|
throws URISyntaxException {
|
||||||
|
|
||||||
super(initUri(request, remoteAddress), initHeaders(request));
|
super(initUri(request, remoteAddress), "", initHeaders(request));
|
||||||
this.request = request;
|
this.request = request;
|
||||||
|
|
||||||
Assert.notNull(dataBufferFactory, "NettyDataBufferFactory must not be null");
|
Assert.notNull(dataBufferFactory, "NettyDataBufferFactory must not be null");
|
||||||
|
|
|
@ -56,8 +56,6 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
|
|
||||||
private final HttpMethod httpMethod;
|
private final HttpMethod httpMethod;
|
||||||
|
|
||||||
private final String contextPath;
|
|
||||||
|
|
||||||
private final MultiValueMap<String, HttpCookie> cookies;
|
private final MultiValueMap<String, HttpCookie> cookies;
|
||||||
|
|
||||||
private final InetSocketAddress remoteAddress;
|
private final InetSocketAddress remoteAddress;
|
||||||
|
@ -70,9 +68,8 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
InetSocketAddress remoteAddress,
|
InetSocketAddress remoteAddress,
|
||||||
Publisher<? extends DataBuffer> body) {
|
Publisher<? extends DataBuffer> body) {
|
||||||
|
|
||||||
super(uri, headers);
|
super(uri, contextPath, headers);
|
||||||
this.httpMethod = httpMethod;
|
this.httpMethod = httpMethod;
|
||||||
this.contextPath = (contextPath != null ? contextPath : "");
|
|
||||||
this.cookies = cookies;
|
this.cookies = cookies;
|
||||||
this.remoteAddress = remoteAddress;
|
this.remoteAddress = remoteAddress;
|
||||||
this.body = Flux.from(body);
|
this.body = Flux.from(body);
|
||||||
|
@ -89,11 +86,6 @@ public class MockServerHttpRequest extends AbstractServerHttpRequest {
|
||||||
return this.httpMethod.name();
|
return this.httpMethod.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getContextPath() {
|
|
||||||
return this.contextPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InetSocketAddress getRemoteAddress() {
|
public InetSocketAddress getRemoteAddress() {
|
||||||
return this.remoteAddress;
|
return this.remoteAddress;
|
||||||
|
|
|
@ -100,7 +100,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<Object> getHandlerInternal(ServerWebExchange exchange) {
|
public Mono<Object> getHandlerInternal(ServerWebExchange exchange) {
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
Object handler;
|
Object handler;
|
||||||
try {
|
try {
|
||||||
handler = lookupHandler(lookupPath, exchange);
|
handler = lookupHandler(lookupPath, exchange);
|
||||||
|
|
|
@ -166,7 +166,7 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
|
||||||
private int getLookupPathIndex(ServerWebExchange exchange) {
|
private int getLookupPathIndex(ServerWebExchange exchange) {
|
||||||
ServerHttpRequest request = exchange.getRequest();
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
String requestPath = request.getURI().getPath();
|
String requestPath = request.getURI().getPath();
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
return requestPath.indexOf(lookupPath);
|
return requestPath.indexOf(lookupPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
List<String> matches = getMatchingPatterns(lookupPath);
|
List<String> matches = getMatchingPatterns(lookupPath);
|
||||||
|
|
||||||
return matches.isEmpty() ? null :
|
return matches.isEmpty() ? null :
|
||||||
|
@ -243,7 +243,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(PatternsRequestCondition other, ServerWebExchange exchange) {
|
public int compareTo(PatternsRequestCondition other, ServerWebExchange exchange) {
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
Comparator<String> patternComparator = this.pathMatcher.getPatternComparator(lookupPath);
|
Comparator<String> patternComparator = this.pathMatcher.getPatternComparator(lookupPath);
|
||||||
Iterator<String> iterator = this.patterns.iterator();
|
Iterator<String> iterator = this.patterns.iterator();
|
||||||
Iterator<String> iteratorOther = other.patterns.iterator();
|
Iterator<String> iteratorOther = other.patterns.iterator();
|
||||||
|
|
|
@ -257,7 +257,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
|
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Looking up handler method for path " + lookupPath);
|
logger.debug("Looking up handler method for path " + lookupPath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,9 +202,11 @@ public class RedirectView extends AbstractUrlBasedView {
|
||||||
String url = getUrl();
|
String url = getUrl();
|
||||||
Assert.state(url != null, "'url' not set");
|
Assert.state(url != null, "'url' not set");
|
||||||
|
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
|
||||||
StringBuilder targetUrl = new StringBuilder();
|
StringBuilder targetUrl = new StringBuilder();
|
||||||
if (isContextRelative() && url.startsWith("/")) {
|
if (isContextRelative() && url.startsWith("/")) {
|
||||||
targetUrl.append(exchange.getRequest().getContextPath());
|
targetUrl.append(request.getPath().contextPath().value());
|
||||||
}
|
}
|
||||||
targetUrl.append(url);
|
targetUrl.append(url);
|
||||||
|
|
||||||
|
@ -214,7 +216,7 @@ public class RedirectView extends AbstractUrlBasedView {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPropagateQuery()) {
|
if (isPropagateQuery()) {
|
||||||
targetUrl = appendCurrentRequestQuery(targetUrl.toString(), exchange.getRequest());
|
targetUrl = appendCurrentRequestQuery(targetUrl.toString(), request);
|
||||||
}
|
}
|
||||||
|
|
||||||
String result = targetUrl.toString();
|
String result = targetUrl.toString();
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.springframework.context.NoSuchMessageException;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.validation.BindException;
|
import org.springframework.validation.BindException;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.validation.Errors;
|
import org.springframework.validation.Errors;
|
||||||
|
@ -180,10 +181,10 @@ public class RequestContext {
|
||||||
/**
|
/**
|
||||||
* Return the context path of the current web application. This is
|
* Return the context path of the current web application. This is
|
||||||
* useful for building links to other resources within the application.
|
* useful for building links to other resources within the application.
|
||||||
* <p>Delegates to {@link ServerHttpRequest#getContextPath()}.
|
* <p>Delegates to {@link ServerHttpRequest#getPath()}.
|
||||||
*/
|
*/
|
||||||
public String getContextPath() {
|
public String getContextPath() {
|
||||||
return this.exchange.getRequest().getContextPath();
|
return this.exchange.getRequest().getPath().contextPath().value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,7 +194,7 @@ public class RequestContext {
|
||||||
* absolute path also URL-encoded accordingly
|
* absolute path also URL-encoded accordingly
|
||||||
*/
|
*/
|
||||||
public String getContextUrl(String relativeUrl) {
|
public String getContextUrl(String relativeUrl) {
|
||||||
String url = getContextPath() + relativeUrl;
|
String url = StringUtils.applyRelativePath(getContextPath() + "/", relativeUrl);
|
||||||
return getExchange().getResponse().encodeUrl(url);
|
return getExchange().getResponse().encodeUrl(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +209,7 @@ public class RequestContext {
|
||||||
* absolute path also URL-encoded accordingly
|
* absolute path also URL-encoded accordingly
|
||||||
*/
|
*/
|
||||||
public String getContextUrl(String relativeUrl, Map<String, ?> params) {
|
public String getContextUrl(String relativeUrl, Map<String, ?> params) {
|
||||||
String url = getContextPath() + relativeUrl;
|
String url = StringUtils.applyRelativePath(getContextPath() + "/", relativeUrl);
|
||||||
UriTemplate template = new UriTemplate(url);
|
UriTemplate template = new UriTemplate(url);
|
||||||
url = template.expand(params).toASCIIString();
|
url = template.expand(params).toASCIIString();
|
||||||
return getExchange().getResponse().encodeUrl(url);
|
return getExchange().getResponse().encodeUrl(url);
|
||||||
|
|
|
@ -258,7 +258,7 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
|
||||||
* Use the request path the leading and trailing slash stripped.
|
* Use the request path the leading and trailing slash stripped.
|
||||||
*/
|
*/
|
||||||
private String getDefaultViewName(ServerWebExchange exchange) {
|
private String getDefaultViewName(ServerWebExchange exchange) {
|
||||||
String path = exchange.getRequest().getPathWithinApplication();
|
String path = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
if (path.startsWith("/")) {
|
if (path.startsWith("/")) {
|
||||||
path = path.substring(1);
|
path = path.substring(1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void handleMatchUriTemplateVariables() throws Exception {
|
public void handleMatchUriTemplateVariables() throws Exception {
|
||||||
ServerWebExchange exchange = get("/1/2").toExchange();
|
ServerWebExchange exchange = get("/1/2").toExchange();
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
|
|
||||||
RequestMappingInfo key = paths("/{path1}/{path2}").build();
|
RequestMappingInfo key = paths("/{path1}/{path2}").build();
|
||||||
this.handlerMapping.handleMatch(key, lookupPath, exchange);
|
this.handlerMapping.handleMatch(key, lookupPath, exchange);
|
||||||
|
@ -232,7 +232,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||||
URI url = URI.create("/group/a%2Fb");
|
URI url = URI.create("/group/a%2Fb");
|
||||||
ServerWebExchange exchange = method(HttpMethod.GET, url).toExchange();
|
ServerWebExchange exchange = method(HttpMethod.GET, url).toExchange();
|
||||||
|
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
this.handlerMapping.handleMatch(key, lookupPath, exchange);
|
this.handlerMapping.handleMatch(key, lookupPath, exchange);
|
||||||
|
|
||||||
String name = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
|
String name = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE;
|
||||||
|
@ -248,7 +248,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||||
public void handleMatchBestMatchingPatternAttribute() throws Exception {
|
public void handleMatchBestMatchingPatternAttribute() throws Exception {
|
||||||
RequestMappingInfo key = paths("/{path1}/2", "/**").build();
|
RequestMappingInfo key = paths("/{path1}/2", "/**").build();
|
||||||
ServerWebExchange exchange = get("/1/2").toExchange();
|
ServerWebExchange exchange = get("/1/2").toExchange();
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
this.handlerMapping.handleMatch(key, lookupPath, exchange);
|
this.handlerMapping.handleMatch(key, lookupPath, exchange);
|
||||||
|
|
||||||
assertEquals("/{path1}/2", exchange.getAttributes().get(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE));
|
assertEquals("/{path1}/2", exchange.getAttributes().get(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE));
|
||||||
|
@ -258,7 +258,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||||
public void handleMatchBestMatchingPatternAttributeNoPatternsDefined() throws Exception {
|
public void handleMatchBestMatchingPatternAttributeNoPatternsDefined() throws Exception {
|
||||||
RequestMappingInfo key = paths().build();
|
RequestMappingInfo key = paths().build();
|
||||||
ServerWebExchange exchange = get("/1/2").toExchange();
|
ServerWebExchange exchange = get("/1/2").toExchange();
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
this.handlerMapping.handleMatch(key, lookupPath, exchange);
|
this.handlerMapping.handleMatch(key, lookupPath, exchange);
|
||||||
|
|
||||||
assertEquals("/1/2", exchange.getAttributes().get(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE));
|
assertEquals("/1/2", exchange.getAttributes().get(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE));
|
||||||
|
@ -367,7 +367,7 @@ public class RequestMappingInfoHandlerMappingTests {
|
||||||
|
|
||||||
private void handleMatch(ServerWebExchange exchange, String pattern) {
|
private void handleMatch(ServerWebExchange exchange, String pattern) {
|
||||||
RequestMappingInfo info = paths(pattern).build();
|
RequestMappingInfo info = paths(pattern).build();
|
||||||
String lookupPath = exchange.getRequest().getPathWithinApplication();
|
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||||
this.handlerMapping.handleMatch(info, lookupPath, exchange);
|
this.handlerMapping.handleMatch(info, lookupPath, exchange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ public class ContextPathIntegrationTests {
|
||||||
|
|
||||||
@GetMapping("/test")
|
@GetMapping("/test")
|
||||||
public String handle(ServerHttpRequest request) {
|
public String handle(ServerHttpRequest request) {
|
||||||
return "Tested in " + request.getContextPath();
|
return "Tested in " + request.getPath().contextPath().value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class RedirectViewTests {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.exchange = MockServerHttpRequest.get("/").contextPath("/context").toExchange();
|
this.exchange = MockServerHttpRequest.get("/context/path").contextPath("/context").toExchange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,8 @@ import static org.junit.Assert.assertEquals;
|
||||||
*/
|
*/
|
||||||
public class RequestContextTests {
|
public class RequestContextTests {
|
||||||
|
|
||||||
private final MockServerWebExchange exchange = MockServerHttpRequest.get("/").contextPath("foo/").toExchange();
|
private final MockServerWebExchange exchange = MockServerHttpRequest.get("/foo/path")
|
||||||
|
.contextPath("/foo").toExchange();
|
||||||
|
|
||||||
private GenericApplicationContext applicationContext;
|
private GenericApplicationContext applicationContext;
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ public class RequestContextTests {
|
||||||
@Test
|
@Test
|
||||||
public void testGetContextUrl() throws Exception {
|
public void testGetContextUrl() throws Exception {
|
||||||
RequestContext context = new RequestContext(this.exchange, this.model, this.applicationContext);
|
RequestContext context = new RequestContext(this.exchange, this.model, this.applicationContext);
|
||||||
assertEquals("foo/bar", context.getContextUrl("bar"));
|
assertEquals("/foo/bar", context.getContextUrl("bar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -59,7 +60,7 @@ public class RequestContextTests {
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("foo", "bar");
|
map.put("foo", "bar");
|
||||||
map.put("spam", "bucket");
|
map.put("spam", "bucket");
|
||||||
assertEquals("foo/bar?spam=bucket", context.getContextUrl("{foo}?spam={spam}", map));
|
assertEquals("/foo/bar?spam=bucket", context.getContextUrl("{foo}?spam={spam}", map));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -68,7 +69,7 @@ public class RequestContextTests {
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
map.put("foo", "bar baz");
|
map.put("foo", "bar baz");
|
||||||
map.put("spam", "&bucket=");
|
map.put("spam", "&bucket=");
|
||||||
assertEquals("foo/bar%20baz?spam=%26bucket%3D", context.getContextUrl("{foo}?spam={spam}", map));
|
assertEquals("/foo/bar%20baz?spam=%26bucket%3D", context.getContextUrl("{foo}?spam={spam}", map));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue