From e9bf4e5fb7b87da6cbf287cfd8cf57550c6236c7 Mon Sep 17 00:00:00 2001 From: Johannes Rost Date: Fri, 21 May 2021 23:26:41 +0200 Subject: [PATCH] Do not reuse WebsocketClientSpec.Builder between Requests (#2216) --- .../config/GatewayAutoConfiguration.java | 15 +++++++++------ .../config/GatewayAutoConfigurationTests.java | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java index 66b8c1ec..2ff02781 100644 --- a/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java +++ b/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java @@ -779,12 +779,15 @@ public class GatewayAutoConfiguration { @ConditionalOnEnabledGlobalFilter(WebsocketRoutingFilter.class) public ReactorNettyWebSocketClient reactorNettyWebSocketClient(HttpClientProperties properties, HttpClient httpClient) { - WebsocketClientSpec.Builder builder = WebsocketClientSpec.builder() - .handlePing(properties.getWebsocket().isProxyPing()); - if (properties.getWebsocket().getMaxFramePayloadLength() != null) { - builder.maxFramePayloadLength(properties.getWebsocket().getMaxFramePayloadLength()); - } - return new ReactorNettyWebSocketClient(httpClient, builder); + Supplier builderSupplier = () -> { + WebsocketClientSpec.Builder builder = WebsocketClientSpec.builder() + .handlePing(properties.getWebsocket().isProxyPing()); + if (properties.getWebsocket().getMaxFramePayloadLength() != null) { + builder.maxFramePayloadLength(properties.getWebsocket().getMaxFramePayloadLength()); + } + return builder; + }; + return new ReactorNettyWebSocketClient(httpClient, builderSupplier); } @Bean diff --git a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java index f34b4d83..8bc34a5e 100644 --- a/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java +++ b/spring-cloud-gateway-server/src/test/java/org/springframework/cloud/gateway/config/GatewayAutoConfigurationTests.java @@ -22,6 +22,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import reactor.netty.http.client.HttpClient; +import reactor.netty.http.client.WebsocketClientSpec; import reactor.netty.http.server.WebsocketServerSpec; import org.springframework.boot.SpringApplication; @@ -210,6 +211,24 @@ public class GatewayAutoConfigurationTests { assertThat(spec2.protocols()).isNull(); } + + @Test // gh-2215 + public void webSocketClientSpecBuilderIsUniquePerReactorNettyWebSocketClient() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + ReactorNettyWebSocketClient websocketClient = new GatewayAutoConfiguration.NettyConfiguration() + .reactorNettyWebSocketClient(new HttpClientProperties(), HttpClient.create()); + + // Method "buildSpec" has only private visibility + Method buildSpec = ReactorNettyWebSocketClient.class.getDeclaredMethod("buildSpec", String.class); + buildSpec.setAccessible(true); + WebsocketClientSpec spec1 = (WebsocketClientSpec) buildSpec.invoke(websocketClient, "p1"); + WebsocketClientSpec spec2 = websocketClient.getWebsocketClientSpec(); + + assertThat(spec1.protocols()).isEqualTo("p1"); + // Protocols should not be cached between requests: + assertThat(spec2.protocols()).isNull(); + } + @EnableAutoConfiguration @SpringBootConfiguration protected static class Config {