@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 @SuppressWarnings("deprecation") public void onWriteInactivity(Runnable runnable, long inactivityDuration) { this.inbound.withConnection(conn -> conn.onWriteIdle(inactivityDuration, runnable)); }
.handle((in, out) -> in.withConnection(c -> c.addHandler(new JsonObjectDecoder())) .receive() .asString() .log("serve") .port(server.address().getPort()) .handle((in, out) -> { in.withConnection(c -> c.addHandler(new JsonObjectDecoder())) .receive() .asString() .log("receive")
.port(server.address().getPort()) .handle((in, out) -> { in.withConnection(x -> x.addHandlerFirst(new HttpClientCodec())) .receiveObject() .ofType(DefaultHttpContent.class) .as(ByteBufFlux::fromInbound)
@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 @SuppressWarnings("deprecation") public void onReadInactivity(Runnable runnable, long inactivityDuration) { this.inbound.withConnection(conn -> conn.onReadIdle(inactivityDuration, runnable)); }
@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 @SuppressWarnings("deprecation") public void onWriteInactivity(Runnable runnable, long inactivityDuration) { this.inbound.withConnection(conn -> conn.onWriteIdle(inactivityDuration, runnable)); }
@Override public Flux<Frame> receive() { return connection.inbound().receive().map(buf -> Frame.from(buf.retain())); }
@Override @SuppressWarnings("deprecation") public void onReadInactivity(Runnable runnable, long inactivityDuration) { this.inbound.withConnection(conn -> conn.onReadIdle(inactivityDuration, runnable)); }
@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 @SuppressWarnings("deprecation") public void onReadInactivity(Runnable runnable, long inactivityDuration) { this.inbound.withConnection(conn -> conn.onReadIdle(inactivityDuration, runnable)); }
@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 @SuppressWarnings("deprecation") public void onReadInactivity(Runnable runnable, long inactivityDuration) { this.inbound.withConnection(conn -> conn.onReadIdle(inactivityDuration, runnable)); }
@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 @SuppressWarnings("deprecation") public void onWriteInactivity(Runnable runnable, long inactivityDuration) { this.inbound.withConnection(conn -> conn.onWriteIdle(inactivityDuration, runnable)); }
@Override public Flux<Frame> receive() { return connection.inbound().receive().map(buf -> Frame.from(buf.retain())); }
@Override @SuppressWarnings("deprecation") public void onWriteInactivity(Runnable runnable, long inactivityDuration) { this.inbound.withConnection(conn -> conn.onWriteIdle(inactivityDuration, runnable)); }
@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); }); }
@Ignore public void consumerSpecAssignsEventHandlers() throws InterruptedException { final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch close = new CountDownLatch(1); final AtomicLong totalDelay = new AtomicLong(); final long start = System.currentTimeMillis(); TcpClient client = TcpClient.create() .host("localhost") .port(timeoutServerPort); Connection s = client.handle((in, out) -> { in.withConnection(c -> c.onDispose(close::countDown)); out.withConnection(c -> c.onWriteIdle(500, () -> { totalDelay.addAndGet(System.currentTimeMillis() - start); latch.countDown(); })); return Mono.delay(Duration.ofSeconds(3)) .then() .log(); }) .wiretap(true) .connectNow(); assertTrue("latch was counted down", latch.await(5, TimeUnit.SECONDS)); assertTrue("close was counted down", close.await(30, TimeUnit.SECONDS)); assertThat("totalDelay was >500ms", totalDelay.get(), greaterThanOrEqualTo(500L)); s.disposeNow(); }