Search in sources :

Example 6 with HttpStatus

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

the class RouteExecutor method createResponseForBody.

private Flux<MutableHttpResponse<?>> createResponseForBody(HttpRequest<?> request, Object body, RouteInfo<?> routeInfo) {
    return Flux.<MutableHttpResponse<?>>defer(() -> {
        Mono<MutableHttpResponse<?>> outgoingResponse;
        if (body == null) {
            if (routeInfo.isVoid()) {
                MutableHttpResponse<Object> data = forStatus(routeInfo);
                if (HttpMethod.permitsRequestBody(request.getMethod())) {
                    data.header(HttpHeaders.CONTENT_LENGTH, "0");
                }
                outgoingResponse = Mono.just(data);
            } else {
                outgoingResponse = Mono.just(newNotFoundError(request));
            }
        } else {
            HttpStatus defaultHttpStatus = routeInfo.isErrorRoute() ? HttpStatus.INTERNAL_SERVER_ERROR : HttpStatus.OK;
            boolean isReactive = routeInfo.isAsyncOrReactive() || Publishers.isConvertibleToPublisher(body);
            if (isReactive) {
                Class<?> bodyClass = body.getClass();
                boolean isSingle = isSingle(routeInfo, bodyClass);
                boolean isCompletable = !isSingle && routeInfo.isVoid() && Publishers.isCompletable(bodyClass);
                if (isSingle || isCompletable) {
                    // full response case
                    Publisher<Object> publisher = Publishers.convertPublisher(body, Publisher.class);
                    Supplier<MutableHttpResponse<?>> emptyResponse = () -> {
                        MutableHttpResponse<?> singleResponse;
                        if (isCompletable || routeInfo.isVoid()) {
                            singleResponse = forStatus(routeInfo, HttpStatus.OK).header(HttpHeaders.CONTENT_LENGTH, "0");
                        } else {
                            singleResponse = newNotFoundError(request);
                        }
                        return singleResponse;
                    };
                    return Flux.from(publisher).flatMap(o -> {
                        MutableHttpResponse<?> singleResponse;
                        if (o instanceof Optional) {
                            Optional optional = (Optional) o;
                            if (optional.isPresent()) {
                                o = ((Optional<?>) o).get();
                            } else {
                                return Flux.just(emptyResponse.get());
                            }
                        }
                        if (o instanceof HttpResponse) {
                            singleResponse = toMutableResponse((HttpResponse<?>) o);
                            final Argument<?> bodyArgument = // Mono
                            routeInfo.getReturnType().getFirstTypeVariable().orElse(// HttpResponse
                            Argument.OBJECT_ARGUMENT).getFirstTypeVariable().orElse(// Mono
                            Argument.OBJECT_ARGUMENT);
                            if (bodyArgument.isAsyncOrReactive()) {
                                return processPublisherBody(request, singleResponse, routeInfo);
                            }
                        } else if (o instanceof HttpStatus) {
                            singleResponse = forStatus(routeInfo, (HttpStatus) o);
                        } else {
                            singleResponse = forStatus(routeInfo, defaultHttpStatus).body(o);
                        }
                        return Flux.just(singleResponse);
                    }).switchIfEmpty(Mono.fromSupplier(emptyResponse));
                } else {
                    // streaming case
                    Argument<?> typeArgument = routeInfo.getReturnType().getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT);
                    if (HttpResponse.class.isAssignableFrom(typeArgument.getType())) {
                        // a response stream
                        Publisher<HttpResponse<?>> bodyPublisher = Publishers.convertPublisher(body, Publisher.class);
                        Flux<MutableHttpResponse<?>> response = Flux.from(bodyPublisher).map(this::toMutableResponse);
                        Argument<?> bodyArgument = typeArgument.getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT);
                        if (bodyArgument.isAsyncOrReactive()) {
                            return response.flatMap((resp) -> processPublisherBody(request, resp, routeInfo));
                        }
                        return response;
                    } else {
                        MutableHttpResponse<?> response = forStatus(routeInfo, defaultHttpStatus).body(body);
                        return processPublisherBody(request, response, routeInfo);
                    }
                }
            }
            // now we have the raw result, transform it as necessary
            if (body instanceof HttpStatus) {
                outgoingResponse = Mono.just(HttpResponse.status((HttpStatus) body));
            } else {
                if (routeInfo.isSuspended()) {
                    boolean isKotlinFunctionReturnTypeUnit = routeInfo instanceof MethodBasedRouteMatch && isKotlinFunctionReturnTypeUnit(((MethodBasedRouteMatch) routeInfo).getExecutableMethod());
                    final Supplier<CompletableFuture<?>> supplier = ContinuationArgumentBinder.extractContinuationCompletableFutureSupplier(request);
                    if (isKotlinCoroutineSuspended(body)) {
                        return Mono.fromCompletionStage(supplier).<MutableHttpResponse<?>>flatMap(obj -> {
                            MutableHttpResponse<?> response;
                            if (obj instanceof HttpResponse) {
                                response = toMutableResponse((HttpResponse<?>) obj);
                                final Argument<?> bodyArgument = routeInfo.getReturnType().getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT);
                                if (bodyArgument.isAsyncOrReactive()) {
                                    return processPublisherBody(request, response, routeInfo);
                                }
                            } else {
                                response = forStatus(routeInfo, defaultHttpStatus);
                                if (!isKotlinFunctionReturnTypeUnit) {
                                    response = response.body(obj);
                                }
                            }
                            return Mono.just(response);
                        }).switchIfEmpty(createNotFoundErrorResponsePublisher(request));
                    } else {
                        Object suspendedBody;
                        if (isKotlinFunctionReturnTypeUnit) {
                            suspendedBody = Mono.empty();
                        } else {
                            suspendedBody = body;
                        }
                        outgoingResponse = toMutableResponse(request, routeInfo, defaultHttpStatus, suspendedBody);
                    }
                } else {
                    outgoingResponse = toMutableResponse(request, routeInfo, defaultHttpStatus, body);
                }
            }
        }
        // for head request we never emit the body
        if (request != null && request.getMethod().equals(HttpMethod.HEAD)) {
            outgoingResponse = outgoingResponse.map(r -> {
                final Object o = r.getBody().orElse(null);
                if (o instanceof ReferenceCounted) {
                    ((ReferenceCounted) o).release();
                }
                r.body(null);
                return r;
            });
        }
        return outgoingResponse;
    }).doOnNext((response) -> {
        applyConfiguredHeaders(response.getHeaders());
        if (routeInfo instanceof RouteMatch) {
            response.setAttribute(HttpAttributes.ROUTE_MATCH, routeInfo);
        }
        response.setAttribute(HttpAttributes.ROUTE_INFO, routeInfo);
    });
}
Also used : Publishers(io.micronaut.core.async.publisher.Publishers) ServerFilterChain(io.micronaut.http.filter.ServerFilterChain) BeanContext(io.micronaut.context.BeanContext) KotlinExecutableMethodUtils.isKotlinFunctionReturnTypeUnit(io.micronaut.inject.util.KotlinExecutableMethodUtils.isKotlinFunctionReturnTypeUnit) LoggerFactory(org.slf4j.LoggerFactory) HttpHeaders(io.micronaut.http.HttpHeaders) Internal(io.micronaut.core.annotation.Internal) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) HttpStatus(io.micronaut.http.HttpStatus) MediaType(io.micronaut.http.MediaType) ReferenceCounted(io.micronaut.core.io.buffer.ReferenceCounted) HttpResponse(io.micronaut.http.HttpResponse) MethodReference(io.micronaut.inject.MethodReference) MethodBasedRouteMatch(io.micronaut.web.router.MethodBasedRouteMatch) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) Qualifiers(io.micronaut.inject.qualifiers.Qualifiers) Singleton(jakarta.inject.Singleton) MutableHttpHeaders(io.micronaut.http.MutableHttpHeaders) CompletionException(java.util.concurrent.CompletionException) HttpFilter(io.micronaut.http.filter.HttpFilter) RequestArgumentSatisfier(io.micronaut.http.server.binding.RequestArgumentSatisfier) List(java.util.List) RouteInfo(io.micronaut.web.router.RouteInfo) BeanCreationException(io.micronaut.context.exceptions.BeanCreationException) Optional(java.util.Optional) HttpAttributes(io.micronaut.http.HttpAttributes) Pattern(java.util.regex.Pattern) RouteMatch(io.micronaut.web.router.RouteMatch) UnsatisfiedRouteException(io.micronaut.web.router.exceptions.UnsatisfiedRouteException) LocalDateTime(java.time.LocalDateTime) CompletableFuture(java.util.concurrent.CompletableFuture) Scheduler(reactor.core.scheduler.Scheduler) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Supplier(java.util.function.Supplier) ExceptionHandler(io.micronaut.http.server.exceptions.ExceptionHandler) ExecutableMethod(io.micronaut.inject.ExecutableMethod) ArrayList(java.util.ArrayList) ErrorContext(io.micronaut.http.server.exceptions.response.ErrorContext) Nullable(io.micronaut.core.annotation.Nullable) ReturnType(io.micronaut.core.type.ReturnType) Schedulers(reactor.core.scheduler.Schedulers) Argument(io.micronaut.core.type.Argument) HttpRequest(io.micronaut.http.HttpRequest) ServerRequestContext(io.micronaut.http.context.ServerRequestContext) ErrorResponseProcessor(io.micronaut.http.server.exceptions.response.ErrorResponseProcessor) ExecutorService(java.util.concurrent.ExecutorService) HttpStatusException(io.micronaut.http.exceptions.HttpStatusException) HttpMethod(io.micronaut.http.HttpMethod) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) ExecutorSelector(io.micronaut.scheduling.executor.ExecutorSelector) Publisher(org.reactivestreams.Publisher) Mono(reactor.core.publisher.Mono) IOException(java.io.IOException) BeanType(io.micronaut.inject.BeanType) ExecutionException(java.util.concurrent.ExecutionException) NonNull(io.micronaut.core.annotation.NonNull) Flux(reactor.core.publisher.Flux) ContinuationArgumentBinder(io.micronaut.http.bind.binders.ContinuationArgumentBinder) KotlinUtils.isKotlinCoroutineSuspended(io.micronaut.core.util.KotlinUtils.isKotlinCoroutineSuspended) BeanDefinition(io.micronaut.inject.BeanDefinition) Router(io.micronaut.web.router.Router) Collections(java.util.Collections) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) Optional(java.util.Optional) Argument(io.micronaut.core.type.Argument) HttpStatus(io.micronaut.http.HttpStatus) MethodBasedRouteMatch(io.micronaut.web.router.MethodBasedRouteMatch) Mono(reactor.core.publisher.Mono) Flux(reactor.core.publisher.Flux) HttpResponse(io.micronaut.http.HttpResponse) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) Publisher(org.reactivestreams.Publisher) MethodBasedRouteMatch(io.micronaut.web.router.MethodBasedRouteMatch) RouteMatch(io.micronaut.web.router.RouteMatch) Supplier(java.util.function.Supplier) ReferenceCounted(io.micronaut.core.io.buffer.ReferenceCounted)

Example 7 with HttpStatus

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

the class RouteExecutor method toMutableResponse.

private MutableHttpResponse<?> toMutableResponse(HttpResponse<?> message) {
    MutableHttpResponse<?> mutableHttpResponse;
    if (message instanceof MutableHttpResponse) {
        mutableHttpResponse = (MutableHttpResponse<?>) message;
    } else {
        HttpStatus httpStatus = message.status();
        mutableHttpResponse = HttpResponse.status(httpStatus, httpStatus.getReason());
        mutableHttpResponse.body(message.body());
        message.getHeaders().forEach((name, value) -> {
            for (String val : value) {
                mutableHttpResponse.header(name, val);
            }
        });
        mutableHttpResponse.getAttributes().putAll(message.getAttributes());
    }
    return mutableHttpResponse;
}
Also used : MutableHttpResponse(io.micronaut.http.MutableHttpResponse) HttpStatus(io.micronaut.http.HttpStatus)

Example 8 with HttpStatus

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

the class RouteExecutor method handleStatusException.

private Publisher<MutableHttpResponse<?>> handleStatusException(HttpRequest<?> request, MutableHttpResponse<?> response) {
    HttpStatus status = response.status();
    RouteInfo<?> routeInfo = response.getAttribute(HttpAttributes.ROUTE_INFO, RouteInfo.class).orElse(null);
    if (status.getCode() >= 400 && routeInfo != null && !routeInfo.isErrorRoute()) {
        RouteMatch<Object> statusRoute = findStatusRoute(request, status, routeInfo);
        if (statusRoute != null) {
            return executeRoute(request, false, Flux.just(statusRoute));
        }
    }
    return Flux.just(response);
}
Also used : HttpStatus(io.micronaut.http.HttpStatus) RouteInfo(io.micronaut.web.router.RouteInfo)

Example 9 with HttpStatus

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

the class RoutingInBoundHandler method writeFinalNettyResponse.

private void writeFinalNettyResponse(MutableHttpResponse<?> message, HttpRequest<?> request, ChannelHandlerContext context) {
    HttpStatus httpStatus = message.status();
    final io.micronaut.http.HttpVersion httpVersion = request.getHttpVersion();
    final boolean isHttp2 = httpVersion == io.micronaut.http.HttpVersion.HTTP_2_0;
    boolean decodeError = request instanceof NettyHttpRequest && ((NettyHttpRequest<?>) request).getNativeRequest().decoderResult().isFailure();
    final Object body = message.body();
    if (body instanceof NettyCustomizableResponseTypeHandlerInvoker) {
        // default Connection header if not set explicitly
        if (!isHttp2) {
            if (!message.getHeaders().contains(HttpHeaders.CONNECTION)) {
                if (!decodeError && (httpStatus.getCode() < 500 || serverConfiguration.isKeepAliveOnServerError())) {
                    message.getHeaders().set(HttpHeaders.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
                } else {
                    message.getHeaders().set(HttpHeaders.CONNECTION, HttpHeaderValues.CLOSE);
                }
            }
        }
        NettyCustomizableResponseTypeHandlerInvoker handler = (NettyCustomizableResponseTypeHandlerInvoker) body;
        message.body(null);
        handler.invoke(request, message, context);
    } else {
        io.netty.handler.codec.http.HttpResponse nettyResponse = NettyHttpResponseBuilder.toHttpResponse(message);
        io.netty.handler.codec.http.HttpHeaders nettyHeaders = nettyResponse.headers();
        // default Connection header if not set explicitly
        if (!isHttp2) {
            if (!nettyHeaders.contains(HttpHeaderNames.CONNECTION)) {
                boolean expectKeepAlive = nettyResponse.protocolVersion().isKeepAliveDefault() || request.getHeaders().isKeepAlive();
                if (!decodeError && (expectKeepAlive || httpStatus.getCode() < 500 || serverConfiguration.isKeepAliveOnServerError())) {
                    nettyHeaders.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
                } else {
                    nettyHeaders.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
                }
            }
        }
        // default to Transfer-Encoding: chunked if Content-Length not set or not already set
        if (!nettyHeaders.contains(HttpHeaderNames.CONTENT_LENGTH) && !nettyHeaders.contains(HttpHeaderNames.TRANSFER_ENCODING)) {
            nettyHeaders.set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
        }
        // close handled by HttpServerKeepAliveHandler
        final NettyHttpRequest<?> nettyHttpRequest = (NettyHttpRequest<?>) request;
        if (isHttp2) {
            addHttp2StreamHeader(request, nettyResponse);
        }
        io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
        GenericFutureListener<Future<? super Void>> requestCompletor = future -> {
            try {
                if (!future.isSuccess()) {
                    final Throwable throwable = future.cause();
                    if (!(throwable instanceof ClosedChannelException)) {
                        if (throwable instanceof Http2Exception.StreamException) {
                            Http2Exception.StreamException se = (Http2Exception.StreamException) throwable;
                            if (se.error() == Http2Error.STREAM_CLOSED) {
                                // ignore
                                return;
                            }
                        }
                        if (LOG.isErrorEnabled()) {
                            LOG.error("Error writing final response: " + throwable.getMessage(), throwable);
                        }
                    }
                }
            } finally {
                cleanupRequest(context, nettyHttpRequest);
                context.read();
            }
        };
        if (nativeRequest instanceof StreamedHttpRequest && !((StreamedHttpRequest) nativeRequest).isConsumed()) {
            StreamedHttpRequest streamedHttpRequest = (StreamedHttpRequest) nativeRequest;
            // We have to clear the buffer of FlowControlHandler before writing the response
            // If this is a streamed request and there is still content to consume then subscribe
            // and write the buffer is empty.
            // noinspection ReactiveStreamsSubscriberImplementation
            streamedHttpRequest.subscribe(new Subscriber<HttpContent>() {

                private Subscription streamSub;

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

                @Override
                public void onNext(HttpContent httpContent) {
                    httpContent.release();
                    streamSub.request(1);
                }

                @Override
                public void onError(Throwable t) {
                    syncWriteAndFlushNettyResponse(context, request, nettyResponse, requestCompletor);
                }

                @Override
                public void onComplete() {
                    syncWriteAndFlushNettyResponse(context, request, nettyResponse, requestCompletor);
                }
            });
        } else {
            syncWriteAndFlushNettyResponse(context, request, nettyResponse, requestCompletor);
        }
    }
}
Also used : Publishers(io.micronaut.core.async.publisher.Publishers) HttpRequestTerminatedEvent(io.micronaut.http.context.event.HttpRequestTerminatedEvent) HttpHeaders(io.micronaut.http.HttpHeaders) Internal(io.micronaut.core.annotation.Internal) NettyStreamedFileCustomizableResponseType(io.micronaut.http.server.netty.types.files.NettyStreamedFileCustomizableResponseType) ByteBufHolder(io.netty.buffer.ByteBufHolder) HttpStatus(io.micronaut.http.HttpStatus) IdleState(io.netty.handler.timeout.IdleState) NettySystemFileCustomizableResponseType(io.micronaut.http.server.netty.types.files.NettySystemFileCustomizableResponseType) NettyPartData(io.micronaut.http.server.netty.multipart.NettyPartData) TextPlainCodec(io.micronaut.runtime.http.codec.TextPlainCodec) IdleStateEvent(io.netty.handler.timeout.IdleStateEvent) Set(java.util.Set) RequestArgumentSatisfier(io.micronaut.http.server.binding.RequestArgumentSatisfier) SSLException(javax.net.ssl.SSLException) RouteInfo(io.micronaut.web.router.RouteInfo) Writable(io.micronaut.core.io.Writable) Body(io.micronaut.http.annotation.Body) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) Http2Error(io.netty.handler.codec.http2.Http2Error) InternalServerException(io.micronaut.http.server.exceptions.InternalServerException) RouteMatch(io.micronaut.web.router.RouteMatch) NettyByteBufferFactory(io.micronaut.buffer.netty.NettyByteBufferFactory) NettyMutableHttpResponse(io.micronaut.http.netty.NettyMutableHttpResponse) MonoSink(reactor.core.publisher.MonoSink) Supplier(java.util.function.Supplier) ArrayList(java.util.ArrayList) UriRouteMatch(io.micronaut.web.router.UriRouteMatch) HttpData(io.netty.handler.codec.http.multipart.HttpData) Nullable(io.micronaut.core.annotation.Nullable) DuplicateRouteException(io.micronaut.web.router.exceptions.DuplicateRouteException) BiConsumer(java.util.function.BiConsumer) ByteBuffer(io.micronaut.core.io.buffer.ByteBuffer) Argument(io.micronaut.core.type.Argument) HttpRequest(io.micronaut.http.HttpRequest) ConversionService(io.micronaut.core.convert.ConversionService) ServerRequestContext(io.micronaut.http.context.ServerRequestContext) ErrorResponseProcessor(io.micronaut.http.server.exceptions.response.ErrorResponseProcessor) MediaTypeCodecRegistry(io.micronaut.http.codec.MediaTypeCodecRegistry) HttpContent(io.netty.handler.codec.http.HttpContent) FileUpload(io.netty.handler.codec.http.multipart.FileUpload) ClosedChannelException(java.nio.channels.ClosedChannelException) Publisher(org.reactivestreams.Publisher) 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) DefaultHttpContent(io.netty.handler.codec.http.DefaultHttpContent) Flux(reactor.core.publisher.Flux) AtomicLong(java.util.concurrent.atomic.AtomicLong) Paths(java.nio.file.Paths) SimpleChannelInboundHandler(io.netty.channel.SimpleChannelInboundHandler) HttpHeaderNames(io.netty.handler.codec.http.HttpHeaderNames) Future(io.netty.util.concurrent.Future) RouteExecutor(io.micronaut.http.server.RouteExecutor) Sinks(reactor.core.publisher.Sinks) StreamingFileUpload(io.micronaut.http.multipart.StreamingFileUpload) URL(java.net.URL) URISyntaxException(java.net.URISyntaxException) LoggerFactory(org.slf4j.LoggerFactory) NettyHttpServerConfiguration(io.micronaut.http.server.netty.configuration.NettyHttpServerConfiguration) FileCustomizableResponseType(io.micronaut.http.server.types.files.FileCustomizableResponseType) Unpooled(io.netty.buffer.Unpooled) CompletionAwareSubscriber(io.micronaut.core.async.subscriber.CompletionAwareSubscriber) PartData(io.micronaut.http.multipart.PartData) NettyCustomizableResponseTypeHandler(io.micronaut.http.server.netty.types.NettyCustomizableResponseTypeHandler) StaticResourceResolver(io.micronaut.web.router.resource.StaticResourceResolver) MediaType(io.micronaut.http.MediaType) Http2Exception(io.netty.handler.codec.http2.Http2Exception) ReferenceCounted(io.micronaut.core.io.buffer.ReferenceCounted) HttpResponse(io.micronaut.http.HttpResponse) ClassUtils(io.micronaut.core.reflect.ClassUtils) Collection(java.util.Collection) MethodBasedRouteMatch(io.micronaut.web.router.MethodBasedRouteMatch) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) MutableHttpResponse(io.micronaut.http.MutableHttpResponse) MutableHttpHeaders(io.micronaut.http.MutableHttpHeaders) NettyCustomizableResponseTypeHandlerRegistry(io.micronaut.http.server.netty.types.NettyCustomizableResponseTypeHandlerRegistry) TooLongFrameException(io.netty.handler.codec.TooLongFrameException) HttpResponseStatus(io.netty.handler.codec.http.HttpResponseStatus) Collectors(java.util.stream.Collectors) ByteBufOutputStream(io.netty.buffer.ByteBufOutputStream) Attribute(io.netty.handler.codec.http.multipart.Attribute) StreamedHttpRequest(io.micronaut.http.netty.stream.StreamedHttpRequest) DecoderResult(io.netty.handler.codec.DecoderResult) List(java.util.List) DefaultHttpHeaders(io.netty.handler.codec.http.DefaultHttpHeaders) Optional(java.util.Optional) HttpAttributes(io.micronaut.http.HttpAttributes) Pattern(java.util.regex.Pattern) HttpVersion(io.netty.handler.codec.http.HttpVersion) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicReference(java.util.concurrent.atomic.AtomicReference) Sharable(io.netty.channel.ChannelHandler.Sharable) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) HashSet(java.util.HashSet) ErrorContext(io.micronaut.http.server.exceptions.response.ErrorContext) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) ByteBuf(io.netty.buffer.ByteBuf) Subscriber(org.reactivestreams.Subscriber) ExecutorService(java.util.concurrent.ExecutorService) HttpMethod(io.micronaut.http.HttpMethod) MediaTypeCodec(io.micronaut.http.codec.MediaTypeCodec) Logger(org.slf4j.Logger) HttpHeaderValues(io.netty.handler.codec.http.HttpHeaderValues) ApplicationEventPublisher(io.micronaut.context.event.ApplicationEventPublisher) GenericFutureListener(io.netty.util.concurrent.GenericFutureListener) NettyStreamingFileUpload(io.micronaut.http.server.netty.multipart.NettyStreamingFileUpload) LongConsumer(java.util.function.LongConsumer) NonNull(io.micronaut.core.annotation.NonNull) CollectionUtils(io.micronaut.core.util.CollectionUtils) Subscription(org.reactivestreams.Subscription) Router(io.micronaut.web.router.Router) Collections(java.util.Collections) JsonSubscriber(io.micronaut.http.netty.stream.JsonSubscriber) Http2Exception(io.netty.handler.codec.http2.Http2Exception) Subscription(org.reactivestreams.Subscription) ClosedChannelException(java.nio.channels.ClosedChannelException) HttpStatus(io.micronaut.http.HttpStatus) StreamedHttpRequest(io.micronaut.http.netty.stream.StreamedHttpRequest) Future(io.netty.util.concurrent.Future) AbstractNettyHttpRequest(io.micronaut.http.netty.AbstractNettyHttpRequest) HttpContent(io.netty.handler.codec.http.HttpContent) DefaultHttpContent(io.netty.handler.codec.http.DefaultHttpContent) LastHttpContent(io.netty.handler.codec.http.LastHttpContent)

Example 10 with HttpStatus

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

the class RoutingInBoundHandler method channelRead0.

@Override
protected void channelRead0(ChannelHandlerContext ctx, io.micronaut.http.HttpRequest<?> request) {
    ctx.channel().config().setAutoRead(false);
    io.micronaut.http.HttpMethod httpMethod = request.getMethod();
    String requestPath = request.getUri().getPath();
    ServerRequestContext.set(request);
    if (LOG.isDebugEnabled()) {
        LOG.debug("Request {} {}", httpMethod, request.getUri());
    }
    NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) request;
    io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
    // handle decoding failure
    DecoderResult decoderResult = nativeRequest.decoderResult();
    if (decoderResult.isFailure()) {
        Throwable cause = decoderResult.cause();
        HttpStatus status = cause instanceof TooLongFrameException ? HttpStatus.REQUEST_ENTITY_TOO_LARGE : HttpStatus.BAD_REQUEST;
        handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(status), status.getReason());
        return;
    }
    MediaType contentType = request.getContentType().orElse(null);
    final String requestMethodName = request.getMethodName();
    if (!multipartEnabled && contentType != null && contentType.equals(MediaType.MULTIPART_FORM_DATA_TYPE)) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Multipart uploads have been disabled via configuration. Rejected request for URI {}, method {}, and content type {}", request.getUri(), requestMethodName, contentType);
        }
        handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE), "Content Type [" + contentType + "] not allowed");
        return;
    }
    UriRouteMatch<Object, Object> routeMatch = null;
    List<UriRouteMatch<Object, Object>> uriRoutes = router.findAllClosest(request);
    if (uriRoutes.size() > 1) {
        throw new DuplicateRouteException(requestPath, uriRoutes);
    } else if (uriRoutes.size() == 1) {
        UriRouteMatch<Object, Object> establishedRoute = uriRoutes.get(0);
        request.setAttribute(HttpAttributes.ROUTE, establishedRoute.getRoute());
        request.setAttribute(HttpAttributes.ROUTE_MATCH, establishedRoute);
        request.setAttribute(HttpAttributes.ROUTE_INFO, establishedRoute);
        request.setAttribute(HttpAttributes.URI_TEMPLATE, establishedRoute.getRoute().getUriMatchTemplate().toString());
        routeMatch = establishedRoute;
    }
    RouteMatch<?> route;
    if (routeMatch == null) {
        // Check if there is a file for the route before returning route not found
        Optional<? extends FileCustomizableResponseType> optionalFile = matchFile(requestPath);
        if (optionalFile.isPresent()) {
            filterAndEncodeResponse(ctx, nettyHttpRequest, Flux.just(HttpResponse.ok(optionalFile.get())));
            return;
        }
        if (LOG.isDebugEnabled()) {
            LOG.debug("No matching route: {} {}", httpMethod, request.getUri());
        }
        // if there is no route present try to locate a route that matches a different HTTP method
        final List<UriRouteMatch<?, ?>> anyMatchingRoutes = router.findAny(request.getUri().toString(), request).collect(Collectors.toList());
        final Collection<MediaType> acceptedTypes = request.accept();
        final boolean hasAcceptHeader = CollectionUtils.isNotEmpty(acceptedTypes);
        Set<MediaType> acceptableContentTypes = contentType != null ? new HashSet<>(5) : null;
        Set<String> allowedMethods = new HashSet<>(5);
        Set<MediaType> produceableContentTypes = hasAcceptHeader ? new HashSet<>(5) : null;
        for (UriRouteMatch<?, ?> anyRoute : anyMatchingRoutes) {
            final String routeMethod = anyRoute.getRoute().getHttpMethodName();
            if (!requestMethodName.equals(routeMethod)) {
                allowedMethods.add(routeMethod);
            }
            if (contentType != null && !anyRoute.doesConsume(contentType)) {
                acceptableContentTypes.addAll(anyRoute.getRoute().getConsumes());
            }
            if (hasAcceptHeader && !anyRoute.doesProduce(acceptedTypes)) {
                produceableContentTypes.addAll(anyRoute.getRoute().getProduces());
            }
        }
        if (CollectionUtils.isNotEmpty(acceptableContentTypes)) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Content type not allowed for URI {}, method {}, and content type {}", request.getUri(), requestMethodName, contentType);
            }
            handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE), "Content Type [" + contentType + "] not allowed. Allowed types: " + acceptableContentTypes);
            return;
        }
        if (CollectionUtils.isNotEmpty(produceableContentTypes)) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Content type not allowed for URI {}, method {}, and content type {}", request.getUri(), requestMethodName, contentType);
            }
            handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.NOT_ACCEPTABLE), "Specified Accept Types " + acceptedTypes + " not supported. Supported types: " + produceableContentTypes);
            return;
        }
        if (!allowedMethods.isEmpty()) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Method not allowed for URI {} and method {}", request.getUri(), requestMethodName);
            }
            handleStatusError(ctx, nettyHttpRequest, HttpResponse.notAllowedGeneric(allowedMethods), "Method [" + requestMethodName + "] not allowed for URI [" + request.getUri() + "]. Allowed methods: " + allowedMethods);
            return;
        } else {
            handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.NOT_FOUND), "Page Not Found");
        }
        return;
    } else {
        route = routeMatch;
    }
    if (LOG.isTraceEnabled()) {
        if (route instanceof MethodBasedRouteMatch) {
            LOG.trace("Matched route {} - {} to controller {}", requestMethodName, requestPath, route.getDeclaringType());
        } else {
            LOG.trace("Matched route {} - {}", requestMethodName, requestPath);
        }
    }
    // all ok proceed to try and execute the route
    if (route.isWebSocketRoute()) {
        handleStatusError(ctx, nettyHttpRequest, HttpResponse.status(HttpStatus.BAD_REQUEST), "Not a WebSocket request");
    } else {
        handleRouteMatch(route, nettyHttpRequest, ctx);
    }
}
Also used : TooLongFrameException(io.netty.handler.codec.TooLongFrameException) MethodBasedRouteMatch(io.micronaut.web.router.MethodBasedRouteMatch) DecoderResult(io.netty.handler.codec.DecoderResult) MediaType(io.micronaut.http.MediaType) HashSet(java.util.HashSet) HttpMethod(io.micronaut.http.HttpMethod) HttpStatus(io.micronaut.http.HttpStatus) DuplicateRouteException(io.micronaut.web.router.exceptions.DuplicateRouteException) UriRouteMatch(io.micronaut.web.router.UriRouteMatch) AbstractNettyHttpRequest(io.micronaut.http.netty.AbstractNettyHttpRequest)

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