io.undertow.websockets.jsr.WebsocketConnectionBuilder Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2018 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.undertow.websockets.jsr;
import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.channels.ClosedChannelException;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker13;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.CharsetUtil;
import io.undertow.httpcore.UndertowOptionMap;
class WebsocketConnectionBuilder {
private final URI uri;
private final EventLoopGroup eventLoopGroup;
private SSLContext ssl;
private UndertowOptionMap optionMap = UndertowOptionMap.EMPTY;
private InetSocketAddress bindAddress;
private WebSocketVersion version = WebSocketVersion.V13;
private WebSocketClientNegotiation clientNegotiation;
// private Set clientExtensions;
private URI proxyUri;
private SslContext proxySsl;
public WebsocketConnectionBuilder(URI uri, EventLoopGroup eventLoopGroup) {
this.uri = uri;
this.eventLoopGroup = eventLoopGroup;
}
public URI getUri() {
return uri;
}
public SSLContext getSsl() {
return ssl;
}
public WebsocketConnectionBuilder setSsl(SSLContext ssl) {
this.ssl = ssl;
return this;
}
public UndertowOptionMap getOptionMap() {
return optionMap;
}
public WebsocketConnectionBuilder setOptionMap(UndertowOptionMap optionMap) {
this.optionMap = optionMap;
return this;
}
public InetSocketAddress getBindAddress() {
return bindAddress;
}
public WebsocketConnectionBuilder setBindAddress(InetSocketAddress bindAddress) {
this.bindAddress = bindAddress;
return this;
}
public WebSocketVersion getVersion() {
return version;
}
public WebsocketConnectionBuilder setVersion(WebSocketVersion version) {
this.version = version;
return this;
}
public WebSocketClientNegotiation getClientNegotiation() {
return clientNegotiation;
}
public WebsocketConnectionBuilder setClientNegotiation(WebSocketClientNegotiation clientNegotiation) {
this.clientNegotiation = clientNegotiation;
return this;
}
//
// public Set getClientExtensions() {
// return clientExtensions;
// }
//
// public WebsocketConnectionBuilder setClientExtensions(Set clientExtensions) {
// this.clientExtensions = clientExtensions;
// return this;
// }
public URI getProxyUri() {
return proxyUri;
}
public WebsocketConnectionBuilder setProxyUri(URI proxyUri) {
this.proxyUri = proxyUri;
return this;
}
public SslContext getProxySsl() {
return proxySsl;
}
public WebsocketConnectionBuilder setProxySsl(SslContext proxySsl) {
this.proxySsl = proxySsl;
return this;
}
public CompletableFuture connect(Function connectFunction) {
io.netty.bootstrap.Bootstrap b = new io.netty.bootstrap.Bootstrap();
int actualPort = uri.getPort() == -1 ? (uri.getScheme().equals("wss") ? 443 : 80) : uri.getPort();
final WebSocketClientHandler handler =
new WebSocketClientHandler(
new WebSocketClientHandshaker13(
uri, WebSocketVersion.V13, null, false, HttpHeaders.EMPTY_HEADERS, 1280000) {
@Override
protected FullHttpRequest newHandshakeRequest() {
FullHttpRequest request = super.newHandshakeRequest();
if (clientNegotiation.getSupportedSubProtocols() != null) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < clientNegotiation.getSupportedSubProtocols().size(); ++i) {
if (i > 0) {
sb.append(", ");
}
sb.append(clientNegotiation.getSupportedSubProtocols().get(i));
}
request.headers().add(HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL, sb.toString());
}
clientNegotiation.beforeRequest(request.headers());
return request;
}
@Override
protected void verify(FullHttpResponse response) {
super.verify(response);
clientNegotiation.afterRequest(response.headers());
}
}, connectFunction);
b.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
if (ssl != null) {
SSLEngine sslEngine = ssl.createSSLEngine(uri.getHost(), actualPort);
sslEngine.setUseClientMode(true);
pipeline.addLast("ssl", new SslHandler(sslEngine));
}
pipeline.addLast("http-codec", new HttpClientCodec());
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
pipeline.addLast("ws-handler", handler);
}
});
//System.out.println("WebSocket Client connecting");
b.connect(uri.getHost(), actualPort).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.cause() != null) {
handler.handshakeFuture.completeExceptionally(future.cause());
}
}
});
return handler.handshakeFuture;
}
private class WebSocketClientHandler extends SimpleChannelInboundHandler
© 2015 - 2025 Weber Informatics LLC | Privacy Policy