Skip to content

Commit 11075f1

Browse files
committed
Fix URI parsing in Reactor Netty request
Issue: SPR-15560
1 parent c59e192 commit 11075f1

File tree

5 files changed

+71
-48
lines changed

5 files changed

+71
-48
lines changed

spring-web/src/main/java/org/springframework/http/server/reactive/ReactorHttpHandlerAdapter.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.http.server.reactive;
1818

19+
import java.net.URISyntaxException;
1920
import java.util.function.BiFunction;
2021

2122
import io.netty.handler.codec.http.HttpResponseStatus;
@@ -53,10 +54,19 @@ public ReactorHttpHandlerAdapter(HttpHandler httpHandler) {
5354
public Mono<Void> apply(HttpServerRequest request, HttpServerResponse response) {
5455

5556
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(response.alloc());
56-
ReactorServerHttpRequest req = new ReactorServerHttpRequest(request, bufferFactory);
57-
ReactorServerHttpResponse resp = new ReactorServerHttpResponse(response, bufferFactory);
57+
ReactorServerHttpRequest adaptedRequest;
58+
ReactorServerHttpResponse adaptedResponse;
59+
try {
60+
adaptedRequest = new ReactorServerHttpRequest(request, bufferFactory);
61+
adaptedResponse = new ReactorServerHttpResponse(response, bufferFactory);
62+
}
63+
catch (URISyntaxException ex) {
64+
logger.error("Invalid URL " + ex.getMessage(), ex);
65+
response.status(HttpResponseStatus.BAD_REQUEST);
66+
return Mono.empty();
67+
}
5868

59-
return this.httpHandler.handle(req, resp)
69+
return this.httpHandler.handle(adaptedRequest, adaptedResponse)
6070
.onErrorResume(ex -> {
6171
logger.error("Could not complete request", ex);
6272
response.status(HttpResponseStatus.INTERNAL_SERVER_ERROR);

spring-web/src/main/java/org/springframework/http/server/reactive/ReactorServerHttpRequest.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,28 +48,25 @@ public class ReactorServerHttpRequest extends AbstractServerHttpRequest {
4848
private final NettyDataBufferFactory bufferFactory;
4949

5050

51-
public ReactorServerHttpRequest(HttpServerRequest request, NettyDataBufferFactory bufferFactory) {
51+
public ReactorServerHttpRequest(HttpServerRequest request, NettyDataBufferFactory bufferFactory)
52+
throws URISyntaxException {
53+
5254
super(initUri(request), initHeaders(request));
5355
Assert.notNull(bufferFactory, "'bufferFactory' must not be null");
5456
this.request = request;
5557
this.bufferFactory = bufferFactory;
5658
}
5759

58-
private static URI initUri(HttpServerRequest channel) {
60+
private static URI initUri(HttpServerRequest channel) throws URISyntaxException {
5961
Assert.notNull(channel, "'channel' must not be null");
6062
InetSocketAddress address = channel.remoteAddress();
6163
String requestUri = channel.uri();
62-
return (address != null ? getBaseUrl(address).resolve(requestUri) : URI.create(requestUri));
64+
return (address != null ? createUrl(address, requestUri) : new URI(requestUri));
6365
}
6466

65-
private static URI getBaseUrl(InetSocketAddress address) {
66-
try {
67-
return new URI(null, null, address.getHostString(), address.getPort(), null, null, null);
68-
}
69-
catch (URISyntaxException ex) {
70-
// Should not happen...
71-
throw new IllegalStateException(ex);
72-
}
67+
private static URI createUrl(InetSocketAddress address, String requestUri) throws URISyntaxException {
68+
URI baseUrl = new URI(null, null, address.getHostString(), address.getPort(), null, null, null);
69+
return new URI(baseUrl.toString() + requestUri);
7370
}
7471

7572
private static HttpHeaders initHeaders(HttpServerRequest channel) {

spring-web/src/test/java/org/springframework/http/server/reactive/ErrorHandlerIntegrationTests.java

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.http.server.reactive;
1818

19-
import java.io.IOException;
2019
import java.net.URI;
2120

2221
import org.junit.Test;
@@ -45,45 +44,55 @@ protected HttpHandler createHttpHandler() {
4544
}
4645

4746
@Test
48-
public void response() throws Exception {
47+
public void responseBodyError() throws Exception {
4948
// TODO: fix Reactor
5049
assumeFalse(server instanceof ReactorHttpServer);
5150

5251
RestTemplate restTemplate = new RestTemplate();
5352
restTemplate.setErrorHandler(NO_OP_ERROR_HANDLER);
5453

55-
ResponseEntity<String> response = restTemplate
56-
.getForEntity(new URI("http://localhost:" + port + "/response"),
57-
String.class);
54+
URI url = new URI("http://localhost:" + port + "/response-body-error");
55+
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
5856

5957
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
6058
}
6159

6260
@Test
63-
public void returnValue() throws Exception {
61+
public void handlingError() throws Exception {
6462
// TODO: fix Reactor
6563
assumeFalse(server instanceof ReactorHttpServer);
6664

6765
RestTemplate restTemplate = new RestTemplate();
6866
restTemplate.setErrorHandler(NO_OP_ERROR_HANDLER);
6967

70-
ResponseEntity<String> response = restTemplate
71-
.getForEntity(new URI("http://localhost:" + port + "/returnValue"),
72-
String.class);
68+
URI url = new URI("http://localhost:" + port + "/handling-error");
69+
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
7370

7471
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, response.getStatusCode());
7572
}
7673

74+
@Test // SPR-15560
75+
public void emptyPathSegments() throws Exception {
76+
77+
RestTemplate restTemplate = new RestTemplate();
78+
restTemplate.setErrorHandler(NO_OP_ERROR_HANDLER);
79+
80+
URI url = new URI("http://localhost:" + port + "//");
81+
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
82+
83+
assertEquals(HttpStatus.OK, response.getStatusCode());
84+
}
85+
7786
private static class ErrorHandler implements HttpHandler {
7887

7988
@Override
8089
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
8190
Exception error = new UnsupportedOperationException();
8291
String path = request.getURI().getPath();
83-
if (path.endsWith("response")) {
92+
if (path.endsWith("response-body-error")) {
8493
return response.writeWith(Mono.error(error));
8594
}
86-
else if (path.endsWith("returnValue")) {
95+
else if (path.endsWith("handling-error")) {
8796
return Mono.error(error);
8897
}
8998
else {
@@ -92,17 +101,16 @@ else if (path.endsWith("returnValue")) {
92101
}
93102
}
94103

95-
private static final ResponseErrorHandler NO_OP_ERROR_HANDLER =
96-
new ResponseErrorHandler() {
104+
private static final ResponseErrorHandler NO_OP_ERROR_HANDLER = new ResponseErrorHandler() {
97105

98-
@Override
99-
public boolean hasError(ClientHttpResponse response) throws IOException {
100-
return false;
101-
}
106+
@Override
107+
public boolean hasError(ClientHttpResponse response) {
108+
return false;
109+
}
102110

103-
@Override
104-
public void handleError(ClientHttpResponse response) throws IOException {
105-
}
106-
};
111+
@Override
112+
public void handleError(ClientHttpResponse response) {
113+
}
114+
};
107115

108116
}

spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyHttpHandlerAdapter.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.http.server.reactive;
1818

1919
import java.net.InetSocketAddress;
20+
import java.net.URISyntaxException;
2021

2122
import org.apache.commons.logging.Log;
2223
import org.apache.commons.logging.LogFactory;
@@ -63,8 +64,17 @@ public Observable<Void> handle(HttpServerRequest<ByteBuf> nativeRequest,
6364
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(channel.alloc());
6465
InetSocketAddress remoteAddress = (InetSocketAddress) channel.remoteAddress();
6566

66-
RxNettyServerHttpRequest request = new RxNettyServerHttpRequest(nativeRequest, bufferFactory, remoteAddress);
67-
RxNettyServerHttpResponse response = new RxNettyServerHttpResponse(nativeResponse, bufferFactory);
67+
RxNettyServerHttpRequest request;
68+
RxNettyServerHttpResponse response;
69+
try {
70+
request = new RxNettyServerHttpRequest(nativeRequest, bufferFactory, remoteAddress);
71+
response = new RxNettyServerHttpResponse(nativeResponse, bufferFactory);
72+
}
73+
catch (URISyntaxException ex) {
74+
logger.error("Could not complete request", ex);
75+
nativeResponse.setStatus(HttpResponseStatus.BAD_REQUEST);
76+
return Observable.empty();
77+
}
6878

6979
Publisher<Void> result = this.httpHandler.handle(request, response)
7080
.onErrorResume(ex -> {

spring-web/src/test/java/org/springframework/http/server/reactive/RxNettyServerHttpRequest.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public class RxNettyServerHttpRequest extends AbstractServerHttpRequest {
5555

5656

5757
public RxNettyServerHttpRequest(HttpServerRequest<ByteBuf> request,
58-
NettyDataBufferFactory dataBufferFactory, InetSocketAddress remoteAddress) {
58+
NettyDataBufferFactory dataBufferFactory, InetSocketAddress remoteAddress)
59+
throws URISyntaxException {
5960

6061
super(initUri(request, remoteAddress), initHeaders(request));
6162

@@ -65,20 +66,17 @@ public RxNettyServerHttpRequest(HttpServerRequest<ByteBuf> request,
6566
this.remoteAddress = remoteAddress;
6667
}
6768

68-
private static URI initUri(HttpServerRequest<ByteBuf> request, InetSocketAddress remoteAddress) {
69+
private static URI initUri(HttpServerRequest<ByteBuf> request, InetSocketAddress remoteAddress)
70+
throws URISyntaxException {
71+
6972
Assert.notNull(request, "'request' must not be null");
7073
String requestUri = request.getUri();
71-
return remoteAddress != null ? getBaseUrl(remoteAddress).resolve(requestUri) : URI.create(requestUri);
74+
return remoteAddress != null ? createUrl(remoteAddress, requestUri) : URI.create(requestUri);
7275
}
7376

74-
private static URI getBaseUrl(InetSocketAddress address) {
75-
try {
76-
return new URI(null, null, address.getHostString(), address.getPort(), null, null, null);
77-
}
78-
catch (URISyntaxException ex) {
79-
// Should not happen...
80-
throw new IllegalStateException(ex);
81-
}
77+
private static URI createUrl(InetSocketAddress address, String requestUri) throws URISyntaxException {
78+
URI baseUrl = new URI(null, null, address.getHostString(), address.getPort(), null, null, null);
79+
return new URI(baseUrl.toString() + requestUri);
8280
}
8381

8482
private static HttpHeaders initHeaders(HttpServerRequest<ByteBuf> request) {

0 commit comments

Comments
 (0)