Search in sources :

Example 1 with RECEIVED

use of io.helidon.webclient.WebClientRequestBuilderImpl.RECEIVED in project helidon by oracle.

the class NettyClientHandler method channelRead0.

@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws IOException {
    Channel channel = ctx.channel();
    if (msg instanceof HttpResponse) {
        channel.config().setAutoRead(false);
        HttpResponse response = (HttpResponse) msg;
        this.requestId = channel.attr(REQUEST_ID).get();
        channel.attr(RESPONSE_RECEIVED).set(true);
        WebClientRequestImpl clientRequest = channel.attr(REQUEST).get();
        RequestConfiguration requestConfiguration = clientRequest.configuration();
        LOGGER.finest(() -> "(client reqID: " + requestId + ") Initial http response message received");
        this.publisher = new HttpResponsePublisher(ctx);
        channel.attr(PUBLISHER).set(this.publisher);
        this.responseCloser = new ResponseCloser(ctx);
        WebClientResponseImpl.Builder responseBuilder = WebClientResponseImpl.builder();
        responseBuilder.contentPublisher(publisher).readerContext(requestConfiguration.readerContext()).status(helidonStatus(response.status())).httpVersion(Http.Version.create(response.protocolVersion().toString())).responseCloser(responseCloser).lastEndpointURI(requestConfiguration.requestURI());
        HttpHeaders nettyHeaders = response.headers();
        for (String name : nettyHeaders.names()) {
            List<String> values = nettyHeaders.getAll(name);
            responseBuilder.addHeader(name, values);
        }
        String connection = nettyHeaders.get(Http.Header.CONNECTION, HttpHeaderValues.CLOSE.toString());
        if (connection.equals(HttpHeaderValues.CLOSE.toString())) {
            ctx.channel().attr(WILL_CLOSE).set(true);
        }
        // we got a response, we can safely complete the future
        // all errors are now fed only to the publisher
        WebClientResponse clientResponse = responseBuilder.build();
        channel.attr(RESPONSE).set(clientResponse);
        for (HttpInterceptor interceptor : HTTP_INTERCEPTORS) {
            if (interceptor.shouldIntercept(response.status(), requestConfiguration)) {
                boolean continueAfter = !interceptor.continueAfterInterception();
                if (continueAfter) {
                    responseCloser.close().thenAccept(future -> LOGGER.finest(() -> "Response closed due to redirection"));
                }
                interceptor.handleInterception(response, clientRequest, channel.attr(RESULT).get());
                if (continueAfter) {
                    return;
                }
            }
        }
        requestConfiguration.cookieManager().put(requestConfiguration.requestURI(), clientResponse.headers().toMap());
        WebClientServiceResponse clientServiceResponse = new WebClientServiceResponseImpl(requestConfiguration.context().get(), clientResponse.headers(), clientResponse.status());
        channel.attr(SERVICE_RESPONSE).set(clientServiceResponse);
        List<WebClientService> services = requestConfiguration.services();
        CompletionStage<WebClientServiceResponse> csr = CompletableFuture.completedFuture(clientServiceResponse);
        for (WebClientService service : services) {
            csr = csr.thenCompose(clientSerResponse -> service.response(clientRequest, clientSerResponse));
        }
        CompletableFuture<WebClientServiceResponse> responseReceived = channel.attr(RECEIVED).get();
        CompletableFuture<WebClientResponse> responseFuture = channel.attr(RESULT).get();
        csr.whenComplete((clientSerResponse, throwable) -> {
            if (throwable != null) {
                responseReceived.completeExceptionally(throwable);
                responseFuture.completeExceptionally(throwable);
                responseCloser.close();
            } else {
                responseReceived.complete(clientServiceResponse);
                responseReceived.thenRun(() -> {
                    if (shouldResponseAutomaticallyClose(clientResponse)) {
                        responseCloser.close().thenAccept(aVoid -> {
                            LOGGER.finest(() -> "Response automatically closed. No entity expected");
                        });
                    }
                    responseFuture.complete(clientResponse);
                });
            }
        });
    }
    if (responseCloser.isClosed()) {
        if (!channel.attr(WILL_CLOSE).get() && channel.hasAttr(RETURN)) {
            if (msg instanceof LastHttpContent) {
                LOGGER.finest(() -> "(client reqID: " + requestId + ") Draining finished");
                if (channel.isActive()) {
                    channel.attr(RETURN).get().set(true);
                }
            } else {
                LOGGER.finest(() -> "(client reqID: " + requestId + ") Draining not finished, requesting new chunk");
            }
            channel.read();
        }
        return;
    }
    // never "else-if" - msg may be an instance of more than one type, we must process all of them
    if (msg instanceof HttpContent) {
        HttpContent content = (HttpContent) msg;
        publisher.emit(content.content());
    }
    if (msg instanceof LastHttpContent) {
        LOGGER.finest(() -> "(client reqID: " + requestId + ") Last http content received");
        if (channel.hasAttr(RETURN)) {
            channel.attr(RETURN).get().set(true);
            responseCloser.close();
            channel.read();
        } else {
            responseCloser.close();
        }
    }
}
Also used : BufferedEmittingPublisher(io.helidon.common.reactive.BufferedEmittingPublisher) AttributeKey(io.netty.util.AttributeKey) HttpHeaders(io.netty.handler.codec.http.HttpHeaders) COMPLETED(io.helidon.webclient.WebClientRequestBuilderImpl.COMPLETED) RECEIVED(io.helidon.webclient.WebClientRequestBuilderImpl.RECEIVED) DataChunk(io.helidon.common.http.DataChunk) RESULT(io.helidon.webclient.WebClientRequestBuilderImpl.RESULT) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) ReentrantReadWriteLock(java.util.concurrent.locks.ReentrantReadWriteLock) HttpObject(io.netty.handler.codec.http.HttpObject) ArrayList(java.util.ArrayList) Level(java.util.logging.Level) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) RESPONSE(io.helidon.webclient.WebClientRequestBuilderImpl.RESPONSE) ByteBuf(io.netty.buffer.ByteBuf) Single(io.helidon.common.reactive.Single) Http(io.helidon.common.http.Http) REQUEST(io.helidon.webclient.WebClientRequestBuilderImpl.REQUEST) HttpContent(io.netty.handler.codec.http.HttpContent) WILL_CLOSE(io.helidon.webclient.WebClientRequestBuilderImpl.WILL_CLOSE) WebClientService(io.helidon.webclient.spi.WebClientService) HttpHeaderValues(io.netty.handler.codec.http.HttpHeaderValues) REQUEST_ID(io.helidon.webclient.WebClientRequestBuilderImpl.REQUEST_ID) IOException(java.io.IOException) HttpResponseStatus(io.netty.handler.codec.http.HttpResponseStatus) Logger(java.util.logging.Logger) Channel(io.netty.channel.Channel) IN_USE(io.helidon.webclient.WebClientRequestBuilderImpl.IN_USE) List(java.util.List) CompletionStage(java.util.concurrent.CompletionStage) SimpleChannelInboundHandler(io.netty.channel.SimpleChannelInboundHandler) HttpResponse(io.netty.handler.codec.http.HttpResponse) RETURN(io.helidon.webclient.WebClientRequestBuilderImpl.RETURN) RESPONSE_RECEIVED(io.helidon.webclient.WebClientRequestBuilderImpl.RESPONSE_RECEIVED) HttpHeaders(io.netty.handler.codec.http.HttpHeaders) Channel(io.netty.channel.Channel) HttpResponse(io.netty.handler.codec.http.HttpResponse) WebClientService(io.helidon.webclient.spi.WebClientService) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) HttpContent(io.netty.handler.codec.http.HttpContent)

Aggregations

DataChunk (io.helidon.common.http.DataChunk)1 Http (io.helidon.common.http.Http)1 BufferedEmittingPublisher (io.helidon.common.reactive.BufferedEmittingPublisher)1 Single (io.helidon.common.reactive.Single)1 COMPLETED (io.helidon.webclient.WebClientRequestBuilderImpl.COMPLETED)1 IN_USE (io.helidon.webclient.WebClientRequestBuilderImpl.IN_USE)1 RECEIVED (io.helidon.webclient.WebClientRequestBuilderImpl.RECEIVED)1 REQUEST (io.helidon.webclient.WebClientRequestBuilderImpl.REQUEST)1 REQUEST_ID (io.helidon.webclient.WebClientRequestBuilderImpl.REQUEST_ID)1 RESPONSE (io.helidon.webclient.WebClientRequestBuilderImpl.RESPONSE)1 RESPONSE_RECEIVED (io.helidon.webclient.WebClientRequestBuilderImpl.RESPONSE_RECEIVED)1 RESULT (io.helidon.webclient.WebClientRequestBuilderImpl.RESULT)1 RETURN (io.helidon.webclient.WebClientRequestBuilderImpl.RETURN)1 WILL_CLOSE (io.helidon.webclient.WebClientRequestBuilderImpl.WILL_CLOSE)1 WebClientService (io.helidon.webclient.spi.WebClientService)1 ByteBuf (io.netty.buffer.ByteBuf)1 Channel (io.netty.channel.Channel)1 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)1 SimpleChannelInboundHandler (io.netty.channel.SimpleChannelInboundHandler)1 HttpContent (io.netty.handler.codec.http.HttpContent)1