@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); }); }
private void doTestIssue186(HttpClient client) { Mono<String> content = client.post() .uri("/") .send(ByteBufFlux.fromString(Mono.just("bodysample"))) .responseContent() .aggregate() .asString(); StepVerifier.create(content) .expectComplete() .verify(Duration.ofSeconds(30)); }
protected <T> BiFunction<? super HttpClientResponse, ? super ByteBufFlux, Publisher<T>> decode(Class<T> type) { return (response, byteBufFlux) -> { this.responseCallback.accept(response); if (response.status().code() == 404) { return Mono.empty(); } else { return byteBufFlux.aggregate().asInputStream().map(bytes -> deserialize(bytes, type)); } }; }
.port(0) .route(r -> r.post("/hi", (req, res) -> req.receive() .aggregate() .asString() .log() .get("/stream", (req, res) -> req.receive() .then(res.compression(true) .options(op -> op.flushOnEach()) .sendString(ep.log()).then()))) .post() .uri("/hi") .send(ByteBufFlux.fromString(Flux.just("1", "2", "3", "4", "5"))) .responseContent() .aggregate() .asString() .log() .uri("/stream") .responseContent() .asString(); System.out.println(content); .post() .uri("/hi") .send(ByteBufFlux.fromString(Flux.just("1", "2", "3", "4", "5"))) .responseContent()
@Override public Flux<Frame> receive() { return connection.inbound().receive().map(buf -> Frame.from(buf.retain())); }
@Test public void testIssue525() { DisposableServer disposableServer = HttpServer.create() .port(0) .tcpConfiguration(tcpServer -> tcpServer.doOnConnection(c -> c.addHandlerFirst("decompressor", new HttpContentDecompressor()))) .handle((req, res) -> res.send(req.receive() .retain())) .wiretap(true) .bindNow(Duration.ofSeconds(30)); byte[] bytes = "test".getBytes(Charset.defaultCharset()); String response = HttpClient.create() .port(disposableServer.port()) .wiretap(true) .headers(h -> h.add("Content-Encoding", "gzip")) .post() .uri("/") .send(Mono.just(Unpooled.wrappedBuffer(compress(bytes)))) .responseContent() .aggregate() .asString() .block(Duration.ofSeconds(30)); assertThat(response).isEqualTo("test"); disposableServer.disposeNow(); }
r.post("/test/{param}", (req, res) -> res.sendString(req.receive() .asString() .log("server-received") .map(it -> it + ' ' + req.param("param") + '!') .post() .uri("/test/World") .send(ByteBufFlux.fromString(Flux.just("Hello") .log("client-send"))) .responseContent() .aggregate() .asString() .log("client-received")
.validateHeaders(false) .initialBufferSize(10)) .handle((req, resp) -> req.receive().then(resp.sendNotFound())) .tcpConfiguration(tcp -> tcp.doOnConnection(c -> { .post() .uri("/") .send(ByteBufFlux.fromString(Mono.just("bodysample"))) .responseContent() .aggregate() .asString() .block();
/** * Convert to a {@link String} inbound {@link Flux} using the default {@link Charset}. * * @return a {@link String} inbound {@link Flux} */ public final Flux<String> asString() { return asString(Charset.defaultCharset()); }
/** * Method for receiving request messages coming a form of websocket frames. * * @return flux websocket {@link ByteBuf} */ public Flux<ByteBuf> receive() { return inbound.aggregateFrames().receive().retain(); }
/** * Decorate as {@link ByteBufFlux} * * @param source publisher to decorate * * @return a {@link ByteBufFlux} */ public static ByteBufFlux fromString(Publisher<? extends String> source) { return fromString(source, Charset.defaultCharset(), ByteBufAllocator.DEFAULT); }
@Test public void testIssue303() { DisposableServer server = HttpServer.create() .port(0) .handle((req, resp) -> resp.sendString(Mono.just("OK"))) .wiretap(true) .bindNow(); Mono<String> content = createHttpClientForContextWithPort(server) .request(HttpMethod.GET) .uri("/") .send(ByteBufFlux.fromInbound(Mono.defer(() -> Mono.just("Hello".getBytes(Charset.defaultCharset()))))) .responseContent() .aggregate() .asString(); StepVerifier.create(content) .expectNextMatches("OK"::equals) .expectComplete() .verify(Duration.ofSeconds(30)); server.disposeNow(); }
.route(r -> r.post("/", (req, resp) -> req.receive() .asString() .flatMap(data -> { latch.countDown(); .post() .uri("/") .send(ByteBufFlux.fromString(Flux.just(data))) .responseContent()) .subscribe();
/** * Decorate as {@link ByteBufFlux} * * @param source publisher to decorate * * @return a {@link ByteBufFlux} */ public static ByteBufFlux fromInbound(Publisher<?> source) { return fromInbound(source, ByteBufAllocator.DEFAULT); }
/** * Open a {@link java.nio.channels.FileChannel} from a path and stream * {@link ByteBuf} chunks with a default maximum size of 500K into * the returned {@link ByteBufFlux} * * @param path the path to the resource to stream * * @return a {@link ByteBufFlux} */ public static ByteBufFlux fromPath(Path path) { return fromPath(path, MAX_CHUNK_SIZE); }
@Test public void httpRespondsEmpty() { DisposableServer server = HttpServer.create() .port(0) .route(r -> r.post("/test/{param}", (req, res) -> Mono.empty())) .wiretap(true) .bindNow(); HttpClient client = HttpClient.create() .port(server.address().getPort()) .wiretap(true); Mono<ByteBuf> content = client.headers(h -> h.add("Content-Type", "text/plain")) .post() .uri("/test/World") .send(ByteBufFlux.fromString(Mono.just("Hello") .log("client-send"))) .responseContent() .log("client-received") .next() .doOnError(t -> System.err.println("Failed requesting server: " + t.getMessage())); StepVerifier.create(content) .expectComplete() .verify(Duration.ofSeconds(5000)); server.disposeNow(); }
/** * Disable auto memory release on each buffer published, retaining in order to prevent * premature recycling when buffers are accumulated downstream (async). * * @return {@link ByteBufFlux} of retained {@link ByteBuf} */ public ByteBufFlux retain() { return new ByteBufFlux(doOnNext(ByteBuf::retain), alloc); }