From b1f1e75c00d1b8aeab521cf0169e89599e8074a6 Mon Sep 17 00:00:00 2001 From: johannesrost Date: Thu, 25 Feb 2021 18:27:47 +0100 Subject: [PATCH] Do not reuse WebsocketServerSpec.Builder between requests Fixes gh-2159 Fixes gh-2160 --- .../config/GatewayAutoConfiguration.java | 22 ++++++++++--------- .../config/GatewayAutoConfigurationTests.java | 19 ++++++++++++++++ 2 files changed, 31 insertions(+), 10 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 47a7cf381f..335d140348 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 @@ -19,6 +19,7 @@ import java.security.cert.X509Certificate; import java.util.List; import java.util.Set; +import java.util.function.Supplier; import com.netflix.hystrix.HystrixObservableCommand; import io.netty.channel.ChannelOption; @@ -28,6 +29,7 @@ import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Flux; import reactor.netty.http.client.HttpClient; +import reactor.netty.http.server.WebsocketServerSpec; import reactor.netty.resources.ConnectionProvider; import reactor.netty.tcp.ProxyProvider; import rx.RxReactiveStreams; @@ -812,17 +814,17 @@ public ReactorNettyWebSocketClient reactorNettyWebSocketClient( @Bean public ReactorNettyRequestUpgradeStrategy reactorNettyRequestUpgradeStrategy( HttpClientProperties httpClientProperties) { - ReactorNettyRequestUpgradeStrategy requestUpgradeStrategy = new ReactorNettyRequestUpgradeStrategy(); - - HttpClientProperties.Websocket websocket = httpClientProperties - .getWebsocket(); - PropertyMapper map = PropertyMapper.get(); - map.from(websocket::getMaxFramePayloadLength).whenNonNull() - .to(requestUpgradeStrategy::setMaxFramePayloadLength); - map.from(websocket::isProxyPing).to(requestUpgradeStrategy::setHandlePing); - return requestUpgradeStrategy; - } + Supplier builderSupplier = () -> { + WebsocketServerSpec.Builder builder = WebsocketServerSpec.builder(); + HttpClientProperties.Websocket websocket = httpClientProperties.getWebsocket(); + PropertyMapper map = PropertyMapper.get(); + map.from(websocket::getMaxFramePayloadLength).whenNonNull().to(builder::maxFramePayloadLength); + map.from(websocket::isProxyPing).to(builder::handlePing); + return builder; + }; + + return new ReactorNettyRequestUpgradeStrategy(builderSupplier); } @Configuration(proxyBeanMethods = false) 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 1df5fa0971..54f509fbc4 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 @@ -16,10 +16,13 @@ package org.springframework.cloud.gateway.config; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import reactor.netty.http.client.HttpClient; +import reactor.netty.http.server.WebsocketServerSpec; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringBootConfiguration; @@ -160,6 +163,22 @@ public void verboseActuatorDisabled() { } } + @Test // gh-2159 + public void reactorNettyRequestUpgradeStrategyWebSocketSpecBuilderIsUniquePerRequest() + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + ReactorNettyRequestUpgradeStrategy strategy = new GatewayAutoConfiguration.NettyConfiguration() + .reactorNettyRequestUpgradeStrategy(new HttpClientProperties()); + + // Method "buildSpec" was introduced for Tests, but has only default visiblity + Method buildSpec = ReactorNettyRequestUpgradeStrategy.class.getDeclaredMethod("buildSpec", String.class); + buildSpec.setAccessible(true); + WebsocketServerSpec spec1 = (WebsocketServerSpec) buildSpec.invoke(strategy, "p1"); + WebsocketServerSpec spec2 = strategy.getWebsocketServerSpec(); + + assertThat(spec1.protocols()).isEqualTo("p1"); + assertThat(spec2.protocols()).isNull(); + } + @EnableAutoConfiguration @SpringBootConfiguration protected static class Config {