diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorHttpHandlerAdapter.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorHttpHandlerAdapter.java index 043c7ef18b..ca8c516411 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorHttpHandlerAdapter.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorHttpHandlerAdapter.java @@ -16,6 +16,7 @@ package org.springframework.http.server.reactive; +import java.net.URISyntaxException; import java.util.function.BiFunction; import io.netty.handler.codec.http.HttpResponseStatus; @@ -53,10 +54,19 @@ public class ReactorHttpHandlerAdapter public Mono apply(HttpServerRequest request, HttpServerResponse response) { NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(response.alloc()); - ReactorServerHttpRequest req = new ReactorServerHttpRequest(request, bufferFactory); - ReactorServerHttpResponse resp = new ReactorServerHttpResponse(response, bufferFactory); + ReactorServerHttpRequest adaptedRequest; + ReactorServerHttpResponse adaptedResponse; + try { + adaptedRequest = new ReactorServerHttpRequest(request, bufferFactory); + adaptedResponse = new ReactorServerHttpResponse(response, bufferFactory); + } + catch (URISyntaxException ex) { + logger.error("Invalid URL " + ex.getMessage(), ex); + response.status(HttpResponseStatus.BAD_REQUEST); + return Mono.empty(); + } - return this.httpHandler.handle(req, resp) + return this.httpHandler.handle(adaptedRequest, adaptedResponse) .onErrorResume(ex -> { logger.error("Could not complete request", ex); response.status(HttpResponseStatus.INTERNAL_SERVER_ERROR); diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java index 174c0112ca..3692b9de38 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java @@ -48,28 +48,25 @@ public class ReactorServerHttpRequest extends AbstractServerHttpRequest { private final NettyDataBufferFactory bufferFactory; - public ReactorServerHttpRequest(HttpServerRequest request, NettyDataBufferFactory bufferFactory) { + public ReactorServerHttpRequest(HttpServerRequest request, NettyDataBufferFactory bufferFactory) + throws URISyntaxException { + super(initUri(request), initHeaders(request)); Assert.notNull(bufferFactory, "'bufferFactory' must not be null"); this.request = request; this.bufferFactory = bufferFactory; } - private static URI initUri(HttpServerRequest channel) { + private static URI initUri(HttpServerRequest channel) throws URISyntaxException { Assert.notNull(channel, "'channel' must not be null"); InetSocketAddress address = channel.remoteAddress(); String requestUri = channel.uri(); - return (address != null ? getBaseUrl(address).resolve(requestUri) : URI.create(requestUri)); + return (address != null ? createUrl(address, requestUri) : new URI(requestUri)); } - private static URI getBaseUrl(InetSocketAddress address) { - try { - return new URI(null, null, address.getHostString(), address.getPort(), null, null, null); - } - catch (URISyntaxException ex) { - // Should not happen... - throw new IllegalStateException(ex); - } + private static URI createUrl(InetSocketAddress address, String requestUri) throws URISyntaxException { + URI baseUrl = new URI(null, null, address.getHostString(), address.getPort(), null, null, null); + return new URI(baseUrl.toString() + requestUri); } private static HttpHeaders initHeaders(HttpServerRequest channel) { diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/ErrorHandlerIntegrationTests.java b/spring-web/src/test/java/org/springframework/http/server/reactive/ErrorHandlerIntegrationTests.java index 8f8b1d6320..94ecdfeca1 100644 --- a/spring-web/src/test/java/org/springframework/http/server/reactive/ErrorHandlerIntegrationTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/reactive/ErrorHandlerIntegrationTests.java @@ -16,7 +16,6 @@ package org.springframework.http.server.reactive; -import java.io.IOException; import java.net.URI; import org.junit.Test; @@ -45,45 +44,55 @@ public class ErrorHandlerIntegrationTests extends AbstractHttpHandlerIntegration } @Test - public void response() throws Exception { + public void responseBodyError() throws Exception { // TODO: fix Reactor assumeFalse(server instanceof ReactorHttpServer); RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(NO_OP_ERROR_HANDLER); - ResponseEntity response = restTemplate - .getForEntity(new URI("http://localhost:" + port + "/response"), - String.class); + URI url = new URI("http://localhost:" + port + "/response-body-error"); + ResponseEntity response = restTemplate.getForEntity(url, String.class); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); } @Test - public void returnValue() throws Exception { + public void handlingError() throws Exception { // TODO: fix Reactor assumeFalse(server instanceof ReactorHttpServer); RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(NO_OP_ERROR_HANDLER); - ResponseEntity response = restTemplate - .getForEntity(new URI("http://localhost:" + port + "/returnValue"), - String.class); + URI url = new URI("http://localhost:" + port + "/handling-error"); + ResponseEntity response = restTemplate.getForEntity(url, String.class); assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode()); } + @Test // SPR-15560 + public void emptyPathSegments() throws Exception { + + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(NO_OP_ERROR_HANDLER); + + URI url = new URI("http://localhost:" + port + "//"); + ResponseEntity response = restTemplate.getForEntity(url, String.class); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + } + private static class ErrorHandler implements HttpHandler { @Override public Mono handle(ServerHttpRequest request, ServerHttpResponse response) { Exception error = new UnsupportedOperationException(); String path = request.getURI().getPath(); - if (path.endsWith("response")) { + if (path.endsWith("response-body-error")) { return response.writeWith(Mono.error(error)); } - else if (path.endsWith("returnValue")) { + else if (path.endsWith("handling-error")) { return Mono.error(error); } else { @@ -92,17 +101,16 @@ public class ErrorHandlerIntegrationTests extends AbstractHttpHandlerIntegration } } - private static final ResponseErrorHandler NO_OP_ERROR_HANDLER = - new ResponseErrorHandler() { + private static final ResponseErrorHandler NO_OP_ERROR_HANDLER = new ResponseErrorHandler() { - @Override - public boolean hasError(ClientHttpResponse response) throws IOException { - return false; - } + @Override + public boolean hasError(ClientHttpResponse response) { + return false; + } - @Override - public void handleError(ClientHttpResponse response) throws IOException { - } - }; + @Override + public void handleError(ClientHttpResponse response) { + } + }; } diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyHttpHandlerAdapter.java b/spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyHttpHandlerAdapter.java index ac9eb4ffa9..a755ab41c8 100644 --- a/spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyHttpHandlerAdapter.java +++ b/spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyHttpHandlerAdapter.java @@ -17,6 +17,7 @@ package org.springframework.http.server.reactive; import java.net.InetSocketAddress; +import java.net.URISyntaxException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -63,8 +64,17 @@ public class RxNettyHttpHandlerAdapter implements RequestHandler result = this.httpHandler.handle(request, response) .onErrorResume(ex -> { diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyServerHttpRequest.java b/spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyServerHttpRequest.java index 503c2653ad..05918cdae7 100644 --- a/spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyServerHttpRequest.java +++ b/spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyServerHttpRequest.java @@ -55,7 +55,8 @@ public class RxNettyServerHttpRequest extends AbstractServerHttpRequest { public RxNettyServerHttpRequest(HttpServerRequest request, - NettyDataBufferFactory dataBufferFactory, InetSocketAddress remoteAddress) { + NettyDataBufferFactory dataBufferFactory, InetSocketAddress remoteAddress) + throws URISyntaxException { super(initUri(request, remoteAddress), initHeaders(request)); @@ -65,20 +66,17 @@ public class RxNettyServerHttpRequest extends AbstractServerHttpRequest { this.remoteAddress = remoteAddress; } - private static URI initUri(HttpServerRequest request, InetSocketAddress remoteAddress) { + private static URI initUri(HttpServerRequest request, InetSocketAddress remoteAddress) + throws URISyntaxException { + Assert.notNull(request, "'request' must not be null"); String requestUri = request.getUri(); - return remoteAddress != null ? getBaseUrl(remoteAddress).resolve(requestUri) : URI.create(requestUri); + return remoteAddress != null ? createUrl(remoteAddress, requestUri) : URI.create(requestUri); } - private static URI getBaseUrl(InetSocketAddress address) { - try { - return new URI(null, null, address.getHostString(), address.getPort(), null, null, null); - } - catch (URISyntaxException ex) { - // Should not happen... - throw new IllegalStateException(ex); - } + private static URI createUrl(InetSocketAddress address, String requestUri) throws URISyntaxException { + URI baseUrl = new URI(null, null, address.getHostString(), address.getPort(), null, null, null); + return new URI(baseUrl.toString() + requestUri); } private static HttpHeaders initHeaders(HttpServerRequest request) {