Search in sources :

Example 1 with ReceivedResponse

use of ratpack.core.http.client.ReceivedResponse in project ratpack by ratpack.

the class RequestActionSupport method addCommonResponseHandlers.

private void addCommonResponseHandlers(ChannelPipeline p, Downstream<? super T> downstream) throws Exception {
    if (channelKey.ssl && p.get(SSL_HANDLER_NAME) == null) {
        // this is added once because netty is not able to properly replace this handler on
        // pooled channels from request to request. Because a pool is unique to a uri,
        // doing this works, as subsequent requests would be passing in the same certs.
        p.addLast(SSL_HANDLER_NAME, createSslHandler());
    }
    p.addLast(CLIENT_CODEC_HANDLER_NAME, new HttpClientCodec(4096, 8192, requestConfig.responseMaxChunkSize, false));
    p.addLast(READ_TIMEOUT_HANDLER_NAME, new ReadTimeoutHandler(requestConfig.readTimeout.toNanos(), TimeUnit.NANOSECONDS));
    p.addLast(REDIRECT_HANDLER_NAME, new SimpleChannelInboundHandler<HttpObject>(false) {

        boolean redirected;

        HttpResponse response;

        @Override
        public void channelInactive(ChannelHandlerContext ctx) {
            ctx.fireExceptionCaught(new PrematureChannelClosureException("Server " + requestConfig.uri + " closed the connection prematurely"));
        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
            // received the end frame of the 100 Continue, send the body, then process the resulting response
            if (msg instanceof LastHttpContent && expectContinue && receivedContinue) {
                expectContinue = false;
                receivedContinue = false;
                sendRequestBody(downstream, ctx.channel());
                return;
            }
            if (msg instanceof HttpResponse) {
                this.response = (HttpResponse) msg;
                int status = response.status().code();
                if (expectContinue) {
                    // need to wait for a 100 Continue to come in
                    if (status == HttpResponseStatus.CONTINUE.code()) {
                        // received the continue, now wait for the end frame before sending the body
                        receivedContinue = true;
                        return;
                    } else if (!isRedirect(status)) {
                        // Received a response other than 100 Continue and not a redirect, so clear that we expect a 100
                        // and process this as the normal response without sending the body.
                        expectContinue = false;
                    }
                }
                int maxRedirects = requestConfig.maxRedirects;
                String locationValue = response.headers().getAsString(HttpHeaderConstants.LOCATION);
                Action<? super RequestSpec> redirectConfigurer = RequestActionSupport.this.requestConfigurer;
                if (isRedirect(status) && redirectCount < maxRedirects && locationValue != null) {
                    final Function<? super ReceivedResponse, Action<? super RequestSpec>> onRedirect = requestConfig.onRedirect;
                    if (onRedirect != null) {
                        final Action<? super RequestSpec> onRedirectResult = ((DefaultExecution) execution).runSync(() -> onRedirect.apply(toReceivedResponse(response)));
                        if (onRedirectResult == null) {
                            redirectConfigurer = null;
                        } else {
                            redirectConfigurer = redirectConfigurer.append(onRedirectResult);
                        }
                    }
                    if (redirectConfigurer != null) {
                        Action<? super RequestSpec> redirectRequestConfig = s -> {
                            if (status == 301 || status == 302) {
                                s.get();
                            }
                        };
                        Action<? super RequestSpec> finalRedirectRequestConfig = redirectConfigurer.append(redirectRequestConfig);
                        Action<? super RequestSpec> executionBoundRedirectRequestConfig = request -> {
                            ((DefaultExecution) execution).runSync(() -> {
                                finalRedirectRequestConfig.execute(request);
                                return null;
                            });
                        };
                        URI locationUri = absolutizeRedirect(requestConfig.uri, locationValue);
                        redirected = true;
                        Future<Void> dispose = dispose(ctx.pipeline(), response);
                        dispose.addListener(future -> {
                            if (future.isSuccess()) {
                                onRedirect(locationUri, redirectCount + 1, expectContinue, executionBoundRedirectRequestConfig).connect(downstream);
                            } else {
                                downstream.error(future.cause());
                            }
                        });
                    }
                }
            }
            if (!redirected) {
                ctx.fireChannelRead(msg);
            }
        }
    });
    if (requestConfig.decompressResponse) {
        p.addLast(DECOMPRESS_HANDLER_NAME, new HttpContentDecompressor());
    }
    p.addLast(WRITABILITY_HANDLER_NAME, new ChannelInboundHandlerAdapter() {

        @Override
        public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
            onWritabilityChanged.run();
            super.channelWritabilityChanged(ctx);
        }
    });
    addResponseHandlers(p, downstream);
}
Also used : Execution(ratpack.exec.Execution) PrematureChannelClosureException(io.netty.handler.codec.PrematureChannelClosureException) SSLParameters(javax.net.ssl.SSLParameters) URISyntaxException(java.net.URISyntaxException) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Upstream(ratpack.exec.Upstream) ReceivedResponse(ratpack.core.http.client.ReceivedResponse) ratpack.core.http.internal(ratpack.core.http.internal) Unpooled(io.netty.buffer.Unpooled) SSLEngine(javax.net.ssl.SSLEngine) RequestSpec(ratpack.core.http.client.RequestSpec) HttpClientReadTimeoutException(ratpack.core.http.client.HttpClientReadTimeoutException) ByteBuf(io.netty.buffer.ByteBuf) ReadTimeoutException(io.netty.handler.timeout.ReadTimeoutException) io.netty.channel(io.netty.channel) URI(java.net.URI) Subscriber(org.reactivestreams.Subscriber) Downstream(ratpack.exec.Downstream) Function(ratpack.func.Function) SslContext(io.netty.handler.ssl.SslContext) ReadTimeoutHandler(io.netty.handler.timeout.ReadTimeoutHandler) Publisher(org.reactivestreams.Publisher) Headers(ratpack.core.http.Headers) GenericFutureListener(io.netty.util.concurrent.GenericFutureListener) DefaultExecution(ratpack.exec.internal.DefaultExecution) HostAndPort(com.google.common.net.HostAndPort) TimeUnit(java.util.concurrent.TimeUnit) io.netty.handler.codec.http(io.netty.handler.codec.http) SSLException(javax.net.ssl.SSLException) Status(ratpack.core.http.Status) SslHandler(io.netty.handler.ssl.SslHandler) Exceptions(ratpack.func.Exceptions) Action(ratpack.func.Action) Subscription(org.reactivestreams.Subscription) ChannelPool(io.netty.channel.pool.ChannelPool) SslContextBuilder(io.netty.handler.ssl.SslContextBuilder) Future(io.netty.util.concurrent.Future) Action(ratpack.func.Action) DefaultExecution(ratpack.exec.internal.DefaultExecution) PrematureChannelClosureException(io.netty.handler.codec.PrematureChannelClosureException) ReceivedResponse(ratpack.core.http.client.ReceivedResponse) URI(java.net.URI) PrematureChannelClosureException(io.netty.handler.codec.PrematureChannelClosureException) URISyntaxException(java.net.URISyntaxException) HttpClientReadTimeoutException(ratpack.core.http.client.HttpClientReadTimeoutException) ReadTimeoutException(io.netty.handler.timeout.ReadTimeoutException) SSLException(javax.net.ssl.SSLException) Function(ratpack.func.Function) ReadTimeoutHandler(io.netty.handler.timeout.ReadTimeoutHandler) Future(io.netty.util.concurrent.Future) RequestSpec(ratpack.core.http.client.RequestSpec)

Example 2 with ReceivedResponse

use of ratpack.core.http.client.ReceivedResponse in project ratpack by ratpack.

the class ContentAggregatingRequestAction method addResponseHandlers.

@Override
protected void addResponseHandlers(ChannelPipeline p, Downstream<? super ReceivedResponse> downstream) {
    p.addLast(AGGREGATOR_HANDLER_NAME, new NoContentLengthOnNoBodyHttpObjectAggregator(requestConfig.maxContentLength));
    p.addLast(RESPONSE_HANDLER_NAME, new SimpleChannelInboundHandler<FullHttpResponse>(false) {

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) throws Exception {
            response.touch();
            dispose(ctx.pipeline(), response).addListener(future -> {
                if (future.isSuccess()) {
                    ByteBuf content = new ByteBufRef(response.content());
                    execution.onComplete(() -> {
                        if (content.refCnt() > 0) {
                            content.release();
                        }
                    });
                    downstream.success(toReceivedResponse(response, content));
                } else {
                    downstream.error(future.cause());
                }
            });
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            Throwable decorated = decorateException(cause);
            forceDispose(ctx.pipeline()).addListener(future -> {
                if (!future.isSuccess()) {
                    decorated.addSuppressed(future.cause());
                }
                downstream.error(decorated);
            });
        }
    });
}
Also used : Downstream(ratpack.exec.Downstream) Execution(ratpack.exec.Execution) ChannelPipeline(io.netty.channel.ChannelPipeline) Upstream(ratpack.exec.Upstream) ReceivedResponse(ratpack.core.http.client.ReceivedResponse) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) RequestSpec(ratpack.core.http.client.RequestSpec) ByteBuf(io.netty.buffer.ByteBuf) SimpleChannelInboundHandler(io.netty.channel.SimpleChannelInboundHandler) Action(ratpack.func.Action) ByteBufRef(ratpack.core.bytebuf.ByteBufRef) URI(java.net.URI) Future(io.netty.util.concurrent.Future) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ByteBuf(io.netty.buffer.ByteBuf) ByteBufRef(ratpack.core.bytebuf.ByteBufRef)

Example 3 with ReceivedResponse

use of ratpack.core.http.client.ReceivedResponse in project ratpack by ratpack.

the class BlockingHttpClient method request.

public ReceivedResponse request(HttpClient httpClient, URI uri, ExecController execController, Duration timeout, Action<? super RequestSpec> action) throws Throwable {
    CountDownLatch latch = new CountDownLatch(1);
    AtomicReference<ExecResult<ReceivedResponse>> result = new AtomicReference<>();
    execController.fork().start(e -> httpClient.request(uri, action.prepend(s -> s.readTimeout(Duration.ofHours(1)))).map(response -> {
        TypedData responseBody = response.getBody();
        ByteBuf responseBuffer = responseBody.getBuffer();
        ByteBuf heapResponseBodyBuffer = unreleasableBuffer(responseBuffer.isDirect() ? TestByteBufAllocators.LEAKING_UNPOOLED_HEAP.heapBuffer(responseBuffer.readableBytes()).writeBytes(responseBuffer) : responseBuffer.retain());
        return new DefaultReceivedResponse(response.getStatus(), response.getHeaders(), new ByteBufBackedTypedData(heapResponseBodyBuffer, responseBody.getContentType()));
    }).connect(new Downstream<ReceivedResponse>() {

        @Override
        public void success(ReceivedResponse value) {
            result.set(ExecResult.of(Result.success(value)));
            latch.countDown();
        }

        @Override
        public void error(Throwable throwable) {
            result.set(ExecResult.of(Result.error(throwable)));
            latch.countDown();
        }

        @Override
        public void complete() {
            result.set(ExecResult.complete());
            latch.countDown();
        }
    }));
    try {
        if (!latch.await(timeout.toNanos(), TimeUnit.NANOSECONDS)) {
            TemporalUnit unit = timeout.getUnits().get(0);
            throw new IllegalStateException("Request to " + uri + " took more than " + timeout.get(unit) + " " + unit.toString() + " to complete");
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw Exceptions.uncheck(e);
    }
    return result.get().getValueOrThrow();
}
Also used : TypedData(ratpack.core.http.TypedData) ByteBufBackedTypedData(ratpack.core.http.internal.ByteBufBackedTypedData) TemporalUnit(java.time.temporal.TemporalUnit) DefaultReceivedResponse(ratpack.core.http.client.internal.DefaultReceivedResponse) AtomicReference(java.util.concurrent.atomic.AtomicReference) CountDownLatch(java.util.concurrent.CountDownLatch) ByteBuf(io.netty.buffer.ByteBuf) ReceivedResponse(ratpack.core.http.client.ReceivedResponse) DefaultReceivedResponse(ratpack.core.http.client.internal.DefaultReceivedResponse) ByteBufBackedTypedData(ratpack.core.http.internal.ByteBufBackedTypedData) Downstream(ratpack.exec.Downstream) ExecResult(ratpack.exec.ExecResult)

Aggregations

ByteBuf (io.netty.buffer.ByteBuf)3 ReceivedResponse (ratpack.core.http.client.ReceivedResponse)3 Downstream (ratpack.exec.Downstream)3 Future (io.netty.util.concurrent.Future)2 URI (java.net.URI)2 RequestSpec (ratpack.core.http.client.RequestSpec)2 Execution (ratpack.exec.Execution)2 Upstream (ratpack.exec.Upstream)2 Action (ratpack.func.Action)2 HostAndPort (com.google.common.net.HostAndPort)1 Unpooled (io.netty.buffer.Unpooled)1 io.netty.channel (io.netty.channel)1 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)1 ChannelPipeline (io.netty.channel.ChannelPipeline)1 SimpleChannelInboundHandler (io.netty.channel.SimpleChannelInboundHandler)1 ChannelPool (io.netty.channel.pool.ChannelPool)1 PrematureChannelClosureException (io.netty.handler.codec.PrematureChannelClosureException)1 io.netty.handler.codec.http (io.netty.handler.codec.http)1 FullHttpResponse (io.netty.handler.codec.http.FullHttpResponse)1 SslContext (io.netty.handler.ssl.SslContext)1