/** * a {@link String} inbound {@link Mono} * * @return a {@link String} inbound {@link Mono} */ public final Mono<String> asString() { return asString(Charset.defaultCharset()); }
/** * Disable auto memory release on each signal published in order to prevent premature * recycling when buffers are accumulated downstream (async). * * @return {@link ByteBufMono} of retained {@link ByteBuf} */ public ByteBufMono retain() { return new ByteBufMono(doOnNext(ByteBuf::retain)); }
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)); } }; }
/** * a {@literal byte[]} inbound {@link Mono} * * @return a {@literal byte[]} inbound {@link Mono} */ public final Mono<byte[]> asByteArray() { return handle((bb, sink) -> { try { byte[] bytes = new byte[bb.readableBytes()]; bb.readBytes(bytes); sink.next(bytes); } catch (IllegalReferenceCountException e) { sink.complete(); } }); }
@Test public void testPreferContentLengthWhenPost() { DisposableServer server = HttpServer.create() .port(0) .wiretap(true) .handle((req, res) -> res.header(HttpHeaderNames.CONTENT_LENGTH, req.requestHeaders() .get(HttpHeaderNames.CONTENT_LENGTH)) .send(req.receive() .aggregate() .retain())) .bindNow(); StepVerifier.create( createHttpClientForContextWithAddress(server) .chunkedTransfer(false) .headers(h -> h.add(HttpHeaderNames.CONTENT_LENGTH, 5)) .post() .uri("/") .send(Mono.just(Unpooled.wrappedBuffer("hello".getBytes(Charset.defaultCharset())))) .responseContent() .aggregate() .asString()) .expectNextMatches("hello"::equals) .expectComplete() .verify(Duration.ofSeconds(30)); server.disposeNow(); }
@Override public Mono<ClientMessage> requestResponse(ClientMessage request) { return Mono.defer( () -> { ByteBuf byteBuf = codec.encode(request); return httpClient .post() .uri(request.qualifier()) .send( (httpRequest, out) -> { LOGGER.debug("Sending request {}", request); // prepare request headers request.headers().forEach(httpRequest::header); return out.sendObject(byteBuf).then(); }) .responseSingle( (httpResponse, bbMono) -> bbMono.map(ByteBuf::retain).map(content -> toMessage(httpResponse, content))); }); }
@Test public void sendFileAsync4096() throws IOException, URISyntaxException { doTestSendFileAsync((req, resp) -> resp.sendByteArray(req.receive() .aggregate() .asByteArray()), 4096, null); }
@Test public void simpleClientPooling() { ConnectionProvider p = ConnectionProvider.fixed("test", 1); AtomicReference<Channel> ch1 = new AtomicReference<>(); AtomicReference<Channel> ch2 = new AtomicReference<>(); HttpResponseStatus r = HttpClient.create(p) .doOnResponse((res, c) -> ch1.set(c.channel())) .wiretap(true) .get() .uri("http://google.com/unsupportedURI") .responseSingle((res, buf) -> buf.thenReturn(res.status())) .block(Duration.ofSeconds(30)); HttpClient.create(p) .doOnResponse((res, c) -> ch2.set(c.channel())) .wiretap(true) .get() .uri("http://google.com/unsupportedURI") .responseSingle((res, buf) -> buf.thenReturn(res.status())) .block(Duration.ofSeconds(30)); AtomicBoolean same = new AtomicBoolean(); same.set(ch1.get() == ch2.get()); Assert.assertTrue(same.get()); Assert.assertEquals(r, HttpResponseStatus.NOT_FOUND); p.dispose(); }
/** * a {@link ByteBuffer} inbound {@link Mono} * * @return a {@link ByteBuffer} inbound {@link Mono} */ public final Mono<ByteBuffer> asByteBuffer() { return handle((bb, sink) -> { try { sink.next(bb.nioBuffer()); } catch (IllegalReferenceCountException e) { sink.complete(); } }); }
@Override public Publisher<Void> apply(HttpServerRequest httpRequest, HttpServerResponse httpResponse) { LOGGER.debug( "Accepted request: {}, headers: {}, params: {}", httpRequest, httpRequest.requestHeaders(), httpRequest.params()); if (httpRequest.method() != POST) { LOGGER.error("Unsupported HTTP method. Expected POST, actual {}", httpRequest.method()); return methodNotAllowed(httpResponse); } return httpRequest .receive() .aggregate() .map(ByteBuf::retain) .doOnNext(content -> metrics.markRequest()) .flatMap(content -> handleRequest(content, httpRequest, httpResponse)) .doOnSuccess(avoid -> metrics.markResponse()) .onErrorResume(t -> error(httpResponse, DefaultErrorMapper.INSTANCE.toMessage(t))); }
@Test public void sendFileAsync1024() throws IOException, URISyntaxException { doTestSendFileAsync((req, resp) -> resp.sendByteArray(req.receive() .aggregate() .asByteArray()), 1024, null); }
.responseSingle((r, buf) -> buf.thenReturn(r.status().code())) .log() .block(Duration.ofSeconds(30));
/** * a {@link String} inbound {@link Mono} * * @return a {@link String} inbound {@link Mono} */ public final Mono<String> asString() { return asString(Charset.defaultCharset()); }
/** * Disable auto memory release on each signal published in order to prevent premature * recycling when buffers are accumulated downstream (async). * * @return {@link ByteBufMono} of retained {@link ByteBuf} */ public ByteBufMono retain() { return new ByteBufMono(doOnNext(ByteBuf::retain)); }
/** * a {@literal byte[]} inbound {@link Mono} * * @return a {@literal byte[]} inbound {@link Mono} */ public final Mono<byte[]> asByteArray() { return handle((bb, sink) -> { try { byte[] bytes = new byte[bb.readableBytes()]; bb.readBytes(bytes); sink.next(bytes); } catch (IllegalReferenceCountException e) { sink.complete(); } }); }
@Override public Publisher<Void> apply(HttpServerRequest httpRequest, HttpServerResponse httpResponse) { LOGGER.debug( "Accepted request: {}, headers: {}, params: {}", httpRequest, httpRequest.requestHeaders(), httpRequest.params()); if (httpRequest.method() != POST) { LOGGER.error("Unsupported HTTP method. Expected POST, actual {}", httpRequest.method()); return methodNotAllowed(httpResponse); } return httpRequest .receive() .aggregate() .map(ByteBuf::retain) .doOnNext(content -> metrics.markRequest()) .flatMap(content -> handleRequest(content, httpRequest, httpResponse)) .doOnSuccess(avoid -> metrics.markResponse()) .onErrorResume(t -> error(httpResponse, ExceptionProcessor.toMessage(t))); }
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)); } }; }
.get() .uri("/test") .responseSingle((res, buf) -> buf.asByteArray() .zipWith(Mono.just(res.responseHeaders()))) .block();
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)); }
/** * a {@link ByteBuffer} inbound {@link Mono} * * @return a {@link ByteBuffer} inbound {@link Mono} */ public final Mono<ByteBuffer> asByteBuffer() { return handle((bb, sink) -> { try { sink.next(bb.nioBuffer()); } catch (IllegalReferenceCountException e) { sink.complete(); } }); }