Search in sources :

Example 1 with ByteBufferFactory

use of io.micronaut.core.io.buffer.ByteBufferFactory in project micronaut-core by micronaut-projects.

the class DefaultHttpClient method buildNettyRequest.

/**
 * @param request                The request
 * @param requestURI             The URI of the request
 * @param requestContentType     The request content type
 * @param permitsBody            Whether permits body
 * @param bodyType               The body type
 * @param onError                Called when the body publisher encounters an error
 * @param closeChannelAfterWrite Whether to close the channel. For stream requests we don't close the channel until disposed of.
 * @return A {@link NettyRequestWriter}
 * @throws HttpPostRequestEncoder.ErrorDataEncoderException if there is an encoder exception
 */
protected NettyRequestWriter buildNettyRequest(MutableHttpRequest request, URI requestURI, MediaType requestContentType, boolean permitsBody, @Nullable Argument<?> bodyType, Consumer<? super Throwable> onError, boolean closeChannelAfterWrite) throws HttpPostRequestEncoder.ErrorDataEncoderException {
    io.netty.handler.codec.http.HttpRequest nettyRequest;
    HttpPostRequestEncoder postRequestEncoder = null;
    if (permitsBody) {
        Optional body = request.getBody();
        boolean hasBody = body.isPresent();
        if (requestContentType.equals(MediaType.APPLICATION_FORM_URLENCODED_TYPE) && hasBody) {
            Object bodyValue = body.get();
            if (bodyValue instanceof CharSequence) {
                ByteBuf byteBuf = charSequenceToByteBuf((CharSequence) bodyValue, requestContentType);
                request.body(byteBuf);
                nettyRequest = NettyHttpRequestBuilder.toHttpRequest(request);
            } else {
                postRequestEncoder = buildFormDataRequest(request, bodyValue);
                nettyRequest = postRequestEncoder.finalizeRequest();
            }
        } else if (requestContentType.equals(MediaType.MULTIPART_FORM_DATA_TYPE) && hasBody) {
            Object bodyValue = body.get();
            postRequestEncoder = buildMultipartRequest(request, bodyValue);
            nettyRequest = postRequestEncoder.finalizeRequest();
        } else {
            ByteBuf bodyContent = null;
            if (hasBody) {
                Object bodyValue = body.get();
                if (Publishers.isConvertibleToPublisher(bodyValue)) {
                    boolean isSingle = Publishers.isSingle(bodyValue.getClass());
                    Publisher<?> publisher = ConversionService.SHARED.convert(bodyValue, Publisher.class).orElseThrow(() -> new IllegalArgumentException("Unconvertible reactive type: " + bodyValue));
                    Flux<HttpContent> requestBodyPublisher = Flux.from(publisher).map(o -> {
                        if (o instanceof CharSequence) {
                            ByteBuf textChunk = Unpooled.copiedBuffer(((CharSequence) o), requestContentType.getCharset().orElse(StandardCharsets.UTF_8));
                            if (log.isTraceEnabled()) {
                                traceChunk(textChunk);
                            }
                            return new DefaultHttpContent(textChunk);
                        } else if (o instanceof ByteBuf) {
                            ByteBuf byteBuf = (ByteBuf) o;
                            if (log.isTraceEnabled()) {
                                log.trace("Sending Bytes Chunk. Length: {}", byteBuf.readableBytes());
                            }
                            return new DefaultHttpContent(byteBuf);
                        } else if (o instanceof byte[]) {
                            byte[] bodyBytes = (byte[]) o;
                            if (log.isTraceEnabled()) {
                                log.trace("Sending Bytes Chunk. Length: {}", bodyBytes.length);
                            }
                            return new DefaultHttpContent(Unpooled.wrappedBuffer(bodyBytes));
                        } else if (o instanceof ByteBuffer) {
                            ByteBuffer<?> byteBuffer = (ByteBuffer<?>) o;
                            Object nativeBuffer = byteBuffer.asNativeBuffer();
                            if (log.isTraceEnabled()) {
                                log.trace("Sending Bytes Chunk. Length: {}", byteBuffer.readableBytes());
                            }
                            if (nativeBuffer instanceof ByteBuf) {
                                return new DefaultHttpContent((ByteBuf) nativeBuffer);
                            } else {
                                return new DefaultHttpContent(Unpooled.wrappedBuffer(byteBuffer.toByteArray()));
                            }
                        } else if (mediaTypeCodecRegistry != null) {
                            Optional<MediaTypeCodec> registeredCodec = mediaTypeCodecRegistry.findCodec(requestContentType);
                            ByteBuf encoded = registeredCodec.map(codec -> {
                                if (bodyType != null && bodyType.isInstance(o)) {
                                    return codec.encode((Argument<Object>) bodyType, o, byteBufferFactory).asNativeBuffer();
                                } else {
                                    return codec.encode(o, byteBufferFactory).asNativeBuffer();
                                }
                            }).orElse(null);
                            if (encoded != null) {
                                if (log.isTraceEnabled()) {
                                    traceChunk(encoded);
                                }
                                return new DefaultHttpContent(encoded);
                            }
                        }
                        throw new CodecException("Cannot encode value [" + o + "]. No possible encoders found");
                    });
                    if (!isSingle && MediaType.APPLICATION_JSON_TYPE.equals(requestContentType)) {
                        requestBodyPublisher = JsonSubscriber.lift(requestBodyPublisher);
                    }
                    requestBodyPublisher = requestBodyPublisher.doOnError(onError);
                    request.body(requestBodyPublisher);
                    nettyRequest = NettyHttpRequestBuilder.toHttpRequest(request);
                    try {
                        nettyRequest.setUri(requestURI.toURL().getFile());
                    } catch (MalformedURLException e) {
                    // should never happen
                    }
                    return new NettyRequestWriter(requestURI.getScheme(), nettyRequest, null, closeChannelAfterWrite);
                } else if (bodyValue instanceof CharSequence) {
                    bodyContent = charSequenceToByteBuf((CharSequence) bodyValue, requestContentType);
                } else if (mediaTypeCodecRegistry != null) {
                    Optional<MediaTypeCodec> registeredCodec = mediaTypeCodecRegistry.findCodec(requestContentType);
                    bodyContent = registeredCodec.map(codec -> {
                        if (bodyType != null && bodyType.isInstance(bodyValue)) {
                            return codec.encode((Argument<Object>) bodyType, bodyValue, byteBufferFactory).asNativeBuffer();
                        } else {
                            return codec.encode(bodyValue, byteBufferFactory).asNativeBuffer();
                        }
                    }).orElse(null);
                }
                if (bodyContent == null) {
                    bodyContent = ConversionService.SHARED.convert(bodyValue, ByteBuf.class).orElseThrow(() -> new HttpClientException("Body [" + bodyValue + "] cannot be encoded to content type [" + requestContentType + "]. No possible codecs or converters found."));
                }
            }
            request.body(bodyContent);
            try {
                nettyRequest = NettyHttpRequestBuilder.toHttpRequest(request);
            } finally {
                // reset body after encoding request in case of retry
                request.body(body.orElse(null));
            }
        }
    } else {
        nettyRequest = NettyHttpRequestBuilder.toHttpRequest(request);
    }
    try {
        nettyRequest.setUri(requestURI.toURL().getFile());
    } catch (MalformedURLException e) {
    // should never happen
    }
    return new NettyRequestWriter(requestURI.getScheme(), nettyRequest, postRequestEncoder, closeChannelAfterWrite);
}
Also used : AttributeKey(io.netty.util.AttributeKey) OrderUtil(io.micronaut.core.order.OrderUtil) Publishers(io.micronaut.core.async.publisher.Publishers) NoHostException(io.micronaut.http.client.exceptions.NoHostException) Processor(org.reactivestreams.Processor) JacksonDatabindMapper(io.micronaut.jackson.databind.JacksonDatabindMapper) ProxyHttpClient(io.micronaut.http.client.ProxyHttpClient) HttpProxyHandler(io.netty.handler.proxy.HttpProxyHandler) SseClient(io.micronaut.http.client.sse.SseClient) ChunkedWriteHandler(io.netty.handler.stream.ChunkedWriteHandler) HANDLER_IDLE_STATE(io.micronaut.http.netty.channel.ChannelPipelineCustomizer.HANDLER_IDLE_STATE) Internal(io.micronaut.core.annotation.Internal) NettyClientSslBuilder(io.micronaut.http.client.netty.ssl.NettyClientSslBuilder) Proxy(java.net.Proxy) InstantiationUtils(io.micronaut.core.reflect.InstantiationUtils) HttpStatus(io.micronaut.http.HttpStatus) Duration(java.time.Duration) CharsetUtil(io.netty.util.CharsetUtil) HANDLER_HTTP2_SETTINGS(io.micronaut.http.netty.channel.ChannelPipelineCustomizer.HANDLER_HTTP2_SETTINGS) HttpClientResponseException(io.micronaut.http.client.exceptions.HttpClientResponseException) ArgumentUtils(io.micronaut.core.util.ArgumentUtils) WebSocketClientHandshakerFactory(io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory) MapperMediaTypeCodec(io.micronaut.json.codec.MapperMediaTypeCodec) LoadBalancer(io.micronaut.http.client.LoadBalancer) SocketChannel(io.netty.channel.socket.SocketChannel) HttpClientErrorDecoder(io.micronaut.http.client.exceptions.HttpClientErrorDecoder) ResourceResolver(io.micronaut.core.io.ResourceResolver) ByteBufferFactory(io.micronaut.core.io.buffer.ByteBufferFactory) ReadTimeoutException(io.micronaut.http.client.exceptions.ReadTimeoutException) IdleStateEvent(io.netty.handler.timeout.IdleStateEvent) ChannelHealthChecker(io.netty.channel.pool.ChannelHealthChecker) StreamingInboundHttp2ToHttpAdapter(io.micronaut.http.netty.stream.StreamingInboundHttp2ToHttpAdapter) StandardCharsets(java.nio.charset.StandardCharsets) HttpFilterResolver(io.micronaut.http.filter.HttpFilterResolver) ClientFilterResolutionContext(io.micronaut.http.client.filter.ClientFilterResolutionContext) LineBasedFrameDecoder(io.netty.handler.codec.LineBasedFrameDecoder) AbstractChannelPoolHandler(io.netty.channel.pool.AbstractChannelPoolHandler) SslHandler(io.netty.handler.ssl.SslHandler) ReferenceCountUtil(io.netty.util.ReferenceCountUtil) MutableHttpRequest(io.micronaut.http.MutableHttpRequest) NettyWebSocketClientHandler(io.micronaut.http.client.netty.websocket.NettyWebSocketClientHandler) ChannelPoolMap(io.netty.channel.pool.ChannelPoolMap) MultipartDataFactory(io.micronaut.http.client.multipart.MultipartDataFactory) NettyByteBufferFactory(io.micronaut.buffer.netty.NettyByteBufferFactory) java.util(java.util) Disposable(reactor.core.Disposable) WebSocketBean(io.micronaut.websocket.context.WebSocketBean) OnMessage(io.micronaut.websocket.annotation.OnMessage) ContentLengthExceededException(io.micronaut.http.client.exceptions.ContentLengthExceededException) Supplier(java.util.function.Supplier) StreamedHttpResponse(io.micronaut.http.netty.stream.StreamedHttpResponse) NettyThreadFactory(io.micronaut.http.netty.channel.NettyThreadFactory) NettyHttpRequestBuilder(io.micronaut.http.netty.NettyHttpRequestBuilder) DefaultHttpClientConfiguration(io.micronaut.http.client.DefaultHttpClientConfiguration) NettyHttpHeaders(io.micronaut.http.netty.NettyHttpHeaders) Nullable(io.micronaut.core.annotation.Nullable) ByteBuffer(io.micronaut.core.io.buffer.ByteBuffer) JsonStreamMediaTypeCodec(io.micronaut.json.codec.JsonStreamMediaTypeCodec) Argument(io.micronaut.core.type.Argument) MultipartException(io.micronaut.http.multipart.MultipartException) ConversionService(io.micronaut.core.convert.ConversionService) ServerRequestContext(io.micronaut.http.context.ServerRequestContext) NOOP(io.micronaut.scheduling.instrument.InvocationInstrumenter.NOOP) MediaTypeCodecRegistry(io.micronaut.http.codec.MediaTypeCodecRegistry) Attribute(io.netty.util.Attribute) JsonNode(io.micronaut.json.tree.JsonNode) SslContext(io.netty.handler.ssl.SslContext) FileUpload(io.netty.handler.codec.http.multipart.FileUpload) Publisher(org.reactivestreams.Publisher) HttpClientConfiguration(io.micronaut.http.client.HttpClientConfiguration) Mono(reactor.core.publisher.Mono) IOException(java.io.IOException) NettyHttpResponseBuilder(io.micronaut.http.netty.NettyHttpResponseBuilder) File(java.io.File) AbstractNettyHttpRequest(io.micronaut.http.netty.AbstractNettyHttpRequest) SimpleChannelPool(io.netty.channel.pool.SimpleChannelPool) Bootstrap(io.netty.bootstrap.Bootstrap) Flux(reactor.core.publisher.Flux) WebSocketClientCompressionHandler(io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler) DEFAULT_SHUTDOWN_TIMEOUT_MILLISECONDS(io.micronaut.http.client.HttpClientConfiguration.DEFAULT_SHUTDOWN_TIMEOUT_MILLISECONDS) ChannelPipelineCustomizer(io.micronaut.http.netty.channel.ChannelPipelineCustomizer) ChannelPool(io.netty.channel.pool.ChannelPool) Instrumentation(io.micronaut.scheduling.instrument.Instrumentation) WebSocketClient(io.micronaut.websocket.WebSocketClient) Future(io.netty.util.concurrent.Future) DefaultThreadFactory(io.netty.util.concurrent.DefaultThreadFactory) ChannelPipelineListener(io.micronaut.http.netty.channel.ChannelPipelineListener) DefaultStreamedHttpResponse(io.micronaut.http.netty.stream.DefaultStreamedHttpResponse) SocketAddress(java.net.SocketAddress) HttpStreamsClientHandler(io.micronaut.http.netty.stream.HttpStreamsClientHandler) UriTemplate(io.micronaut.http.uri.UriTemplate) io.netty.handler.codec.http2(io.netty.handler.codec.http2) ByteBufAllocator(io.netty.buffer.ByteBufAllocator) URISyntaxException(java.net.URISyntaxException) DEFAULT_SHUTDOWN_QUIET_PERIOD_MILLISECONDS(io.micronaut.http.client.HttpClientConfiguration.DEFAULT_SHUTDOWN_QUIET_PERIOD_MILLISECONDS) ArrayUtils(io.micronaut.core.util.ArrayUtils) LoggerFactory(org.slf4j.LoggerFactory) TimeoutException(java.util.concurrent.TimeoutException) InvocationInstrumenter(io.micronaut.scheduling.instrument.InvocationInstrumenter) InvocationInstrumenterFactory(io.micronaut.scheduling.instrument.InvocationInstrumenterFactory) ClientFilterChain(io.micronaut.http.filter.ClientFilterChain) DefaultHttp2Content(io.micronaut.http.netty.stream.DefaultHttp2Content) Event(io.micronaut.http.sse.Event) Unpooled(io.netty.buffer.Unpooled) FixedChannelPool(io.netty.channel.pool.FixedChannelPool) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) MediaType(io.micronaut.http.MediaType) ReferenceCounted(io.micronaut.core.io.buffer.ReferenceCounted) JsonMapper(io.micronaut.json.JsonMapper) ApplicationProtocolNegotiationHandler(io.netty.handler.ssl.ApplicationProtocolNegotiationHandler) HttpResponse(io.micronaut.http.HttpResponse) ApplicationConfiguration(io.micronaut.runtime.ApplicationConfiguration) URI(java.net.URI) HttpClient(io.micronaut.http.client.HttpClient) HttpDataFactory(io.netty.handler.codec.http.multipart.HttpDataFactory) ThreadFactory(java.util.concurrent.ThreadFactory) RequestBinderRegistry(io.micronaut.http.bind.RequestBinderRegistry) MultipartBody(io.micronaut.http.client.multipart.MultipartBody) JsonMediaTypeCodec(io.micronaut.json.codec.JsonMediaTypeCodec) CodecException(io.micronaut.http.codec.CodecException) ReadTimeoutHandler(io.netty.handler.timeout.ReadTimeoutHandler) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) MutableHttpHeaders(io.micronaut.http.MutableHttpHeaders) TooLongFrameException(io.netty.handler.codec.TooLongFrameException) InterfaceHttpData(io.netty.handler.codec.http.multipart.InterfaceHttpData) InetSocketAddress(java.net.InetSocketAddress) Collectors(java.util.stream.Collectors) NioEventLoopGroup(io.netty.channel.nio.NioEventLoopGroup) StringUtils(io.micronaut.core.util.StringUtils) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) HttpClientFilter(io.micronaut.http.filter.HttpClientFilter) StreamedHttpRequest(io.micronaut.http.netty.stream.StreamedHttpRequest) io.netty.handler.codec.http(io.netty.handler.codec.http) StreamingHttpClient(io.micronaut.http.client.StreamingHttpClient) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) Type(java.net.Proxy.Type) Socks5ProxyHandler(io.netty.handler.proxy.Socks5ProxyHandler) ClientWebSocket(io.micronaut.websocket.annotation.ClientWebSocket) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) ClientServerContextFilter(io.micronaut.http.client.filters.ClientServerContextFilter) LoggingHandler(io.netty.handler.logging.LoggingHandler) UriBuilder(io.micronaut.http.uri.UriBuilder) HttpPostRequestEncoder(io.netty.handler.codec.http.multipart.HttpPostRequestEncoder) FluxSink(reactor.core.publisher.FluxSink) DefaultHttpDataFactory(io.netty.handler.codec.http.multipart.DefaultHttpDataFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HttpClientFilterResolver(io.micronaut.http.filter.HttpClientFilterResolver) Scheduler(reactor.core.scheduler.Scheduler) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) WebSocketBeanRegistry(io.micronaut.websocket.context.WebSocketBeanRegistry) BeanMap(io.micronaut.core.beans.BeanMap) NoopAddressResolverGroup(io.netty.resolver.NoopAddressResolverGroup) WebSocketVersion(io.netty.handler.codec.http.websocketx.WebSocketVersion) BlockingHttpClient(io.micronaut.http.client.BlockingHttpClient) ByteBuf(io.netty.buffer.ByteBuf) Charset(java.nio.charset.Charset) HttpClientException(io.micronaut.http.client.exceptions.HttpClientException) io.netty.channel(io.netty.channel) Schedulers(reactor.core.scheduler.Schedulers) HttpResponseWrapper(io.micronaut.http.HttpResponseWrapper) Subscriber(org.reactivestreams.Subscriber) MediaTypeCodec(io.micronaut.http.codec.MediaTypeCodec) Logger(org.slf4j.Logger) DefaultRequestBinderRegistry(io.micronaut.http.bind.DefaultRequestBinderRegistry) MalformedURLException(java.net.MalformedURLException) AnnotationMetadataResolver(io.micronaut.core.annotation.AnnotationMetadataResolver) GenericFutureListener(io.netty.util.concurrent.GenericFutureListener) ApplicationProtocolNames(io.netty.handler.ssl.ApplicationProtocolNames) DefaultHttpClientFilterResolver(io.micronaut.http.client.filter.DefaultHttpClientFilterResolver) Http2Content(io.micronaut.http.netty.stream.Http2Content) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) NonNull(io.micronaut.core.annotation.NonNull) IdleStateHandler(io.netty.handler.timeout.IdleStateHandler) ByteBufUtil(io.netty.buffer.ByteBufUtil) EmptyByteBuf(io.netty.buffer.EmptyByteBuf) CollectionUtils(io.micronaut.core.util.CollectionUtils) Subscription(org.reactivestreams.Subscription) Closeable(java.io.Closeable) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) AbstractChannelPoolMap(io.netty.channel.pool.AbstractChannelPoolMap) JsonSubscriber(io.micronaut.http.netty.stream.JsonSubscriber) InputStream(java.io.InputStream) MalformedURLException(java.net.MalformedURLException) Argument(io.micronaut.core.type.Argument) HttpPostRequestEncoder(io.netty.handler.codec.http.multipart.HttpPostRequestEncoder) Flux(reactor.core.publisher.Flux) Publisher(org.reactivestreams.Publisher) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) ByteBuf(io.netty.buffer.ByteBuf) EmptyByteBuf(io.netty.buffer.EmptyByteBuf) ByteBuffer(io.micronaut.core.io.buffer.ByteBuffer) HttpClientException(io.micronaut.http.client.exceptions.HttpClientException) io.netty.handler.codec.http(io.netty.handler.codec.http) CodecException(io.micronaut.http.codec.CodecException)

Example 2 with ByteBufferFactory

use of io.micronaut.core.io.buffer.ByteBufferFactory in project micronaut-core by micronaut-projects.

the class DefaultHttpClient method addFullHttpResponseHandler.

@SuppressWarnings("MagicNumber")
private <O, E> void addFullHttpResponseHandler(io.micronaut.http.HttpRequest<?> request, Channel channel, boolean secure, ChannelPool channelPool, FluxSink<io.micronaut.http.HttpResponse<O>> emitter, Argument<O> bodyType, Argument<E> errorType) {
    ChannelPipeline pipeline = channel.pipeline();
    final SimpleChannelInboundHandler<FullHttpResponse> newHandler = new SimpleChannelInboundHandlerInstrumented<FullHttpResponse>(false) {

        AtomicBoolean complete = new AtomicBoolean(false);

        boolean keepAlive = true;

        @Override
        public boolean acceptInboundMessage(Object msg) {
            return msg instanceof FullHttpResponse && (secure || !discardH2cStream((HttpMessage) msg));
        }

        @Override
        protected void channelReadInstrumented(ChannelHandlerContext channelHandlerContext, FullHttpResponse fullResponse) {
            try {
                HttpResponseStatus status = fullResponse.status();
                int statusCode = status.code();
                HttpStatus httpStatus;
                try {
                    httpStatus = HttpStatus.valueOf(statusCode);
                } catch (IllegalArgumentException e) {
                    if (complete.compareAndSet(false, true)) {
                        if (!emitter.isCancelled()) {
                            emitter.error(e);
                        }
                    } else if (log.isWarnEnabled()) {
                        log.warn("Unsupported http status after handler completed: " + e.getMessage(), e);
                    }
                    return;
                }
                try {
                    HttpHeaders headers = fullResponse.headers();
                    if (log.isDebugEnabled()) {
                        log.debug("Received response {} from {}", status.code(), request.getUri());
                    }
                    if (log.isTraceEnabled()) {
                        traceHeaders(headers);
                        traceBody("Response", fullResponse.content());
                    }
                    // it is a redirect
                    if (statusCode > 300 && statusCode < 400 && configuration.isFollowRedirects() && headers.contains(HttpHeaderNames.LOCATION)) {
                        String location = headers.get(HttpHeaderNames.LOCATION);
                        final MutableHttpRequest<Object> redirectRequest;
                        if (statusCode == 307) {
                            redirectRequest = io.micronaut.http.HttpRequest.create(request.getMethod(), location);
                            request.getBody().ifPresent(redirectRequest::body);
                        } else {
                            redirectRequest = io.micronaut.http.HttpRequest.GET(location);
                        }
                        setRedirectHeaders(request, redirectRequest);
                        Flux<io.micronaut.http.HttpResponse<O>> redirectExchange = Flux.from(resolveRedirectURI(request, redirectRequest)).switchMap(buildExchangePublisher(request, redirectRequest, bodyType, errorType));
                        redirectExchange.defaultIfEmpty(io.micronaut.http.HttpResponse.notFound()).subscribe(oHttpResponse -> {
                            if (bodyType == null || !bodyType.isVoid()) {
                                emitter.next(oHttpResponse);
                            }
                            emitter.complete();
                        }, throwable -> {
                            if (!emitter.isCancelled()) {
                                emitter.error(throwable);
                            }
                        });
                        return;
                    }
                    if (statusCode == HttpStatus.NO_CONTENT.getCode()) {
                        // normalize the NO_CONTENT header, since http content aggregator adds it even if not present in the response
                        headers.remove(HttpHeaderNames.CONTENT_LENGTH);
                    }
                    boolean convertBodyWithBodyType = statusCode < 400 || (!DefaultHttpClient.this.configuration.isExceptionOnErrorStatus() && bodyType.equalsType(errorType));
                    FullNettyClientHttpResponse<O> response = new FullNettyClientHttpResponse<>(fullResponse, httpStatus, mediaTypeCodecRegistry, byteBufferFactory, bodyType, convertBodyWithBodyType);
                    if (complete.compareAndSet(false, true)) {
                        if (convertBodyWithBodyType) {
                            if (bodyType == null || !bodyType.isVoid()) {
                                emitter.next(response);
                            }
                            response.onComplete();
                            emitter.complete();
                        } else {
                            // error flow
                            try {
                                HttpClientResponseException clientError;
                                if (errorType != null && errorType != HttpClient.DEFAULT_ERROR_TYPE) {
                                    clientError = new HttpClientResponseException(status.reasonPhrase(), null, response, new HttpClientErrorDecoder() {

                                        @Override
                                        public Argument<?> getErrorType(MediaType mediaType) {
                                            return errorType;
                                        }
                                    });
                                } else {
                                    clientError = new HttpClientResponseException(status.reasonPhrase(), response);
                                }
                                try {
                                    if (!emitter.isCancelled()) {
                                        emitter.error(clientError);
                                    }
                                } finally {
                                    response.onComplete();
                                }
                            } catch (Throwable t) {
                                if (t instanceof HttpClientResponseException) {
                                    try {
                                        if (!emitter.isCancelled()) {
                                            emitter.error(t);
                                        }
                                    } finally {
                                        response.onComplete();
                                    }
                                } else {
                                    response.onComplete();
                                    FullNettyClientHttpResponse<Object> errorResponse = new FullNettyClientHttpResponse<>(fullResponse, httpStatus, mediaTypeCodecRegistry, byteBufferFactory, null, false);
                                    errorResponse.onComplete();
                                    HttpClientResponseException clientResponseError = new HttpClientResponseException("Error decoding HTTP error response body: " + t.getMessage(), t, errorResponse, null);
                                    if (!emitter.isCancelled()) {
                                        emitter.error(clientResponseError);
                                    }
                                }
                            }
                        }
                    }
                } catch (Throwable t) {
                    if (complete.compareAndSet(false, true)) {
                        if (t instanceof HttpClientResponseException) {
                            if (!emitter.isCancelled()) {
                                emitter.error(t);
                            }
                        } else {
                            FullNettyClientHttpResponse<Object> response = new FullNettyClientHttpResponse<>(fullResponse, httpStatus, mediaTypeCodecRegistry, byteBufferFactory, null, false);
                            HttpClientResponseException clientResponseError = new HttpClientResponseException("Error decoding HTTP response body: " + t.getMessage(), t, response, new HttpClientErrorDecoder() {

                                @Override
                                public Argument<?> getErrorType(MediaType mediaType) {
                                    return errorType;
                                }
                            });
                            try {
                                if (!emitter.isCancelled()) {
                                    emitter.error(clientResponseError);
                                }
                            } finally {
                                response.onComplete();
                            }
                        }
                    } else {
                        if (log.isWarnEnabled()) {
                            log.warn("Exception fired after handler completed: " + t.getMessage(), t);
                        }
                    }
                }
            } finally {
                if (fullResponse.refCnt() > 0) {
                    try {
                        ReferenceCountUtil.release(fullResponse);
                    } catch (Throwable e) {
                        if (log.isDebugEnabled()) {
                            log.debug("Failed to release response: {}", fullResponse);
                        }
                    }
                }
                if (!HttpUtil.isKeepAlive(fullResponse)) {
                    keepAlive = false;
                }
                pipeline.remove(this);
            }
        }

        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) {
            if (channelPool != null) {
                if (readTimeoutMillis != null) {
                    ctx.pipeline().remove(ChannelPipelineCustomizer.HANDLER_READ_TIMEOUT);
                }
                final Channel ch = ctx.channel();
                if (!keepAlive) {
                    ch.closeFuture().addListener((future -> channelPool.release(ch)));
                } else {
                    channelPool.release(ch);
                }
            } else {
                // just close it to prevent any future reads without a handler registered
                ctx.close();
            }
        }

        @Override
        public void handlerAdded(ChannelHandlerContext ctx) {
            if (readTimeoutMillis != null) {
                if (httpVersion == io.micronaut.http.HttpVersion.HTTP_2_0) {
                    Http2SettingsHandler settingsHandler = (Http2SettingsHandler) ctx.pipeline().get(HANDLER_HTTP2_SETTINGS);
                    if (settingsHandler != null) {
                        addInstrumentedListener(settingsHandler.promise, future -> {
                            if (future.isSuccess()) {
                                pipeline.addBefore(ChannelPipelineCustomizer.HANDLER_HTTP2_CONNECTION, ChannelPipelineCustomizer.HANDLER_READ_TIMEOUT, new ReadTimeoutHandler(readTimeoutMillis, TimeUnit.MILLISECONDS));
                            }
                        });
                    } else {
                        pipeline.addBefore(ChannelPipelineCustomizer.HANDLER_HTTP2_CONNECTION, ChannelPipelineCustomizer.HANDLER_READ_TIMEOUT, new ReadTimeoutHandler(readTimeoutMillis, TimeUnit.MILLISECONDS));
                    }
                } else {
                    pipeline.addBefore(ChannelPipelineCustomizer.HANDLER_HTTP_CLIENT_CODEC, ChannelPipelineCustomizer.HANDLER_READ_TIMEOUT, new ReadTimeoutHandler(readTimeoutMillis, TimeUnit.MILLISECONDS));
                }
            }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            try {
                if (complete.compareAndSet(false, true)) {
                    String message = cause.getMessage();
                    if (message == null) {
                        message = cause.getClass().getSimpleName();
                    }
                    if (log.isTraceEnabled()) {
                        log.trace("HTTP Client exception ({}) occurred for request : {} {}", message, request.getMethodName(), request.getUri());
                    }
                    if (cause instanceof TooLongFrameException) {
                        if (!emitter.isCancelled()) {
                            emitter.error(new ContentLengthExceededException(configuration.getMaxContentLength()));
                        }
                    } else if (cause instanceof io.netty.handler.timeout.ReadTimeoutException) {
                        if (!emitter.isCancelled()) {
                            emitter.error(ReadTimeoutException.TIMEOUT_EXCEPTION);
                        }
                    } else {
                        if (!emitter.isCancelled()) {
                            emitter.error(new HttpClientException("Error occurred reading HTTP response: " + message, cause));
                        }
                    }
                }
            } finally {
                keepAlive = false;
                pipeline.remove(this);
            }
        }
    };
    pipeline.addLast(ChannelPipelineCustomizer.HANDLER_MICRONAUT_FULL_HTTP_RESPONSE, newHandler);
}
Also used : AttributeKey(io.netty.util.AttributeKey) OrderUtil(io.micronaut.core.order.OrderUtil) Publishers(io.micronaut.core.async.publisher.Publishers) NoHostException(io.micronaut.http.client.exceptions.NoHostException) Processor(org.reactivestreams.Processor) JacksonDatabindMapper(io.micronaut.jackson.databind.JacksonDatabindMapper) ProxyHttpClient(io.micronaut.http.client.ProxyHttpClient) HttpProxyHandler(io.netty.handler.proxy.HttpProxyHandler) SseClient(io.micronaut.http.client.sse.SseClient) ChunkedWriteHandler(io.netty.handler.stream.ChunkedWriteHandler) HANDLER_IDLE_STATE(io.micronaut.http.netty.channel.ChannelPipelineCustomizer.HANDLER_IDLE_STATE) Internal(io.micronaut.core.annotation.Internal) NettyClientSslBuilder(io.micronaut.http.client.netty.ssl.NettyClientSslBuilder) Proxy(java.net.Proxy) InstantiationUtils(io.micronaut.core.reflect.InstantiationUtils) HttpStatus(io.micronaut.http.HttpStatus) Duration(java.time.Duration) CharsetUtil(io.netty.util.CharsetUtil) HANDLER_HTTP2_SETTINGS(io.micronaut.http.netty.channel.ChannelPipelineCustomizer.HANDLER_HTTP2_SETTINGS) HttpClientResponseException(io.micronaut.http.client.exceptions.HttpClientResponseException) ArgumentUtils(io.micronaut.core.util.ArgumentUtils) WebSocketClientHandshakerFactory(io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory) MapperMediaTypeCodec(io.micronaut.json.codec.MapperMediaTypeCodec) LoadBalancer(io.micronaut.http.client.LoadBalancer) SocketChannel(io.netty.channel.socket.SocketChannel) HttpClientErrorDecoder(io.micronaut.http.client.exceptions.HttpClientErrorDecoder) ResourceResolver(io.micronaut.core.io.ResourceResolver) ByteBufferFactory(io.micronaut.core.io.buffer.ByteBufferFactory) ReadTimeoutException(io.micronaut.http.client.exceptions.ReadTimeoutException) IdleStateEvent(io.netty.handler.timeout.IdleStateEvent) ChannelHealthChecker(io.netty.channel.pool.ChannelHealthChecker) StreamingInboundHttp2ToHttpAdapter(io.micronaut.http.netty.stream.StreamingInboundHttp2ToHttpAdapter) StandardCharsets(java.nio.charset.StandardCharsets) HttpFilterResolver(io.micronaut.http.filter.HttpFilterResolver) ClientFilterResolutionContext(io.micronaut.http.client.filter.ClientFilterResolutionContext) LineBasedFrameDecoder(io.netty.handler.codec.LineBasedFrameDecoder) AbstractChannelPoolHandler(io.netty.channel.pool.AbstractChannelPoolHandler) SslHandler(io.netty.handler.ssl.SslHandler) ReferenceCountUtil(io.netty.util.ReferenceCountUtil) MutableHttpRequest(io.micronaut.http.MutableHttpRequest) NettyWebSocketClientHandler(io.micronaut.http.client.netty.websocket.NettyWebSocketClientHandler) ChannelPoolMap(io.netty.channel.pool.ChannelPoolMap) MultipartDataFactory(io.micronaut.http.client.multipart.MultipartDataFactory) NettyByteBufferFactory(io.micronaut.buffer.netty.NettyByteBufferFactory) java.util(java.util) Disposable(reactor.core.Disposable) WebSocketBean(io.micronaut.websocket.context.WebSocketBean) OnMessage(io.micronaut.websocket.annotation.OnMessage) ContentLengthExceededException(io.micronaut.http.client.exceptions.ContentLengthExceededException) Supplier(java.util.function.Supplier) StreamedHttpResponse(io.micronaut.http.netty.stream.StreamedHttpResponse) NettyThreadFactory(io.micronaut.http.netty.channel.NettyThreadFactory) NettyHttpRequestBuilder(io.micronaut.http.netty.NettyHttpRequestBuilder) DefaultHttpClientConfiguration(io.micronaut.http.client.DefaultHttpClientConfiguration) NettyHttpHeaders(io.micronaut.http.netty.NettyHttpHeaders) Nullable(io.micronaut.core.annotation.Nullable) ByteBuffer(io.micronaut.core.io.buffer.ByteBuffer) JsonStreamMediaTypeCodec(io.micronaut.json.codec.JsonStreamMediaTypeCodec) Argument(io.micronaut.core.type.Argument) MultipartException(io.micronaut.http.multipart.MultipartException) ConversionService(io.micronaut.core.convert.ConversionService) ServerRequestContext(io.micronaut.http.context.ServerRequestContext) NOOP(io.micronaut.scheduling.instrument.InvocationInstrumenter.NOOP) MediaTypeCodecRegistry(io.micronaut.http.codec.MediaTypeCodecRegistry) Attribute(io.netty.util.Attribute) JsonNode(io.micronaut.json.tree.JsonNode) SslContext(io.netty.handler.ssl.SslContext) FileUpload(io.netty.handler.codec.http.multipart.FileUpload) Publisher(org.reactivestreams.Publisher) HttpClientConfiguration(io.micronaut.http.client.HttpClientConfiguration) Mono(reactor.core.publisher.Mono) IOException(java.io.IOException) NettyHttpResponseBuilder(io.micronaut.http.netty.NettyHttpResponseBuilder) File(java.io.File) AbstractNettyHttpRequest(io.micronaut.http.netty.AbstractNettyHttpRequest) SimpleChannelPool(io.netty.channel.pool.SimpleChannelPool) Bootstrap(io.netty.bootstrap.Bootstrap) Flux(reactor.core.publisher.Flux) WebSocketClientCompressionHandler(io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler) DEFAULT_SHUTDOWN_TIMEOUT_MILLISECONDS(io.micronaut.http.client.HttpClientConfiguration.DEFAULT_SHUTDOWN_TIMEOUT_MILLISECONDS) ChannelPipelineCustomizer(io.micronaut.http.netty.channel.ChannelPipelineCustomizer) ChannelPool(io.netty.channel.pool.ChannelPool) Instrumentation(io.micronaut.scheduling.instrument.Instrumentation) WebSocketClient(io.micronaut.websocket.WebSocketClient) Future(io.netty.util.concurrent.Future) DefaultThreadFactory(io.netty.util.concurrent.DefaultThreadFactory) ChannelPipelineListener(io.micronaut.http.netty.channel.ChannelPipelineListener) DefaultStreamedHttpResponse(io.micronaut.http.netty.stream.DefaultStreamedHttpResponse) SocketAddress(java.net.SocketAddress) HttpStreamsClientHandler(io.micronaut.http.netty.stream.HttpStreamsClientHandler) UriTemplate(io.micronaut.http.uri.UriTemplate) io.netty.handler.codec.http2(io.netty.handler.codec.http2) ByteBufAllocator(io.netty.buffer.ByteBufAllocator) URISyntaxException(java.net.URISyntaxException) DEFAULT_SHUTDOWN_QUIET_PERIOD_MILLISECONDS(io.micronaut.http.client.HttpClientConfiguration.DEFAULT_SHUTDOWN_QUIET_PERIOD_MILLISECONDS) ArrayUtils(io.micronaut.core.util.ArrayUtils) LoggerFactory(org.slf4j.LoggerFactory) TimeoutException(java.util.concurrent.TimeoutException) InvocationInstrumenter(io.micronaut.scheduling.instrument.InvocationInstrumenter) InvocationInstrumenterFactory(io.micronaut.scheduling.instrument.InvocationInstrumenterFactory) ClientFilterChain(io.micronaut.http.filter.ClientFilterChain) DefaultHttp2Content(io.micronaut.http.netty.stream.DefaultHttp2Content) Event(io.micronaut.http.sse.Event) Unpooled(io.netty.buffer.Unpooled) FixedChannelPool(io.netty.channel.pool.FixedChannelPool) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) MediaType(io.micronaut.http.MediaType) ReferenceCounted(io.micronaut.core.io.buffer.ReferenceCounted) JsonMapper(io.micronaut.json.JsonMapper) ApplicationProtocolNegotiationHandler(io.netty.handler.ssl.ApplicationProtocolNegotiationHandler) HttpResponse(io.micronaut.http.HttpResponse) ApplicationConfiguration(io.micronaut.runtime.ApplicationConfiguration) URI(java.net.URI) HttpClient(io.micronaut.http.client.HttpClient) HttpDataFactory(io.netty.handler.codec.http.multipart.HttpDataFactory) ThreadFactory(java.util.concurrent.ThreadFactory) RequestBinderRegistry(io.micronaut.http.bind.RequestBinderRegistry) MultipartBody(io.micronaut.http.client.multipart.MultipartBody) JsonMediaTypeCodec(io.micronaut.json.codec.JsonMediaTypeCodec) CodecException(io.micronaut.http.codec.CodecException) ReadTimeoutHandler(io.netty.handler.timeout.ReadTimeoutHandler) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) MutableHttpHeaders(io.micronaut.http.MutableHttpHeaders) TooLongFrameException(io.netty.handler.codec.TooLongFrameException) InterfaceHttpData(io.netty.handler.codec.http.multipart.InterfaceHttpData) InetSocketAddress(java.net.InetSocketAddress) Collectors(java.util.stream.Collectors) NioEventLoopGroup(io.netty.channel.nio.NioEventLoopGroup) StringUtils(io.micronaut.core.util.StringUtils) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) HttpClientFilter(io.micronaut.http.filter.HttpClientFilter) StreamedHttpRequest(io.micronaut.http.netty.stream.StreamedHttpRequest) io.netty.handler.codec.http(io.netty.handler.codec.http) StreamingHttpClient(io.micronaut.http.client.StreamingHttpClient) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) Type(java.net.Proxy.Type) Socks5ProxyHandler(io.netty.handler.proxy.Socks5ProxyHandler) ClientWebSocket(io.micronaut.websocket.annotation.ClientWebSocket) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) ClientServerContextFilter(io.micronaut.http.client.filters.ClientServerContextFilter) LoggingHandler(io.netty.handler.logging.LoggingHandler) UriBuilder(io.micronaut.http.uri.UriBuilder) HttpPostRequestEncoder(io.netty.handler.codec.http.multipart.HttpPostRequestEncoder) FluxSink(reactor.core.publisher.FluxSink) DefaultHttpDataFactory(io.netty.handler.codec.http.multipart.DefaultHttpDataFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HttpClientFilterResolver(io.micronaut.http.filter.HttpClientFilterResolver) Scheduler(reactor.core.scheduler.Scheduler) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) WebSocketBeanRegistry(io.micronaut.websocket.context.WebSocketBeanRegistry) BeanMap(io.micronaut.core.beans.BeanMap) NoopAddressResolverGroup(io.netty.resolver.NoopAddressResolverGroup) WebSocketVersion(io.netty.handler.codec.http.websocketx.WebSocketVersion) BlockingHttpClient(io.micronaut.http.client.BlockingHttpClient) ByteBuf(io.netty.buffer.ByteBuf) Charset(java.nio.charset.Charset) HttpClientException(io.micronaut.http.client.exceptions.HttpClientException) io.netty.channel(io.netty.channel) Schedulers(reactor.core.scheduler.Schedulers) HttpResponseWrapper(io.micronaut.http.HttpResponseWrapper) Subscriber(org.reactivestreams.Subscriber) MediaTypeCodec(io.micronaut.http.codec.MediaTypeCodec) Logger(org.slf4j.Logger) DefaultRequestBinderRegistry(io.micronaut.http.bind.DefaultRequestBinderRegistry) MalformedURLException(java.net.MalformedURLException) AnnotationMetadataResolver(io.micronaut.core.annotation.AnnotationMetadataResolver) GenericFutureListener(io.netty.util.concurrent.GenericFutureListener) ApplicationProtocolNames(io.netty.handler.ssl.ApplicationProtocolNames) DefaultHttpClientFilterResolver(io.micronaut.http.client.filter.DefaultHttpClientFilterResolver) Http2Content(io.micronaut.http.netty.stream.Http2Content) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) NonNull(io.micronaut.core.annotation.NonNull) IdleStateHandler(io.netty.handler.timeout.IdleStateHandler) ByteBufUtil(io.netty.buffer.ByteBufUtil) EmptyByteBuf(io.netty.buffer.EmptyByteBuf) CollectionUtils(io.micronaut.core.util.CollectionUtils) Subscription(org.reactivestreams.Subscription) Closeable(java.io.Closeable) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) AbstractChannelPoolMap(io.netty.channel.pool.AbstractChannelPoolMap) JsonSubscriber(io.micronaut.http.netty.stream.JsonSubscriber) InputStream(java.io.InputStream) NettyHttpHeaders(io.micronaut.http.netty.NettyHttpHeaders) MutableHttpHeaders(io.micronaut.http.MutableHttpHeaders) TooLongFrameException(io.netty.handler.codec.TooLongFrameException) HttpClientException(io.micronaut.http.client.exceptions.HttpClientException) MediaType(io.micronaut.http.MediaType) HttpStatus(io.micronaut.http.HttpStatus) SocketChannel(io.netty.channel.socket.SocketChannel) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) StreamedHttpResponse(io.micronaut.http.netty.stream.StreamedHttpResponse) DefaultStreamedHttpResponse(io.micronaut.http.netty.stream.DefaultStreamedHttpResponse) HttpResponse(io.micronaut.http.HttpResponse) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HttpClientResponseException(io.micronaut.http.client.exceptions.HttpClientResponseException) HttpClientErrorDecoder(io.micronaut.http.client.exceptions.HttpClientErrorDecoder) ReadTimeoutHandler(io.netty.handler.timeout.ReadTimeoutHandler) ContentLengthExceededException(io.micronaut.http.client.exceptions.ContentLengthExceededException)

Aggregations

NettyByteBufferFactory (io.micronaut.buffer.netty.NettyByteBufferFactory)2 AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)2 AnnotationMetadataResolver (io.micronaut.core.annotation.AnnotationMetadataResolver)2 Internal (io.micronaut.core.annotation.Internal)2 NonNull (io.micronaut.core.annotation.NonNull)2 Nullable (io.micronaut.core.annotation.Nullable)2 Publishers (io.micronaut.core.async.publisher.Publishers)2 BeanMap (io.micronaut.core.beans.BeanMap)2 ConversionService (io.micronaut.core.convert.ConversionService)2 ResourceResolver (io.micronaut.core.io.ResourceResolver)2 ByteBuffer (io.micronaut.core.io.buffer.ByteBuffer)2 ByteBufferFactory (io.micronaut.core.io.buffer.ByteBufferFactory)2 ReferenceCounted (io.micronaut.core.io.buffer.ReferenceCounted)2 OrderUtil (io.micronaut.core.order.OrderUtil)2 InstantiationUtils (io.micronaut.core.reflect.InstantiationUtils)2 Argument (io.micronaut.core.type.Argument)2 ArgumentUtils (io.micronaut.core.util.ArgumentUtils)2 ArrayUtils (io.micronaut.core.util.ArrayUtils)2 CollectionUtils (io.micronaut.core.util.CollectionUtils)2 StringUtils (io.micronaut.core.util.StringUtils)2