Skip to content

Commit 994a35d

Browse files
committed
Mutated ServerHttpRequest returns native request correctly
Closes gh-26304
1 parent 8095ba4 commit 994a35d

File tree

8 files changed

+69
-100
lines changed

8 files changed

+69
-100
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -236,7 +236,7 @@ public Flux<DataBuffer> getBody() {
236236
@SuppressWarnings("unchecked")
237237
@Override
238238
public <T> T getNativeRequest() {
239-
return (T) this.originalRequest;
239+
return ServerHttpRequestDecorator.getNativeRequest(this.originalRequest);
240240
}
241241

242242
@Override

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -120,6 +120,28 @@ public Flux<DataBuffer> getBody() {
120120
}
121121

122122

123+
/**
124+
* Return the native request of the underlying server API, if possible,
125+
* also unwrapping {@link ServerHttpRequestDecorator} if necessary.
126+
* @param request the request to check
127+
* @param <T> the expected native request type
128+
* @throws IllegalArgumentException if the native request can't be obtained
129+
* @since 5.3.3
130+
*/
131+
public static <T> T getNativeRequest(ServerHttpRequest request) {
132+
if (request instanceof AbstractServerHttpRequest) {
133+
return ((AbstractServerHttpRequest) request).getNativeRequest();
134+
}
135+
else if (request instanceof ServerHttpRequestDecorator) {
136+
return getNativeRequest(((ServerHttpRequestDecorator) request).getDelegate());
137+
}
138+
else {
139+
throw new IllegalArgumentException(
140+
"Can't find native request in " + request.getClass().getName());
141+
}
142+
}
143+
144+
123145
@Override
124146
public String toString() {
125147
return getClass().getSimpleName() + " [delegate=" + getDelegate() + "]";

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -110,6 +110,28 @@ public Mono<Void> setComplete() {
110110
}
111111

112112

113+
/**
114+
* Return the native response of the underlying server API, if possible,
115+
* also unwrapping {@link ServerHttpResponseDecorator} if necessary.
116+
* @param response the response to check
117+
* @param <T> the expected native response type
118+
* @throws IllegalArgumentException if the native response can't be obtained
119+
* @since 5.3.3
120+
*/
121+
public static <T> T getNativeResponse(ServerHttpResponse response) {
122+
if (response instanceof AbstractServerHttpResponse) {
123+
return ((AbstractServerHttpResponse) response).getNativeResponse();
124+
}
125+
else if (response instanceof ServerHttpResponseDecorator) {
126+
return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate());
127+
}
128+
else {
129+
throw new IllegalArgumentException(
130+
"Can't find native response in " + response.getClass().getName());
131+
}
132+
}
133+
134+
113135
@Override
114136
public String toString() {
115137
return getClass().getSimpleName() + " [delegate=" + getDelegate() + "]";

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424
import javax.servlet.AsyncContext;
2525
import javax.servlet.ReadListener;
2626
import javax.servlet.ServletInputStream;
27+
import javax.servlet.http.HttpServletRequest;
2728

2829
import org.junit.jupiter.api.Test;
2930

@@ -189,6 +190,15 @@ void mutateContextPathWithoutUpdatingPathShouldFail() throws Exception {
189190
.hasMessage("Invalid contextPath '/fail': must match the start of requestPath: '/context/path'");
190191
}
191192

193+
@Test // gh-26304
194+
public void mutateDoesNotPreventAccessToNativeRequest() throws Exception {
195+
ServerHttpRequest request = createRequest("/path");
196+
request = request.mutate().header("key", "value").build();
197+
198+
Object nativeRequest = ServerHttpRequestDecorator.getNativeRequest(request);
199+
assertThat(nativeRequest).isInstanceOf(HttpServletRequest.class);
200+
}
201+
192202
private ServerHttpRequest createRequest(String uriString) throws Exception {
193203
return createRequest(uriString, "");
194204
}

spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,8 +30,6 @@
3030
import org.springframework.context.Lifecycle;
3131
import org.springframework.core.NamedThreadLocal;
3232
import org.springframework.core.io.buffer.DataBufferFactory;
33-
import org.springframework.http.server.reactive.AbstractServerHttpRequest;
34-
import org.springframework.http.server.reactive.AbstractServerHttpResponse;
3533
import org.springframework.http.server.reactive.ServerHttpRequest;
3634
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
3735
import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -148,8 +146,8 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
148146
ServerHttpRequest request = exchange.getRequest();
149147
ServerHttpResponse response = exchange.getResponse();
150148

151-
HttpServletRequest servletRequest = getNativeRequest(request);
152-
HttpServletResponse servletResponse = getNativeResponse(response);
149+
HttpServletRequest servletRequest = ServerHttpRequestDecorator.getNativeRequest(request);
150+
HttpServletResponse servletResponse = ServerHttpResponseDecorator.getNativeResponse(response);
153151

154152
HandshakeInfo handshakeInfo = handshakeInfoFactory.get();
155153
DataBufferFactory factory = response.bufferFactory();
@@ -181,32 +179,6 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
181179
}));
182180
}
183181

184-
private static HttpServletRequest getNativeRequest(ServerHttpRequest request) {
185-
if (request instanceof AbstractServerHttpRequest) {
186-
return ((AbstractServerHttpRequest) request).getNativeRequest();
187-
}
188-
else if (request instanceof ServerHttpRequestDecorator) {
189-
return getNativeRequest(((ServerHttpRequestDecorator) request).getDelegate());
190-
}
191-
else {
192-
throw new IllegalArgumentException(
193-
"Couldn't find HttpServletRequest in " + request.getClass().getName());
194-
}
195-
}
196-
197-
private static HttpServletResponse getNativeResponse(ServerHttpResponse response) {
198-
if (response instanceof AbstractServerHttpResponse) {
199-
return ((AbstractServerHttpResponse) response).getNativeResponse();
200-
}
201-
else if (response instanceof ServerHttpResponseDecorator) {
202-
return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate());
203-
}
204-
else {
205-
throw new IllegalArgumentException(
206-
"Couldn't find HttpServletResponse in " + response.getClass().getName());
207-
}
208-
}
209-
210182
private void startLazily(HttpServletRequest request) {
211183
if (isRunning()) {
212184
return;

spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/ReactorNettyRequestUpgradeStrategy.java

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@
2424
import reactor.netty.http.server.WebsocketServerSpec;
2525

2626
import org.springframework.core.io.buffer.NettyDataBufferFactory;
27-
import org.springframework.http.server.reactive.AbstractServerHttpResponse;
2827
import org.springframework.http.server.reactive.ServerHttpResponse;
2928
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
3029
import org.springframework.lang.Nullable;
@@ -161,7 +160,7 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
161160
@Nullable String subProtocol, Supplier<HandshakeInfo> handshakeInfoFactory) {
162161

163162
ServerHttpResponse response = exchange.getResponse();
164-
HttpServerResponse reactorResponse = getNativeResponse(response);
163+
HttpServerResponse reactorResponse = ServerHttpResponseDecorator.getNativeResponse(response);
165164
HandshakeInfo handshakeInfo = handshakeInfoFactory.get();
166165
NettyDataBufferFactory bufferFactory = (NettyDataBufferFactory) response.bufferFactory();
167166
URI uri = exchange.getRequest().getURI();
@@ -179,17 +178,4 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
179178
}));
180179
}
181180

182-
private static HttpServerResponse getNativeResponse(ServerHttpResponse response) {
183-
if (response instanceof AbstractServerHttpResponse) {
184-
return ((AbstractServerHttpResponse) response).getNativeResponse();
185-
}
186-
else if (response instanceof ServerHttpResponseDecorator) {
187-
return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate());
188-
}
189-
else {
190-
throw new IllegalArgumentException(
191-
"Couldn't find native response in " + response.getClass().getName());
192-
}
193-
}
194-
195181
}

spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/TomcatRequestUpgradeStrategy.java

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,8 +28,6 @@
2828
import reactor.core.publisher.Mono;
2929

3030
import org.springframework.core.io.buffer.DataBufferFactory;
31-
import org.springframework.http.server.reactive.AbstractServerHttpRequest;
32-
import org.springframework.http.server.reactive.AbstractServerHttpResponse;
3331
import org.springframework.http.server.reactive.ServerHttpRequest;
3432
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
3533
import org.springframework.http.server.reactive.ServerHttpResponse;
@@ -132,8 +130,8 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
132130
ServerHttpRequest request = exchange.getRequest();
133131
ServerHttpResponse response = exchange.getResponse();
134132

135-
HttpServletRequest servletRequest = getNativeRequest(request);
136-
HttpServletResponse servletResponse = getNativeResponse(response);
133+
HttpServletRequest servletRequest = ServerHttpRequestDecorator.getNativeRequest(request);
134+
HttpServletResponse servletResponse = ServerHttpResponseDecorator.getNativeResponse(response);
137135

138136
HandshakeInfo handshakeInfo = handshakeInfoFactory.get();
139137
DataBufferFactory bufferFactory = response.bufferFactory();
@@ -161,32 +159,6 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
161159
}));
162160
}
163161

164-
private static HttpServletRequest getNativeRequest(ServerHttpRequest request) {
165-
if (request instanceof AbstractServerHttpRequest) {
166-
return ((AbstractServerHttpRequest) request).getNativeRequest();
167-
}
168-
else if (request instanceof ServerHttpRequestDecorator) {
169-
return getNativeRequest(((ServerHttpRequestDecorator) request).getDelegate());
170-
}
171-
else {
172-
throw new IllegalArgumentException(
173-
"Couldn't find HttpServletRequest in " + request.getClass().getName());
174-
}
175-
}
176-
177-
private static HttpServletResponse getNativeResponse(ServerHttpResponse response) {
178-
if (response instanceof AbstractServerHttpResponse) {
179-
return ((AbstractServerHttpResponse) response).getNativeResponse();
180-
}
181-
else if (response instanceof ServerHttpResponseDecorator) {
182-
return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate());
183-
}
184-
else {
185-
throw new IllegalArgumentException(
186-
"Couldn't find HttpServletResponse in " + response.getClass().getName());
187-
}
188-
}
189-
190162
private WsServerContainer getContainer(HttpServletRequest request) {
191163
if (this.serverContainer == null) {
192164
Object container = request.getServletContext().getAttribute(SERVER_CONTAINER_ATTR);

spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/UndertowRequestUpgradeStrategy.java

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,8 +31,6 @@
3131
import reactor.core.publisher.Mono;
3232

3333
import org.springframework.core.io.buffer.DataBufferFactory;
34-
import org.springframework.http.server.reactive.AbstractServerHttpRequest;
35-
import org.springframework.http.server.reactive.ServerHttpRequest;
3634
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
3735
import org.springframework.lang.Nullable;
3836
import org.springframework.web.reactive.socket.HandshakeInfo;
@@ -57,7 +55,7 @@ public class UndertowRequestUpgradeStrategy implements RequestUpgradeStrategy {
5755
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
5856
@Nullable String subProtocol, Supplier<HandshakeInfo> handshakeInfoFactory) {
5957

60-
HttpServerExchange httpExchange = getNativeRequest(exchange.getRequest());
58+
HttpServerExchange httpExchange = ServerHttpRequestDecorator.getNativeRequest(exchange.getRequest());
6159

6260
Set<String> protocols = (subProtocol != null ? Collections.singleton(subProtocol) : Collections.emptySet());
6361
Hybi13Handshake handshake = new Hybi13Handshake(protocols, false);
@@ -83,19 +81,6 @@ public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler,
8381
}));
8482
}
8583

86-
private static HttpServerExchange getNativeRequest(ServerHttpRequest request) {
87-
if (request instanceof AbstractServerHttpRequest) {
88-
return ((AbstractServerHttpRequest) request).getNativeRequest();
89-
}
90-
else if (request instanceof ServerHttpRequestDecorator) {
91-
return getNativeRequest(((ServerHttpRequestDecorator) request).getDelegate());
92-
}
93-
else {
94-
throw new IllegalArgumentException(
95-
"Couldn't find HttpServerExchange in " + request.getClass().getName());
96-
}
97-
}
98-
9984

10085
private class DefaultCallback implements WebSocketConnectionCallback {
10186

0 commit comments

Comments
 (0)