@Override public Flux<DataBuffer> getBody() { return this.inbound.receive() .doOnSubscribe(s -> { if (this.rejectSubscribers.get()) { throw new IllegalStateException("The client response body can only be consumed once."); } }) .doOnCancel(() -> { // https://github.com/reactor/reactor-netty/issues/503 // FluxReceive rejects multiple subscribers, but not after a cancel(). // Subsequent subscribers after cancel() will not be rejected, but will hang instead. // So we need to intercept and reject them in that case. this.rejectSubscribers.set(true); }) .map(byteBuf -> { byteBuf.retain(); return this.bufferFactory.wrap(byteBuf); }); }
@Override public Flux<DataBuffer> getBody() { return this.inbound.receive() .doOnSubscribe(s -> { if (this.rejectSubscribers.get()) { throw new IllegalStateException("The client response body can only be consumed once."); } }) .doOnCancel(() -> { // https://github.com/reactor/reactor-netty/issues/503 // FluxReceive rejects multiple subscribers, but not after a cancel(). // Subsequent subscribers after cancel() will not be rejected, but will hang instead. // So we need to intercept and reject them in that case. this.rejectSubscribers.set(true); }) .map(byteBuf -> { byteBuf.retain(); return this.bufferFactory.wrap(byteBuf); }); }
@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // NOTICE: nothing in "pre" filter stage as CLIENT_RESPONSE_CONN_ATTR is not added // until the NettyRoutingFilter is run return chain.filter(exchange).then(Mono.defer(() -> { Connection connection = exchange.getAttribute(CLIENT_RESPONSE_CONN_ATTR); if (connection == null) { return Mono.empty(); } log.trace("NettyWriteResponseFilter start"); ServerHttpResponse response = exchange.getResponse(); NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory(); //TODO: what if it's not netty final Flux<NettyDataBuffer> body = connection.inbound().receive() .retain() //TODO: needed? .map(factory::wrap); MediaType contentType = null; try { contentType = response.getHeaders().getContentType(); } catch (Exception e) { log.trace("invalid media type", e); } return (isStreamingMediaType(contentType) ? response.writeAndFlushWith(body.map(Flux::just)) : response.writeWith(body)); })); }
@Override public Flux<Frame> receive() { return connection.inbound().receive().map(buf -> Frame.from(buf.retain())); }
@Override public Flux<Frame> receive() { return connection .inbound() .receive() .map( buf -> { CompositeByteBuf composite = connection.channel().alloc().compositeBuffer(); ByteBuf length = wrappedBuffer(new byte[FRAME_LENGTH_SIZE]); FrameHeaderFlyweight.encodeLength(length, 0, buf.readableBytes()); composite.addComponents(true, length, buf.retain()); return Frame.from(composite); }); }
@Override public Flux<DataBuffer> getBody() { return this.inbound.receive() .doOnSubscribe(s -> // See https://github.com/reactor/reactor-netty/issues/503 Assert.state(this.bodyConsumed.compareAndSet(false, true), "The client response body can only be consumed once.")) .map(byteBuf -> { byteBuf.retain(); return this.bufferFactory.wrap(byteBuf); }); }
@Override public Flux<DataBuffer> getBody() { return response.receive() .doOnSubscribe(s -> // WebClient's onStatus handling tries to drain the body, which may // have also been done by application code in the onStatus callback. // That relies on the 2nd subscriber being rejected but FluxReceive // isn't consistent in doing so and may hang without completion. Assert.state(this.bodyConsumed.compareAndSet(false, true), "The client response body can only be consumed once.")) .map(byteBuf -> { // 5.0.x only: do not retain, make a copy.. byte[] data = new byte[byteBuf.readableBytes()]; byteBuf.readBytes(data); return ReactorClientHttpConnector.BUFFER_FACTORY.wrap(data); }); }
@Override public Flux<Frame> receive() { return connection.inbound().receive().map(buf -> Frame.from(buf.retain())); }
@Override public Flux<Frame> receive() { return connection .inbound() .receive() .map( buf -> { CompositeByteBuf composite = connection.channel().alloc().compositeBuffer(); ByteBuf length = wrappedBuffer(new byte[FRAME_LENGTH_SIZE]); FrameHeaderFlyweight.encodeLength(length, 0, buf.readableBytes()); composite.addComponents(true, length, buf.retain()); return Frame.from(composite); }); }
@SuppressWarnings("unused") private Mono<Void> onMessage(NettyInbound in, NettyOutbound out) { return in.receive() // .retain() .map(this::toMessage) .doOnNext(messageSink::next) .then(); }
@Test public void testTcpClientWithInetSocketAddress() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); TcpClient client = TcpClient.create().port(echoServerPort); Connection s = client.handle((in, out) -> { in.receive() .subscribe(d -> latch.countDown()); return out.sendString(Flux.just("Hello")) .neverComplete(); }) .wiretap(true) .connectNow(Duration.ofSeconds(5)); latch.await(5, TimeUnit.SECONDS); s.disposeNow(); assertThat("latch was counted down", latch.getCount(), is(0L)); }
private void tcpClientHandlesLineFeedData(TcpClient client) throws InterruptedException { final int messages = 100; final CountDownLatch latch = new CountDownLatch(messages); final List<String> strings = new ArrayList<>(); Connection c = client.handle((in, out) -> out.sendString(Flux.range(1, messages) .map(i -> "Hello World!" + i + "\n") .subscribeOn(Schedulers.parallel())) .then( in.receive() .asString() .take(100) .flatMapIterable(s -> Arrays.asList(s.split("\\n"))) .doOnNext(s -> { strings.add(s); latch.countDown(); }).then()) ) .wiretap(true) .connectNow(Duration.ofSeconds(30)); System.out.println("Connected"); c.onDispose() .log() .block(Duration.ofSeconds(30)); assertTrue("Expected messages not received. Received " + strings.size() + " messages: " + strings, latch.await(15, TimeUnit.SECONDS)); assertEquals(messages, strings.size()); }
@Test public void testTcpClient() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); Connection client = TcpClient.create() .host("localhost") .port(echoServerPort) .handle((in, out) -> { in.receive() .log("conn") .subscribe(s -> latch.countDown()); return out.sendString(Flux.just("Hello World!")) .neverComplete(); }) .wiretap(true) .connectNow(); latch.await(30, TimeUnit.SECONDS); client.disposeNow(); assertThat("latch was counted down", latch.getCount(), is(0L)); }
@Test public void connectionWillAttemptToReconnectWhenItIsDropped() throws InterruptedException { final CountDownLatch connectionLatch = new CountDownLatch(1); final CountDownLatch reconnectionLatch = new CountDownLatch(1); try { TcpClient tcpClient = TcpClient.newConnection() .host("localhost") .port(abortServerPort); Mono<? extends Connection> handler = tcpClient.handle((in, out) -> { System.out.println("Start"); connectionLatch.countDown(); in.receive() .subscribe(); return Flux.never(); }) .wiretap(true) .connect(); handler.log() .then(handler.doOnSuccess(s -> reconnectionLatch.countDown())) .block(Duration.ofSeconds(30)) .onDispose(); assertTrue("Initial connection is made", connectionLatch.await(5, TimeUnit.SECONDS)); assertTrue("A reconnect attempt was made", reconnectionLatch.await(5, TimeUnit.SECONDS)); } catch (AbortedException ise){ return; } }
.map(i -> "Hello World!" + i + "\n") .subscribeOn(Schedulers.parallel())) .then( in.receive() .asString() .take(100)
@Test public void testIssue462() throws InterruptedException { final CountDownLatch countDownLatch = new CountDownLatch(1); DisposableServer server = TcpServer.create() .port(0) .handle((in, out) -> { in.receive() .log("channel") .subscribe(trip -> countDownLatch.countDown()); return Flux.never(); }) .wiretap(true) .bindNow(); assertNotNull(server); System.out.println("PORT +" + server.address() .getPort()); Connection client = TcpClient.create() .port(server.address() .getPort()) .handle((in, out) -> out.sendString(Flux.just("test"))) .wiretap(true) .connectNow(); assertNotNull(client); client.disposeNow(); server.disposeNow(); assertThat("Latch was counted down", countDownLatch.await(5, TimeUnit.SECONDS)); }
@Test public void disableChunkImplicitDefault() { ConnectionProvider p = ConnectionProvider.fixed("test", 1); HttpClient client = HttpClient.create(p) .tcpConfiguration(tcpClient -> tcpClient.host("google.com")) .wiretap(true) .chunkedTransfer(false); Tuple2<HttpResponseStatus, Channel> r = client.get() .uri("/unsupportedURI") .responseConnection((res, conn) -> Mono.just(res.status()) .delayUntil(s -> conn.inbound().receive()) .zipWith(Mono.just(conn.channel()))) .blockLast(Duration.ofSeconds(30)); assertThat(r).isNotNull(); Channel r2 = client.get() .uri("/unsupportedURI") .responseConnection((res, conn) -> Mono.just(conn.channel()) .delayUntil(s -> conn.inbound().receive())) .blockLast(Duration.ofSeconds(30)); assertThat(r2).isNotNull(); Assert.assertSame(r.getT2(), r2); Assert.assertEquals(r.getT1(), HttpResponseStatus.NOT_FOUND); p.dispose(); }
.handle((in, out) -> { try { in.receive() .blockFirst();
.port(0) .handle((in, out) -> in.receive() .take(1) .thenMany(Flux.defer(() ->
in.receive() .asString() .subscribe(data -> {