private static WebClient.Builder createDefaultWebClient(Duration connectTimeout, Duration readTimeout) { HttpClient httpClient = HttpClient.create() .compress(true) .tcpConfiguration(tcp -> tcp.bootstrap(bootstrap -> bootstrap.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, (int) connectTimeout.toMillis() )).observe((connection, newState) -> { if (ConnectionObserver.State.CONNECTED.equals(newState)) { connection.addHandlerLast(new ReadTimeoutHandler(readTimeout.toMillis(), TimeUnit.MILLISECONDS )); } })); ReactorClientHttpConnector connector = new ReactorClientHttpConnector(httpClient); return WebClient.builder().clientConnector(connector); } }
private static WebClientProvider getWebClientProvider(ClientConfiguration clientConfiguration) { Duration connectTimeout = clientConfiguration.getConnectTimeout(); Duration soTimeout = clientConfiguration.getSocketTimeout(); TcpClient tcpClient = TcpClient.create(); if (!connectTimeout.isNegative()) { tcpClient = tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, Math.toIntExact(connectTimeout.toMillis())); } if (!soTimeout.isNegative()) { tcpClient = tcpClient.doOnConnected(connection -> connection // .addHandlerLast(new ReadTimeoutHandler(soTimeout.toMillis(), TimeUnit.MILLISECONDS)) .addHandlerLast(new WriteTimeoutHandler(soTimeout.toMillis(), TimeUnit.MILLISECONDS))); } String scheme = "http"; HttpClient httpClient = HttpClient.from(tcpClient); if (clientConfiguration.useSsl()) { httpClient = httpClient.secure(sslConfig -> { Optional<SSLContext> sslContext = clientConfiguration.getSslContext(); sslContext.ifPresent(it -> sslConfig.sslContext(new JdkSslContext(it, true, ClientAuth.NONE))); }); scheme = "https"; } ReactorClientHttpConnector connector = new ReactorClientHttpConnector(httpClient); WebClientProvider provider = WebClientProvider.create(scheme, connector); return provider.withDefaultHeaders(clientConfiguration.getDefaultHeaders()); }
@Override public Mono<DuplexConnection> connect() { return client .doOnConnected(c -> c.addHandlerLast(new RSocketLengthCodec())) .connect() .map(TcpDuplexConnection::new); } }
@Override public Mono<CloseableChannel> start(ConnectionAcceptor acceptor) { Objects.requireNonNull(acceptor, "acceptor must not be null"); return server .doOnConnection( c -> { c.addHandlerLast(new RSocketLengthCodec()); TcpDuplexConnection connection = new TcpDuplexConnection(c); acceptor.apply(connection).then(Mono.<Void>never()).subscribe(c.disposeSubscriber()); }) .bind() .map(CloseableChannel::new); } }
/** * Add a {@link ChannelHandler} to the end of the "user" {@link io.netty.channel.ChannelPipeline}, * that is just before the reactor-added handlers (like {@link NettyPipeline#ReactiveBridge}. * If a handler with a similar name already exists, this operation is skipped. * <p> * {@code [ [reactor codecs], [<- user FIRST HANDLERS added here, user LAST HANDLERS added here ->], [reactor handlers] ]} * <p> * If effectively added, the handler will be safely removed when the channel is made * inactive (pool release). * * @param handler handler instance * * @return this Connection */ default Connection addHandlerLast(ChannelHandler handler){ return addHandlerLast(handler.getClass().getSimpleName(), handler); }
/** * Add a {@link ChannelHandler} to the end of the "user" {@link io.netty.channel.ChannelPipeline}, * that is just before the reactor-added handlers (like {@link NettyPipeline#ReactiveBridge}. * If a handler with a similar name already exists, this operation is skipped. * <p> * {@code [ [reactor codecs], [<- user FIRST HANDLERS added here, user LAST HANDLERS added here ->], [reactor handlers] ]} * <p> * If effectively added, the handler will be safely removed when the channel is made * inactive (pool release). * * @param handler handler instance * * @return this Connection */ default Connection addHandlerLast(ChannelHandler handler){ return addHandlerLast(handler.getClass().getSimpleName(), handler); }
static void addChunkedWriter(Connection c){ if (c.channel() .pipeline() .get(ChunkedWriteHandler.class) == null) { c.addHandlerLast(NettyPipeline.ChunkedWriter, new ChunkedWriteHandler()); } }
static void addChunkedWriter(Connection c){ if (c.channel() .pipeline() .get(ChunkedWriteHandler.class) == null) { c.addHandlerLast(NettyPipeline.ChunkedWriter, new ChunkedWriteHandler()); } }
/** * Turn this {@link WebsocketInbound} into aggregating mode which will only produce * fully formed frame that have been received fragmented. * * @param maxContentLength the maximum frame length * * @return this inbound */ default WebsocketInbound aggregateFrames(int maxContentLength) { withConnection(c -> c.addHandlerLast(new WebSocketFrameAggregator(maxContentLength))); return this; }
/** * Turn this {@link WebsocketInbound} into aggregating mode which will only produce * fully formed frame that have been received fragmented. * * @param maxContentLength the maximum frame length * * @return this inbound */ default WebsocketInbound aggregateFrames(int maxContentLength) { withConnection(c -> c.addHandlerLast(new WebSocketFrameAggregator(maxContentLength))); return this; }
@Override public Mono<DuplexConnection> connect() { return client .doOnConnected(c -> c.addHandlerLast(new RSocketLengthCodec())) .connect() .map(TcpDuplexConnection::new); } }
@Override public Mono<CloseableChannel> start(ConnectionAcceptor acceptor) { Objects.requireNonNull(acceptor, "acceptor must not be null"); return server .doOnConnection( c -> { c.addHandlerLast(new RSocketLengthCodec()); TcpDuplexConnection connection = new TcpDuplexConnection(c); acceptor.apply(connection).then(Mono.<Void>never()).subscribe(c.disposeSubscriber()); }) .bind() .map(CloseableChannel::new); } }
@Test public void addNonByteDecoderWhenEmptyPipeline() { ChannelHandler decoder = new ChannelHandlerAdapter() { }; testContext.addHandlerLast("decoder", decoder); assertEquals(channel.pipeline() .names(), Arrays.asList("decoder", "DefaultChannelPipeline$TailContext#0")); }
@Test public void addNonByteDecoderWhenNoLeft() { channel.pipeline() .addLast(NettyPipeline.ReactiveBridge, new ChannelHandlerAdapter() { }); ChannelHandler decoder = new ChannelHandlerAdapter() { }; testContext.addHandlerLast("decoder", decoder); assertEquals(channel.pipeline() .names(), Arrays.asList("decoder", NettyPipeline.ReactiveBridge, "DefaultChannelPipeline$TailContext#0")); }
@Test public void addNonByteDecoderWhenNoRight() { channel.pipeline() .addLast(NettyPipeline.HttpCodec, new ChannelHandlerAdapter() { }); ChannelHandler decoder = new ChannelHandlerAdapter() { }; testContext.addHandlerLast("decoder", decoder); assertEquals(channel.pipeline() .names(), Arrays.asList(NettyPipeline.HttpCodec, "decoder", "DefaultChannelPipeline$TailContext#0")); }
@Test public void addNonByteDecoderWhenFullReactorPipeline() { channel.pipeline() .addLast(NettyPipeline.HttpCodec, new HttpServerCodec()) .addLast(NettyPipeline.HttpTrafficHandler, new ChannelDuplexHandler()) .addLast(NettyPipeline.ReactiveBridge, new ChannelHandlerAdapter() { }); ChannelHandler decoder = new ChannelHandlerAdapter() { }; testContext.addHandlerLast("decoder", decoder); assertEquals(channel.pipeline() .names(), Arrays.asList(NettyPipeline.HttpCodec, NettyPipeline.HttpTrafficHandler, "decoder", NettyPipeline.ReactiveBridge, "DefaultChannelPipeline$TailContext#0")); }
@Test public void addByteDecoderWhenEmptyPipeline() { ChannelHandler decoder = new LineBasedFrameDecoder(12); testContext.addHandlerLast("decoder", decoder) .addHandlerFirst("decoder$extract", NettyPipeline.inboundHandler(ADD_EXTRACTOR)); assertEquals(channel.pipeline() .names(), Arrays.asList("decoder$extract", "decoder", "DefaultChannelPipeline$TailContext#0")); }
@Test public void addByteDecoderWhenFullReactorPipeline() { channel.pipeline() .addLast(NettyPipeline.HttpCodec, new HttpServerCodec()) .addLast(NettyPipeline.HttpTrafficHandler, new ChannelDuplexHandler()) .addLast(NettyPipeline.ReactiveBridge, new ChannelHandlerAdapter() { }); ChannelHandler decoder = new LineBasedFrameDecoder(12); testContext.addHandlerLast("decoder", decoder) .addHandlerFirst("decoder$extract", NettyPipeline.inboundHandler(ADD_EXTRACTOR)); assertEquals(channel.pipeline() .names(), Arrays.asList(NettyPipeline.HttpCodec, NettyPipeline.HttpTrafficHandler, "decoder$extract", "decoder", NettyPipeline.ReactiveBridge, "DefaultChannelPipeline$TailContext#0")); }
@Test public void addByteDecoderWhenNoLeft() { channel.pipeline() .addLast(NettyPipeline.ReactiveBridge, new ChannelHandlerAdapter() { }); ChannelHandler decoder = new LineBasedFrameDecoder(12); testContext.addHandlerLast("decoder", decoder) .addHandlerFirst("decoder$extract", NettyPipeline.inboundHandler(ADD_EXTRACTOR)); assertEquals(channel.pipeline() .names(), Arrays.asList("decoder$extract", "decoder", NettyPipeline.ReactiveBridge, "DefaultChannelPipeline$TailContext#0")); }
@Test public void addByteDecoderWhenNoRight() { channel.pipeline() .addLast(NettyPipeline.HttpCodec, new ChannelHandlerAdapter() { }); ChannelHandler decoder = new LineBasedFrameDecoder(12); testContext.addHandlerLast("decoder", decoder) .addHandlerFirst("decoder$extract", NettyPipeline.inboundHandler(ADD_EXTRACTOR)); assertEquals(channel.pipeline() .names(), Arrays.asList(NettyPipeline.HttpCodec, "decoder$extract", "decoder", "DefaultChannelPipeline$TailContext#0")); }