|
|
|
|
@@ -17,15 +17,18 @@
|
|
|
|
|
package org.springframework.web.reactive.socket.client;
|
|
|
|
|
|
|
|
|
|
import java.net.URI;
|
|
|
|
|
import java.util.function.Supplier;
|
|
|
|
|
|
|
|
|
|
import org.apache.commons.logging.Log;
|
|
|
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
|
import reactor.core.publisher.Mono;
|
|
|
|
|
import reactor.netty.http.client.HttpClient;
|
|
|
|
|
import reactor.netty.http.client.WebsocketClientSpec;
|
|
|
|
|
import reactor.netty.http.websocket.WebsocketInbound;
|
|
|
|
|
|
|
|
|
|
import org.springframework.core.io.buffer.NettyDataBufferFactory;
|
|
|
|
|
import org.springframework.http.HttpHeaders;
|
|
|
|
|
import org.springframework.lang.Nullable;
|
|
|
|
|
import org.springframework.util.Assert;
|
|
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
import org.springframework.web.reactive.socket.HandshakeInfo;
|
|
|
|
|
@@ -47,9 +50,13 @@ public class ReactorNettyWebSocketClient implements WebSocketClient {
|
|
|
|
|
|
|
|
|
|
private final HttpClient httpClient;
|
|
|
|
|
|
|
|
|
|
private int maxFramePayloadLength = NettyWebSocketSessionSupport.DEFAULT_FRAME_MAX_SIZE;
|
|
|
|
|
private final Supplier<WebsocketClientSpec.Builder> specBuilderSupplier;
|
|
|
|
|
|
|
|
|
|
private boolean handlePing;
|
|
|
|
|
@Nullable
|
|
|
|
|
private Integer maxFramePayloadLength = NettyWebSocketSessionSupport.DEFAULT_FRAME_MAX_SIZE;
|
|
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
|
private Boolean handlePing;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -60,12 +67,25 @@ public class ReactorNettyWebSocketClient implements WebSocketClient {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor that accepts an existing {@link HttpClient} builder.
|
|
|
|
|
* Constructor that accepts an existing {@link HttpClient}.
|
|
|
|
|
* @since 5.1
|
|
|
|
|
*/
|
|
|
|
|
public ReactorNettyWebSocketClient(HttpClient httpClient) {
|
|
|
|
|
this(httpClient, WebsocketClientSpec.builder());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor with an {@link HttpClient} and a supplier for the
|
|
|
|
|
* {@link WebsocketClientSpec.Builder} to use.
|
|
|
|
|
* @since 5.3
|
|
|
|
|
*/
|
|
|
|
|
public ReactorNettyWebSocketClient(
|
|
|
|
|
HttpClient httpClient, Supplier<WebsocketClientSpec.Builder> builderSupplier) {
|
|
|
|
|
|
|
|
|
|
Assert.notNull(httpClient, "HttpClient is required");
|
|
|
|
|
Assert.notNull(builderSupplier, "WebsocketClientSpec.Builder is required");
|
|
|
|
|
this.httpClient = httpClient;
|
|
|
|
|
this.specBuilderSupplier = builderSupplier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -76,6 +96,31 @@ public class ReactorNettyWebSocketClient implements WebSocketClient {
|
|
|
|
|
return this.httpClient;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Build an instance of {@code WebsocketClientSpec} that reflects the current
|
|
|
|
|
* configuration. This can be used to check the configured parameters except
|
|
|
|
|
* for sub-protocols which depend on the {@link WebSocketHandler} that is used
|
|
|
|
|
* for a given upgrade.
|
|
|
|
|
* @since 5.3
|
|
|
|
|
*/
|
|
|
|
|
public WebsocketClientSpec getWebsocketClientSpec() {
|
|
|
|
|
return buildSpec(null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private WebsocketClientSpec buildSpec(@Nullable String protocols) {
|
|
|
|
|
WebsocketClientSpec.Builder builder = this.specBuilderSupplier.get();
|
|
|
|
|
if (StringUtils.hasText(protocols)) {
|
|
|
|
|
builder.protocols(protocols);
|
|
|
|
|
}
|
|
|
|
|
if (this.maxFramePayloadLength != null) {
|
|
|
|
|
builder.maxFramePayloadLength(this.maxFramePayloadLength);
|
|
|
|
|
}
|
|
|
|
|
if (this.handlePing != null) {
|
|
|
|
|
builder.handlePing(this.handlePing);
|
|
|
|
|
}
|
|
|
|
|
return builder.build();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Configure the maximum allowable frame payload length. Setting this value
|
|
|
|
|
* to your application's requirement may reduce denial of service attacks
|
|
|
|
|
@@ -96,7 +141,7 @@ public class ReactorNettyWebSocketClient implements WebSocketClient {
|
|
|
|
|
* @since 5.2
|
|
|
|
|
*/
|
|
|
|
|
public int getMaxFramePayloadLength() {
|
|
|
|
|
return this.maxFramePayloadLength;
|
|
|
|
|
return getWebsocketClientSpec().maxFramePayloadLength();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -119,7 +164,7 @@ public class ReactorNettyWebSocketClient implements WebSocketClient {
|
|
|
|
|
* @since 5.2.4
|
|
|
|
|
*/
|
|
|
|
|
public boolean getHandlePing() {
|
|
|
|
|
return this.handlePing;
|
|
|
|
|
return getWebsocketClientSpec().handlePing();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@@ -128,12 +173,11 @@ public class ReactorNettyWebSocketClient implements WebSocketClient {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@SuppressWarnings("deprecation")
|
|
|
|
|
public Mono<Void> execute(URI url, HttpHeaders requestHeaders, WebSocketHandler handler) {
|
|
|
|
|
String protocols = StringUtils.collectionToCommaDelimitedString(handler.getSubProtocols());
|
|
|
|
|
return getHttpClient()
|
|
|
|
|
.headers(nettyHeaders -> setNettyHeaders(requestHeaders, nettyHeaders))
|
|
|
|
|
.websocket(protocols, getMaxFramePayloadLength(), this.handlePing)
|
|
|
|
|
.websocket(buildSpec(protocols))
|
|
|
|
|
.uri(url.toString())
|
|
|
|
|
.handle((inbound, outbound) -> {
|
|
|
|
|
HttpHeaders responseHeaders = toHttpHeaders(inbound);
|
|
|
|
|
|