Search in sources :

Example 1 with HttpStatus

use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.

the class DefaultHttpClient method streamRequestThroughChannel.

private void streamRequestThroughChannel(io.micronaut.http.HttpRequest<?> parentRequest, AtomicReference<io.micronaut.http.HttpRequest> requestWrapper, FluxSink emitter, Channel channel, boolean failOnError) throws HttpPostRequestEncoder.ErrorDataEncoderException {
    io.micronaut.http.HttpRequest<?> finalRequest = requestWrapper.get();
    URI requestURI = finalRequest.getUri();
    NettyRequestWriter requestWriter = prepareRequest(finalRequest, requestURI, emitter, false);
    HttpRequest nettyRequest = requestWriter.getNettyRequest();
    ChannelPipeline pipeline = channel.pipeline();
    pipeline.addLast(ChannelPipelineCustomizer.HANDLER_MICRONAUT_HTTP_RESPONSE_FULL, new SimpleChannelInboundHandlerInstrumented<FullHttpResponse>() {

        final AtomicBoolean received = new AtomicBoolean(false);

        @Override
        public boolean acceptInboundMessage(Object msg) {
            return msg instanceof FullHttpResponse;
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            if (received.compareAndSet(false, true)) {
                emitter.error(cause);
            }
        }

        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
            if (evt instanceof IdleStateEvent && received.compareAndSet(false, true)) {
                // closed to idle ste
                emitter.error(ReadTimeoutException.TIMEOUT_EXCEPTION);
            }
        }

        @Override
        protected void channelReadInstrumented(ChannelHandlerContext ctx, FullHttpResponse msg) {
            if (received.compareAndSet(false, true)) {
                HttpResponseStatus status = msg.status();
                int statusCode = status.code();
                HttpStatus httpStatus;
                try {
                    httpStatus = HttpStatus.valueOf(statusCode);
                } catch (IllegalArgumentException e) {
                    emitter.error(e);
                    return;
                }
                Publisher<HttpContent> bodyPublisher;
                if (msg.content() instanceof EmptyByteBuf) {
                    bodyPublisher = Publishers.empty();
                } else {
                    bodyPublisher = Publishers.just(new DefaultLastHttpContent(msg.content()));
                }
                DefaultStreamedHttpResponse nettyResponse = new DefaultStreamedHttpResponse(msg.protocolVersion(), msg.status(), msg.headers(), bodyPublisher);
                NettyStreamedHttpResponse response = new NettyStreamedHttpResponse(nettyResponse, httpStatus);
                HttpHeaders headers = msg.headers();
                if (log.isTraceEnabled()) {
                    log.trace("HTTP Client Streaming Response Received ({}) for Request: {} {}", msg.status(), nettyRequest.method().name(), nettyRequest.uri());
                    traceHeaders(headers);
                }
                boolean errorStatus = statusCode >= 400;
                if (errorStatus && failOnError) {
                    emitter.error(new HttpClientResponseException(response.getStatus().getReason(), response));
                } else {
                    emitter.next(response);
                    emitter.complete();
                }
            }
        }
    });
    pipeline.addLast(ChannelPipelineCustomizer.HANDLER_MICRONAUT_HTTP_RESPONSE_STREAM, new SimpleChannelInboundHandlerInstrumented<StreamedHttpResponse>() {

        final AtomicBoolean received = new AtomicBoolean(false);

        @Override
        public boolean acceptInboundMessage(Object msg) {
            return msg instanceof StreamedHttpResponse;
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            if (received.compareAndSet(false, true)) {
                emitter.error(cause);
            }
        }

        @Override
        protected void channelReadInstrumented(ChannelHandlerContext ctx, StreamedHttpResponse msg) {
            if (received.compareAndSet(false, true)) {
                HttpResponseStatus status = msg.status();
                int statusCode = status.code();
                HttpStatus httpStatus;
                try {
                    httpStatus = HttpStatus.valueOf(statusCode);
                } catch (IllegalArgumentException e) {
                    emitter.error(e);
                    return;
                }
                NettyStreamedHttpResponse response = new NettyStreamedHttpResponse(msg, httpStatus);
                HttpHeaders headers = msg.headers();
                if (log.isTraceEnabled()) {
                    log.trace("HTTP Client Streaming Response Received ({}) for Request: {} {}", msg.status(), nettyRequest.method().name(), nettyRequest.uri());
                    traceHeaders(headers);
                }
                if (statusCode > 300 && statusCode < 400 && configuration.isFollowRedirects() && headers.contains(HttpHeaderNames.LOCATION)) {
                    String location = headers.get(HttpHeaderNames.LOCATION);
                    Flux<io.micronaut.http.HttpResponse<Object>> redirectedExchange;
                    try {
                        MutableHttpRequest<Object> redirectRequest;
                        if (statusCode == 307) {
                            redirectRequest = io.micronaut.http.HttpRequest.create(finalRequest.getMethod(), location);
                            finalRequest.getBody().ifPresent(redirectRequest::body);
                        } else {
                            redirectRequest = io.micronaut.http.HttpRequest.GET(location);
                        }
                        setRedirectHeaders(nettyRequest, redirectRequest);
                        redirectedExchange = Flux.from(resolveRedirectURI(parentRequest, redirectRequest)).flatMap(uri -> buildStreamExchange(parentRequest, redirectRequest, uri, null));
                        // noinspection SubscriberImplementation
                        redirectedExchange.subscribe(new Subscriber<io.micronaut.http.HttpResponse<Object>>() {

                            Subscription sub;

                            @Override
                            public void onSubscribe(Subscription s) {
                                s.request(1);
                                this.sub = s;
                            }

                            @Override
                            public void onNext(io.micronaut.http.HttpResponse<Object> objectHttpResponse) {
                                emitter.next(objectHttpResponse);
                            }

                            @Override
                            public void onError(Throwable t) {
                                emitter.error(t);
                            }

                            @Override
                            public void onComplete() {
                                emitter.complete();
                            }
                        });
                    } catch (Exception e) {
                        emitter.error(e);
                    }
                } else {
                    boolean errorStatus = statusCode >= 400;
                    if (errorStatus && failOnError) {
                        emitter.error(new HttpClientResponseException(response.getStatus().getReason(), response));
                    } else {
                        emitter.next(response);
                        emitter.complete();
                    }
                }
            }
        }
    });
    if (log.isDebugEnabled()) {
        debugRequest(requestURI, nettyRequest);
    }
    if (log.isTraceEnabled()) {
        traceRequest(requestWrapper.get(), nettyRequest);
    }
    requestWriter.writeAndClose(channel, null, emitter);
}
Also used : NettyHttpHeaders(io.micronaut.http.netty.NettyHttpHeaders) MutableHttpHeaders(io.micronaut.http.MutableHttpHeaders) DefaultStreamedHttpResponse(io.micronaut.http.netty.stream.DefaultStreamedHttpResponse) URI(java.net.URI) Subscriber(org.reactivestreams.Subscriber) JsonSubscriber(io.micronaut.http.netty.stream.JsonSubscriber) Subscription(org.reactivestreams.Subscription) MutableHttpRequest(io.micronaut.http.MutableHttpRequest) AbstractNettyHttpRequest(io.micronaut.http.netty.AbstractNettyHttpRequest) StreamedHttpRequest(io.micronaut.http.netty.stream.StreamedHttpRequest) StreamedHttpResponse(io.micronaut.http.netty.stream.StreamedHttpResponse) DefaultStreamedHttpResponse(io.micronaut.http.netty.stream.DefaultStreamedHttpResponse) EmptyByteBuf(io.netty.buffer.EmptyByteBuf) HttpStatus(io.micronaut.http.HttpStatus) Flux(reactor.core.publisher.Flux) StreamedHttpResponse(io.micronaut.http.netty.stream.StreamedHttpResponse) DefaultStreamedHttpResponse(io.micronaut.http.netty.stream.DefaultStreamedHttpResponse) HttpResponse(io.micronaut.http.HttpResponse) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) Publisher(org.reactivestreams.Publisher) MutableHttpRequest(io.micronaut.http.MutableHttpRequest) NoHostException(io.micronaut.http.client.exceptions.NoHostException) HttpClientResponseException(io.micronaut.http.client.exceptions.HttpClientResponseException) ReadTimeoutException(io.micronaut.http.client.exceptions.ReadTimeoutException) ContentLengthExceededException(io.micronaut.http.client.exceptions.ContentLengthExceededException) MultipartException(io.micronaut.http.multipart.MultipartException) IOException(java.io.IOException) URISyntaxException(java.net.URISyntaxException) TimeoutException(java.util.concurrent.TimeoutException) CodecException(io.micronaut.http.codec.CodecException) TooLongFrameException(io.netty.handler.codec.TooLongFrameException) WebSocketSessionException(io.micronaut.websocket.exceptions.WebSocketSessionException) HttpClientException(io.micronaut.http.client.exceptions.HttpClientException) MalformedURLException(java.net.MalformedURLException) IdleStateEvent(io.netty.handler.timeout.IdleStateEvent) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HttpClientResponseException(io.micronaut.http.client.exceptions.HttpClientResponseException) io.netty.handler.codec.http(io.netty.handler.codec.http)

Example 2 with HttpStatus

use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.

the class RoutingInBoundHandler method createNettyResponse.

@NonNull
private NettyMutableHttpResponse<?> createNettyResponse(HttpResponse<?> message) {
    HttpStatus httpStatus = message.status();
    Object body = message.body();
    io.netty.handler.codec.http.HttpHeaders nettyHeaders = new DefaultHttpHeaders(serverConfiguration.isValidateHeaders());
    message.getHeaders().forEach((BiConsumer<String, List<String>>) nettyHeaders::set);
    return new NettyMutableHttpResponse<>(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(httpStatus.getCode(), httpStatus.getReason()), body instanceof ByteBuf ? body : null, ConversionService.SHARED);
}
Also used : NettyMutableHttpResponse(io.micronaut.http.netty.NettyMutableHttpResponse) HttpStatus(io.micronaut.http.HttpStatus) DefaultHttpHeaders(io.netty.handler.codec.http.DefaultHttpHeaders) ArrayList(java.util.ArrayList) List(java.util.List) ByteBuf(io.netty.buffer.ByteBuf) NonNull(io.micronaut.core.annotation.NonNull)

Example 3 with HttpStatus

use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.

the class HttpConverterRegistrar method register.

@Override
public void register(ConversionService<?> conversionService) {
    conversionService.addConverter(String.class, HttpVersion.class, s -> {
        try {
            return HttpVersion.valueOf(Double.parseDouble(s));
        } catch (NumberFormatException e) {
            return HttpVersion.valueOf(s);
        }
    });
    conversionService.addConverter(Number.class, HttpVersion.class, s -> HttpVersion.valueOf(s.doubleValue()));
    conversionService.addConverter(CharSequence.class, Readable.class, (object, targetType, context) -> {
        String pathStr = object.toString();
        Optional<ResourceLoader> supportingLoader = resourceResolver.getSupportingLoader(pathStr);
        if (!supportingLoader.isPresent()) {
            context.reject(pathStr, new ConfigurationException("No supported resource loader for path [" + pathStr + "]. Prefix the path with a supported prefix such as 'classpath:' or 'file:'"));
            return Optional.empty();
        } else {
            final Optional<URL> resource = resourceResolver.getResource(pathStr);
            if (resource.isPresent()) {
                return Optional.of(Readable.of(resource.get()));
            } else {
                context.reject(object, new ConfigurationException("No resource exists for value: " + object));
                return Optional.empty();
            }
        }
    });
    conversionService.addConverter(CharSequence.class, MediaType.class, (object, targetType, context) -> {
        try {
            return Optional.of(MediaType.of(object));
        } catch (IllegalArgumentException e) {
            context.reject(e);
            return Optional.empty();
        }
    });
    conversionService.addConverter(Number.class, HttpStatus.class, (object, targetType, context) -> {
        try {
            HttpStatus status = HttpStatus.valueOf(object.shortValue());
            return Optional.of(status);
        } catch (IllegalArgumentException e) {
            context.reject(object, e);
            return Optional.empty();
        }
    });
    conversionService.addConverter(CharSequence.class, SocketAddress.class, (object, targetType, context) -> {
        String address = object.toString();
        try {
            URL url = new URL(address);
            int port = url.getPort();
            if (port == -1) {
                port = url.getDefaultPort();
            }
            if (port == -1) {
                context.reject(object, new ConfigurationException("Failed to find a port in the given value"));
                return Optional.empty();
            }
            return Optional.of(InetSocketAddress.createUnresolved(url.getHost(), port));
        } catch (MalformedURLException malformedURLException) {
            String[] parts = object.toString().split(":");
            if (parts.length == 2) {
                try {
                    int port = Integer.parseInt(parts[1]);
                    return Optional.of(InetSocketAddress.createUnresolved(parts[0], port));
                } catch (IllegalArgumentException illegalArgumentException) {
                    context.reject(object, illegalArgumentException);
                    return Optional.empty();
                }
            } else {
                context.reject(object, new ConfigurationException("The address is not in a proper format of IP:PORT or a standard URL"));
                return Optional.empty();
            }
        }
    });
    conversionService.addConverter(CharSequence.class, ProxySelector.class, (object, targetType, context) -> {
        if (object.toString().equals("default")) {
            return Optional.of(ProxySelector.getDefault());
        } else {
            return Optional.empty();
        }
    });
}
Also used : ResourceLoader(io.micronaut.core.io.ResourceLoader) MalformedURLException(java.net.MalformedURLException) ConfigurationException(io.micronaut.context.exceptions.ConfigurationException) HttpStatus(io.micronaut.http.HttpStatus) URL(java.net.URL)

Example 4 with HttpStatus

use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.

the class HealthResultFilter method doFilterOnce.

@Override
protected Publisher<MutableHttpResponse<?>> doFilterOnce(HttpRequest<?> request, ServerFilterChain chain) {
    return Publishers.map(chain.proceed(request), response -> {
        Object body = response.body();
        if (body instanceof HealthResult) {
            HealthResult healthResult = (HealthResult) body;
            HealthStatus status = healthResult.getStatus();
            HttpStatus httpStatus = healthEndpoint.getStatusConfiguration().getHttpMapping().get(status.getName());
            if (httpStatus != null) {
                response.status(httpStatus);
            } else {
                boolean operational = status.getOperational().orElse(true);
                if (!operational) {
                    response.status(HttpStatus.SERVICE_UNAVAILABLE);
                }
            }
        }
        return response;
    });
}
Also used : HttpStatus(io.micronaut.http.HttpStatus) HealthStatus(io.micronaut.health.HealthStatus) HealthResult(io.micronaut.management.health.indicator.HealthResult)

Example 5 with HttpStatus

use of io.micronaut.http.HttpStatus in project micronaut-core by micronaut-projects.

the class ServiceHttpClientFactory method healthCheckStarter.

/**
 * Creates a {@link ApplicationEventListener} that listens to {@link ServerStartupEvent} for each configured HTTP client
 * in order to register a health check if necessary.
 *
 * @param configuration The configuration
 * @param instanceList  The instance list
 * @return The event listener
 */
@EachBean(ServiceHttpClientConfiguration.class)
@Requires(condition = ServiceHttpClientCondition.class)
ApplicationEventListener<ServerStartupEvent> healthCheckStarter(@Parameter ServiceHttpClientConfiguration configuration, @Parameter StaticServiceInstanceList instanceList) {
    if (configuration.isHealthCheck()) {
        return event -> {
            final List<URI> originalURLs = configuration.getUrls();
            Collection<URI> loadBalancedURIs = instanceList.getLoadBalancedURIs();
            final HttpClient httpClient = clientFactory.get().getClient(configuration.getHttpVersion(), configuration.getServiceId(), configuration.getPath().orElse(null));
            final Duration initialDelay = configuration.getHealthCheckInterval();
            Duration delay = configuration.getHealthCheckInterval();
            taskScheduler.scheduleWithFixedDelay(initialDelay, delay, () -> Flux.fromIterable(originalURLs).flatMap(originalURI -> {
                URI healthCheckURI = originalURI.resolve(configuration.getHealthCheckUri());
                return Flux.from(httpClient.exchange(HttpRequest.GET(healthCheckURI))).onErrorResume(throwable -> {
                    if (throwable instanceof HttpClientResponseException) {
                        HttpClientResponseException responseException = (HttpClientResponseException) throwable;
                        return Flux.just((HttpResponse<ByteBuffer>) responseException.getResponse());
                    }
                    return Flux.just(HttpResponse.serverError());
                }).map(response -> Collections.singletonMap(originalURI, response.getStatus()));
            }).subscribe(uriToStatusMap -> {
                Map.Entry<URI, HttpStatus> entry = uriToStatusMap.entrySet().iterator().next();
                URI uri = entry.getKey();
                HttpStatus status = entry.getValue();
                if (status.getCode() >= 300) {
                    loadBalancedURIs.remove(uri);
                } else if (!loadBalancedURIs.contains(uri)) {
                    loadBalancedURIs.add(uri);
                }
            }));
        };
    }
    throw new DisabledBeanException("HTTP Client Health Check not enabled");
}
Also used : ServerStartupEvent(io.micronaut.runtime.server.event.ServerStartupEvent) Parameter(io.micronaut.context.annotation.Parameter) Collection(java.util.Collection) DisabledBeanException(io.micronaut.context.exceptions.DisabledBeanException) StaticServiceInstanceList(io.micronaut.discovery.StaticServiceInstanceList) Internal(io.micronaut.core.annotation.Internal) Flux(reactor.core.publisher.Flux) List(java.util.List) EachBean(io.micronaut.context.annotation.EachBean) Factory(io.micronaut.context.annotation.Factory) HttpStatus(io.micronaut.http.HttpStatus) BeanProvider(io.micronaut.context.BeanProvider) Duration(java.time.Duration) Map(java.util.Map) Requires(io.micronaut.context.annotation.Requires) ByteBuffer(io.micronaut.core.io.buffer.ByteBuffer) HttpResponse(io.micronaut.http.HttpResponse) HttpClientResponseException(io.micronaut.http.client.exceptions.HttpClientResponseException) TaskScheduler(io.micronaut.scheduling.TaskScheduler) HttpRequest(io.micronaut.http.HttpRequest) URI(java.net.URI) ApplicationEventListener(io.micronaut.context.event.ApplicationEventListener) Collections(java.util.Collections) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) HttpClientResponseException(io.micronaut.http.client.exceptions.HttpClientResponseException) HttpStatus(io.micronaut.http.HttpStatus) Collection(java.util.Collection) StaticServiceInstanceList(io.micronaut.discovery.StaticServiceInstanceList) List(java.util.List) Duration(java.time.Duration) URI(java.net.URI) ByteBuffer(io.micronaut.core.io.buffer.ByteBuffer) Map(java.util.Map) DisabledBeanException(io.micronaut.context.exceptions.DisabledBeanException) Requires(io.micronaut.context.annotation.Requires) EachBean(io.micronaut.context.annotation.EachBean)

Aggregations

HttpStatus (io.micronaut.http.HttpStatus)11 HttpResponse (io.micronaut.http.HttpResponse)5 MutableHttpResponse (io.micronaut.http.MutableHttpResponse)5 Flux (reactor.core.publisher.Flux)5 Internal (io.micronaut.core.annotation.Internal)4 NonNull (io.micronaut.core.annotation.NonNull)4 MediaType (io.micronaut.http.MediaType)4 MutableHttpHeaders (io.micronaut.http.MutableHttpHeaders)4 AbstractNettyHttpRequest (io.micronaut.http.netty.AbstractNettyHttpRequest)4 Nullable (io.micronaut.core.annotation.Nullable)3 Publishers (io.micronaut.core.async.publisher.Publishers)3 ByteBuffer (io.micronaut.core.io.buffer.ByteBuffer)3 ReferenceCounted (io.micronaut.core.io.buffer.ReferenceCounted)3 Argument (io.micronaut.core.type.Argument)3 HttpMethod (io.micronaut.http.HttpMethod)3 HttpRequest (io.micronaut.http.HttpRequest)3 ServerRequestContext (io.micronaut.http.context.ServerRequestContext)3 JsonSubscriber (io.micronaut.http.netty.stream.JsonSubscriber)3 StreamedHttpRequest (io.micronaut.http.netty.stream.StreamedHttpRequest)3 MethodBasedRouteMatch (io.micronaut.web.router.MethodBasedRouteMatch)3