From 994a35d6916791f9dfe98f35536dfbf089bc9950 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 4 Jan 2021 21:35:51 +0000 Subject: [PATCH] Mutated ServerHttpRequest returns native request correctly Closes gh-26304 --- .../DefaultServerHttpRequestBuilder.java | 4 +-- .../reactive/ServerHttpRequestDecorator.java | 24 ++++++++++++- .../reactive/ServerHttpResponseDecorator.java | 24 ++++++++++++- .../reactive/ServerHttpRequestTests.java | 12 ++++++- .../upgrade/JettyRequestUpgradeStrategy.java | 34 ++----------------- .../ReactorNettyRequestUpgradeStrategy.java | 18 ++-------- .../upgrade/TomcatRequestUpgradeStrategy.java | 34 ++----------------- .../UndertowRequestUpgradeStrategy.java | 19 ++--------- 8 files changed, 69 insertions(+), 100 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultServerHttpRequestBuilder.java b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultServerHttpRequestBuilder.java index 297c475ac3..847669e0eb 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultServerHttpRequestBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/DefaultServerHttpRequestBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -236,7 +236,7 @@ class DefaultServerHttpRequestBuilder implements ServerHttpRequest.Builder { @SuppressWarnings("unchecked") @Override public T getNativeRequest() { - return (T) this.originalRequest; + return ServerHttpRequestDecorator.getNativeRequest(this.originalRequest); } @Override diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpRequestDecorator.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpRequestDecorator.java index b75e3f12fb..df1086d21c 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpRequestDecorator.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpRequestDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -120,6 +120,28 @@ public class ServerHttpRequestDecorator implements ServerHttpRequest { } + /** + * Return the native request of the underlying server API, if possible, + * also unwrapping {@link ServerHttpRequestDecorator} if necessary. + * @param request the request to check + * @param the expected native request type + * @throws IllegalArgumentException if the native request can't be obtained + * @since 5.3.3 + */ + public static T getNativeRequest(ServerHttpRequest request) { + if (request instanceof AbstractServerHttpRequest) { + return ((AbstractServerHttpRequest) request).getNativeRequest(); + } + else if (request instanceof ServerHttpRequestDecorator) { + return getNativeRequest(((ServerHttpRequestDecorator) request).getDelegate()); + } + else { + throw new IllegalArgumentException( + "Can't find native request in " + request.getClass().getName()); + } + } + + @Override public String toString() { return getClass().getSimpleName() + " [delegate=" + getDelegate() + "]"; diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java b/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java index 274cea9676..125a7bb7d6 100644 --- a/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java +++ b/spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2021 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. @@ -110,6 +110,28 @@ public class ServerHttpResponseDecorator implements ServerHttpResponse { } + /** + * Return the native response of the underlying server API, if possible, + * also unwrapping {@link ServerHttpResponseDecorator} if necessary. + * @param response the response to check + * @param the expected native response type + * @throws IllegalArgumentException if the native response can't be obtained + * @since 5.3.3 + */ + public static T getNativeResponse(ServerHttpResponse response) { + if (response instanceof AbstractServerHttpResponse) { + return ((AbstractServerHttpResponse) response).getNativeResponse(); + } + else if (response instanceof ServerHttpResponseDecorator) { + return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate()); + } + else { + throw new IllegalArgumentException( + "Can't find native response in " + response.getClass().getName()); + } + } + + @Override public String toString() { return getClass().getSimpleName() + " [delegate=" + getDelegate() + "]"; diff --git a/spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpRequestTests.java b/spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpRequestTests.java index 39addff0aa..d9ca717ca6 100644 --- a/spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpRequestTests.java +++ b/spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpRequestTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -24,6 +24,7 @@ import java.util.Collections; import javax.servlet.AsyncContext; import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; import org.junit.jupiter.api.Test; @@ -189,6 +190,15 @@ public class ServerHttpRequestTests { .hasMessage("Invalid contextPath '/fail': must match the start of requestPath: '/context/path'"); } + @Test // gh-26304 + public void mutateDoesNotPreventAccessToNativeRequest() throws Exception { + ServerHttpRequest request = createRequest("/path"); + request = request.mutate().header("key", "value").build(); + + Object nativeRequest = ServerHttpRequestDecorator.getNativeRequest(request); + assertThat(nativeRequest).isInstanceOf(HttpServletRequest.class); + } + private ServerHttpRequest createRequest(String uriString) throws Exception { return createRequest(uriString, ""); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java index 7d5b008100..cad57bd591 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -30,8 +30,6 @@ import reactor.core.publisher.Mono; import org.springframework.context.Lifecycle; import org.springframework.core.NamedThreadLocal; import org.springframework.core.io.buffer.DataBufferFactory; -import org.springframework.http.server.reactive.AbstractServerHttpRequest; -import org.springframework.http.server.reactive.AbstractServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.http.server.reactive.ServerHttpResponse; @@ -148,8 +146,8 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); - HttpServletRequest servletRequest = getNativeRequest(request); - HttpServletResponse servletResponse = getNativeResponse(response); + HttpServletRequest servletRequest = ServerHttpRequestDecorator.getNativeRequest(request); + HttpServletResponse servletResponse = ServerHttpResponseDecorator.getNativeResponse(response); HandshakeInfo handshakeInfo = handshakeInfoFactory.get(); DataBufferFactory factory = response.bufferFactory(); @@ -181,32 +179,6 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life })); } - private static HttpServletRequest getNativeRequest(ServerHttpRequest request) { - if (request instanceof AbstractServerHttpRequest) { - return ((AbstractServerHttpRequest) request).getNativeRequest(); - } - else if (request instanceof ServerHttpRequestDecorator) { - return getNativeRequest(((ServerHttpRequestDecorator) request).getDelegate()); - } - else { - throw new IllegalArgumentException( - "Couldn't find HttpServletRequest in " + request.getClass().getName()); - } - } - - private static HttpServletResponse getNativeResponse(ServerHttpResponse response) { - if (response instanceof AbstractServerHttpResponse) { - return ((AbstractServerHttpResponse) response).getNativeResponse(); - } - else if (response instanceof ServerHttpResponseDecorator) { - return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate()); - } - else { - throw new IllegalArgumentException( - "Couldn't find HttpServletResponse in " + response.getClass().getName()); - } - } - private void startLazily(HttpServletRequest request) { if (isRunning()) { return; diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/ReactorNettyRequestUpgradeStrategy.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/ReactorNettyRequestUpgradeStrategy.java index c3dda93389..d8f98768a6 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/ReactorNettyRequestUpgradeStrategy.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/ReactorNettyRequestUpgradeStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -24,7 +24,6 @@ import reactor.netty.http.server.HttpServerResponse; import reactor.netty.http.server.WebsocketServerSpec; import org.springframework.core.io.buffer.NettyDataBufferFactory; -import org.springframework.http.server.reactive.AbstractServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; import org.springframework.lang.Nullable; @@ -161,7 +160,7 @@ public class ReactorNettyRequestUpgradeStrategy implements RequestUpgradeStrateg @Nullable String subProtocol, Supplier handshakeInfoFactory) { ServerHttpResponse response = exchange.getResponse(); - HttpServerResponse reactorResponse = getNativeResponse(response); + HttpServerResponse reactorResponse = ServerHttpResponseDecorator.getNativeResponse(response); HandshakeInfo handshakeInfo = handshakeInfoFactory.get(); NettyDataBufferFactory bufferFactory = (NettyDataBufferFactory) response.bufferFactory(); URI uri = exchange.getRequest().getURI(); @@ -179,17 +178,4 @@ public class ReactorNettyRequestUpgradeStrategy implements RequestUpgradeStrateg })); } - private static HttpServerResponse getNativeResponse(ServerHttpResponse response) { - if (response instanceof AbstractServerHttpResponse) { - return ((AbstractServerHttpResponse) response).getNativeResponse(); - } - else if (response instanceof ServerHttpResponseDecorator) { - return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate()); - } - else { - throw new IllegalArgumentException( - "Couldn't find native response in " + response.getClass().getName()); - } - } - } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/TomcatRequestUpgradeStrategy.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/TomcatRequestUpgradeStrategy.java index a9d84b1644..f918410dd5 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/TomcatRequestUpgradeStrategy.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/TomcatRequestUpgradeStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -28,8 +28,6 @@ import org.apache.tomcat.websocket.server.WsServerContainer; import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBufferFactory; -import org.springframework.http.server.reactive.AbstractServerHttpRequest; -import org.springframework.http.server.reactive.AbstractServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.http.server.reactive.ServerHttpResponse; @@ -132,8 +130,8 @@ public class TomcatRequestUpgradeStrategy implements RequestUpgradeStrategy { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); - HttpServletRequest servletRequest = getNativeRequest(request); - HttpServletResponse servletResponse = getNativeResponse(response); + HttpServletRequest servletRequest = ServerHttpRequestDecorator.getNativeRequest(request); + HttpServletResponse servletResponse = ServerHttpResponseDecorator.getNativeResponse(response); HandshakeInfo handshakeInfo = handshakeInfoFactory.get(); DataBufferFactory bufferFactory = response.bufferFactory(); @@ -161,32 +159,6 @@ public class TomcatRequestUpgradeStrategy implements RequestUpgradeStrategy { })); } - private static HttpServletRequest getNativeRequest(ServerHttpRequest request) { - if (request instanceof AbstractServerHttpRequest) { - return ((AbstractServerHttpRequest) request).getNativeRequest(); - } - else if (request instanceof ServerHttpRequestDecorator) { - return getNativeRequest(((ServerHttpRequestDecorator) request).getDelegate()); - } - else { - throw new IllegalArgumentException( - "Couldn't find HttpServletRequest in " + request.getClass().getName()); - } - } - - private static HttpServletResponse getNativeResponse(ServerHttpResponse response) { - if (response instanceof AbstractServerHttpResponse) { - return ((AbstractServerHttpResponse) response).getNativeResponse(); - } - else if (response instanceof ServerHttpResponseDecorator) { - return getNativeResponse(((ServerHttpResponseDecorator) response).getDelegate()); - } - else { - throw new IllegalArgumentException( - "Couldn't find HttpServletResponse in " + response.getClass().getName()); - } - } - private WsServerContainer getContainer(HttpServletRequest request) { if (this.serverContainer == null) { Object container = request.getServletContext().getAttribute(SERVER_CONTAINER_ATTR); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/UndertowRequestUpgradeStrategy.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/UndertowRequestUpgradeStrategy.java index fa60bcdb71..973bbf4fb2 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/UndertowRequestUpgradeStrategy.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/UndertowRequestUpgradeStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -31,8 +31,6 @@ import io.undertow.websockets.spi.WebSocketHttpExchange; import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBufferFactory; -import org.springframework.http.server.reactive.AbstractServerHttpRequest; -import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.lang.Nullable; import org.springframework.web.reactive.socket.HandshakeInfo; @@ -57,7 +55,7 @@ public class UndertowRequestUpgradeStrategy implements RequestUpgradeStrategy { public Mono upgrade(ServerWebExchange exchange, WebSocketHandler handler, @Nullable String subProtocol, Supplier handshakeInfoFactory) { - HttpServerExchange httpExchange = getNativeRequest(exchange.getRequest()); + HttpServerExchange httpExchange = ServerHttpRequestDecorator.getNativeRequest(exchange.getRequest()); Set protocols = (subProtocol != null ? Collections.singleton(subProtocol) : Collections.emptySet()); Hybi13Handshake handshake = new Hybi13Handshake(protocols, false); @@ -83,19 +81,6 @@ public class UndertowRequestUpgradeStrategy implements RequestUpgradeStrategy { })); } - private static HttpServerExchange getNativeRequest(ServerHttpRequest request) { - if (request instanceof AbstractServerHttpRequest) { - return ((AbstractServerHttpRequest) request).getNativeRequest(); - } - else if (request instanceof ServerHttpRequestDecorator) { - return getNativeRequest(((ServerHttpRequestDecorator) request).getDelegate()); - } - else { - throw new IllegalArgumentException( - "Couldn't find HttpServerExchange in " + request.getClass().getName()); - } - } - private class DefaultCallback implements WebSocketConnectionCallback {