public ReactorClientHttpResponse(HttpClientResponse response, NettyInbound inbound, ByteBufAllocator alloc) { this.response = response; this.inbound = inbound; this.bufferFactory = new NettyDataBufferFactory(alloc); }
protected WebSocketMessage toMessage(WebSocketFrame frame) { DataBuffer payload = bufferFactory().wrap(frame.content()); return new WebSocketMessage(messageTypes.get(frame.getClass()), payload); }
@Test // SPR-17054 public void unsupportedMediaTypeShouldConsumeAndCancel() { NettyDataBufferFactory factory = new NettyDataBufferFactory(new PooledByteBufAllocator(true)); NettyDataBuffer buffer = factory.wrap(ByteBuffer.wrap("spring".getBytes(StandardCharsets.UTF_8))); TestPublisher<DataBuffer> body = TestPublisher.create(); MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK); response.getHeaders().setContentType(MediaType.APPLICATION_PDF); response.setBody(body.flux()); BodyExtractor<Mono<User>, ReactiveHttpInputMessage> extractor = BodyExtractors.toMono(User.class); StepVerifier.create(extractor.extract(response, this.context)) .then(() -> { body.assertWasSubscribed(); body.emit(buffer); }) .expectErrorSatisfies(throwable -> { assertTrue(throwable instanceof UnsupportedMediaTypeException); try { buffer.release(); Assert.fail("releasing the buffer should have failed"); } catch (IllegalReferenceCountException exc) { } body.assertCancelled(); }).verify(); }
private ReactorClientHttpConnector initConnector() { if (bufferFactory instanceof NettyDataBufferFactory) { ByteBufAllocator allocator = ((NettyDataBufferFactory) bufferFactory).getByteBufAllocator(); return new ReactorClientHttpConnector(this.factory, httpClient -> httpClient.tcpConfiguration(tcpClient -> tcpClient.option(ChannelOption.ALLOCATOR, allocator))); } else { return new ReactorClientHttpConnector(); } }
protected WebSocketFrame toFrame(WebSocketMessage message) { ByteBuf byteBuf = NettyDataBufferFactory.toByteBuf(message.getPayload()); if (WebSocketMessage.Type.TEXT.equals(message.getType())) { return new TextWebSocketFrame(byteBuf); } else if (WebSocketMessage.Type.BINARY.equals(message.getType())) { return new BinaryWebSocketFrame(byteBuf); } else if (WebSocketMessage.Type.PING.equals(message.getType())) { return new PingWebSocketFrame(byteBuf); } else if (WebSocketMessage.Type.PONG.equals(message.getType())) { return new PongWebSocketFrame(byteBuf); } else { throw new IllegalArgumentException("Unexpected message type: " + message.getType()); } }
private static <T extends DataBuffer> T logging(Logger log, String inOrOut, T buffer) { try { InputStream dataBuffer = buffer.asInputStream(); byte[] bytes = IOUtils.toByteArray(dataBuffer); NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false)); if (log.isDebugEnabled()) { log.debug("\n" + "{}Payload : {}", inOrOut, new String(bytes)); } DataBufferUtils.release(buffer); return (T) nettyDataBufferFactory.wrap(bytes); } catch (IOException e) { log.error(e.getMessage(), e); } return null; } }
private void verifyAllocations() { if (this.bufferFactory instanceof NettyDataBufferFactory) { ByteBufAllocator allocator = ((NettyDataBufferFactory) this.bufferFactory).getByteBufAllocator(); if (allocator instanceof PooledByteBufAllocator) { PooledByteBufAllocatorMetric metric = ((PooledByteBufAllocator) allocator).metric(); long total = getAllocations(metric.directArenas()) + getAllocations(metric.heapArenas()); assertEquals("ByteBuf Leak: " + total + " unreleased allocations", 0, total); } } }
protected WebSocketFrame toFrame(WebSocketMessage message) { ByteBuf byteBuf = NettyDataBufferFactory.toByteBuf(message.getPayload()); if (WebSocketMessage.Type.TEXT.equals(message.getType())) { return new TextWebSocketFrame(byteBuf); } else if (WebSocketMessage.Type.BINARY.equals(message.getType())) { return new BinaryWebSocketFrame(byteBuf); } else if (WebSocketMessage.Type.PING.equals(message.getType())) { return new PingWebSocketFrame(byteBuf); } else if (WebSocketMessage.Type.PONG.equals(message.getType())) { return new PongWebSocketFrame(byteBuf); } else { throw new IllegalArgumentException("Unexpected message type: " + message.getType()); } }
public ReactorClientHttpResponse(HttpClientResponse response, NettyInbound inbound, ByteBufAllocator alloc) { this.response = response; this.inbound = inbound; this.bufferFactory = new NettyDataBufferFactory(alloc); }
@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); }); }
public ReactorClientHttpRequest(HttpMethod method, URI uri, HttpClientRequest request, NettyOutbound outbound) { this.httpMethod = method; this.uri = uri; this.request = request; this.outbound = outbound; this.bufferFactory = new NettyDataBufferFactory(outbound.alloc()); }
/** * Returns a {@link PooledDataBuffer} which will be released after consuming by the consumer. * Currently the {@link NettyDataBuffer} is only one implementation of the {@link PooledDataBuffer} * which is exposed to the public API. */ private PooledDataBuffer withNettyDataBufferFactory(ByteBufHttpData data) { return ((NettyDataBufferFactory) delegate).wrap(data.content()); }
public ReactorClientHttpRequest(HttpMethod method, URI uri, HttpClientRequest request, NettyOutbound outbound) { this.httpMethod = method; this.uri = uri; this.request = request; this.outbound = outbound; this.bufferFactory = new NettyDataBufferFactory(outbound.alloc()); }
@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> apply(HttpServerRequest reactorRequest, HttpServerResponse reactorResponse) { NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc()); try { ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory); ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory); if (request.getMethod() == HttpMethod.HEAD) { response = new HttpHeadResponseDecorator(response); } return this.httpHandler.handle(request, response) .doOnError(ex -> logger.trace(request.getLogPrefix() + "Failed to complete: " + ex.getMessage())) .doOnSuccess(aVoid -> logger.trace(request.getLogPrefix() + "Handling completed")); } catch (URISyntaxException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to get request URI: " + ex.getMessage()); } reactorResponse.status(HttpResponseStatus.BAD_REQUEST); return Mono.empty(); } }
@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); }); }
@Parameterized.Parameters(name = "{0}") public static Object[][] buffers() { return new Object[][]{ {new NettyDataBufferFactory(new UnpooledByteBufAllocator(true))}, {new NettyDataBufferFactory(new UnpooledByteBufAllocator(false))}, {new NettyDataBufferFactory(new PooledByteBufAllocator(true))}, {new NettyDataBufferFactory(new PooledByteBufAllocator(false))}}; }
protected WebSocketMessage toMessage(WebSocketFrame frame) { DataBuffer payload = bufferFactory().wrap(frame.content()); return new WebSocketMessage(MESSAGE_TYPES.get(frame.getClass()), payload); }
@Parameterized.Parameters(name = "{0}") public static Object[][] dataBufferFactories() { return new Object[][] { {new NettyDataBufferFactory(new UnpooledByteBufAllocator(true))}, {new NettyDataBufferFactory(new UnpooledByteBufAllocator(false))}, // disable caching for reliable leak detection, see https://github.com/netty/netty/issues/5275 {new NettyDataBufferFactory(new PooledByteBufAllocator(true, 1, 1, 8192, 11, 0, 0, 0, true))}, {new NettyDataBufferFactory(new PooledByteBufAllocator(false, 1, 1, 8192, 11, 0, 0, 0, true))}, {new DefaultDataBufferFactory(true)}, {new DefaultDataBufferFactory(false)} }; }
@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); }); }