Search in sources :

Example 1 with NettyByteBufferFactory

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

the class AbstractNettyWebSocketHandler method handleWebSocketFrame.

/**
 * Handles WebSocket frame request.
 *
 * @param ctx The context
 * @param msg The frame
 */
protected void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame msg) {
    if (msg instanceof TextWebSocketFrame || msg instanceof BinaryWebSocketFrame || msg instanceof ContinuationWebSocketFrame) {
        if (messageHandler == null) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("WebSocket bean [" + webSocketBean.getTarget() + "] received message, but defined no @OnMessage handler. Dropping frame...");
            }
            writeCloseFrameAndTerminate(ctx, CloseReason.UNSUPPORTED_DATA);
        } else {
            ByteBuf msgContent = msg.content().retain();
            if (!msg.isFinalFragment()) {
                frameBuffer.updateAndGet((buffer) -> {
                    if (buffer == null) {
                        buffer = ctx.alloc().compositeBuffer();
                    }
                    buffer.addComponent(true, msgContent);
                    return buffer;
                });
                return;
            }
            ByteBuf content;
            CompositeByteBuf buffer = frameBuffer.getAndSet(null);
            if (buffer == null) {
                content = msgContent;
            } else {
                buffer.addComponent(true, msgContent);
                content = buffer;
            }
            Argument<?> bodyArgument = this.getBodyArgument();
            Optional<?> converted = ConversionService.SHARED.convert(content, bodyArgument);
            content.release();
            if (!converted.isPresent()) {
                MediaType mediaType;
                try {
                    mediaType = messageHandler.stringValue(Consumes.class).map(MediaType::of).orElse(MediaType.APPLICATION_JSON_TYPE);
                } catch (IllegalArgumentException e) {
                    exceptionCaught(ctx, e);
                    return;
                }
                try {
                    converted = mediaTypeCodecRegistry.findCodec(mediaType).map(codec -> codec.decode(bodyArgument, new NettyByteBufferFactory(ctx.alloc()).wrap(msg.content())));
                } catch (CodecException e) {
                    messageProcessingException(ctx, e);
                    return;
                }
            }
            if (converted.isPresent()) {
                Object v = converted.get();
                NettyWebSocketSession currentSession = getSession();
                ExecutableBinder<WebSocketState> executableBinder = new DefaultExecutableBinder<>(Collections.singletonMap(bodyArgument, v));
                try {
                    BoundExecutable boundExecutable = executableBinder.bind(messageHandler.getExecutableMethod(), webSocketBinder, new WebSocketState(currentSession, originatingRequest));
                    Object result = invokeExecutable(boundExecutable, messageHandler);
                    if (Publishers.isConvertibleToPublisher(result)) {
                        Flux<?> flowable = Flux.from(instrumentPublisher(ctx, result));
                        flowable.subscribe(o -> {
                        }, error -> messageProcessingException(ctx, error), () -> messageHandled(ctx, session, v));
                    } else {
                        messageHandled(ctx, session, v);
                    }
                } catch (Throwable e) {
                    messageProcessingException(ctx, e);
                }
            } else {
                writeCloseFrameAndTerminate(ctx, CloseReason.UNSUPPORTED_DATA.getCode(), CloseReason.UNSUPPORTED_DATA.getReason() + ": " + "Received data cannot be converted to target type: " + bodyArgument);
            }
        }
    } else if (msg instanceof PingWebSocketFrame) {
        // respond with pong
        PingWebSocketFrame frame = (PingWebSocketFrame) msg.retain();
        ctx.writeAndFlush(new PongWebSocketFrame(frame.content()));
    } else if (msg instanceof PongWebSocketFrame) {
        if (pongHandler != null) {
            ByteBuf content = msg.content();
            WebSocketPongMessage message = new WebSocketPongMessage(NettyByteBufferFactory.DEFAULT.wrap(content));
            NettyWebSocketSession currentSession = getSession();
            ExecutableBinder<WebSocketState> executableBinder = new DefaultExecutableBinder<>(Collections.singletonMap(getPongArgument(), message));
            try {
                BoundExecutable boundExecutable = executableBinder.bind(pongHandler.getExecutableMethod(), webSocketBinder, new WebSocketState(currentSession, originatingRequest));
                Object result = invokeExecutable(boundExecutable, pongHandler);
                if (Publishers.isConvertibleToPublisher(result)) {
                    // delay the buffer release until the publisher has completed
                    content.retain();
                    Flux<?> flowable = Flux.from(instrumentPublisher(ctx, result));
                    flowable.subscribe(o -> {
                    }, error -> {
                        if (LOG.isErrorEnabled()) {
                            LOG.error("Error Processing WebSocket Pong Message [" + webSocketBean + "]: " + error.getMessage(), error);
                        }
                        exceptionCaught(ctx, error);
                    }, content::release);
                }
            } catch (Throwable e) {
                if (LOG.isErrorEnabled()) {
                    LOG.error("Error Processing WebSocket Message [" + webSocketBean + "]: " + e.getMessage(), e);
                }
                exceptionCaught(ctx, e);
            }
        }
    } else if (msg instanceof CloseWebSocketFrame) {
        CloseWebSocketFrame cwsf = (CloseWebSocketFrame) msg;
        handleCloseFrame(ctx, cwsf);
    } else {
        writeCloseFrameAndTerminate(ctx, CloseReason.UNSUPPORTED_DATA);
    }
}
Also used : Publishers(io.micronaut.core.async.publisher.Publishers) ArgumentBinderRegistry(io.micronaut.core.bind.ArgumentBinderRegistry) LoggerFactory(org.slf4j.LoggerFactory) Internal(io.micronaut.core.annotation.Internal) UnsatisfiedArgumentException(io.micronaut.core.bind.exceptions.UnsatisfiedArgumentException) CloseReason(io.micronaut.websocket.CloseReason) MediaType(io.micronaut.http.MediaType) Map(java.util.Map) RequestBinderRegistry(io.micronaut.http.bind.RequestBinderRegistry) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) CodecException(io.micronaut.http.codec.CodecException) ContinuationWebSocketFrame(io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame) WebSocketState(io.micronaut.websocket.bind.WebSocketState) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) List(java.util.List) Optional(java.util.Optional) NettyByteBufferFactory(io.micronaut.buffer.netty.NettyByteBufferFactory) WebSocketBean(io.micronaut.websocket.context.WebSocketBean) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) AtomicReference(java.util.concurrent.atomic.AtomicReference) ExecutableMethod(io.micronaut.inject.ExecutableMethod) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) WebSocketVersion(io.netty.handler.codec.http.websocketx.WebSocketVersion) ExecutableBinder(io.micronaut.core.bind.ExecutableBinder) ByteBuf(io.netty.buffer.ByteBuf) PongWebSocketFrame(io.netty.handler.codec.http.websocketx.PongWebSocketFrame) Schedulers(reactor.core.scheduler.Schedulers) CloseWebSocketFrame(io.netty.handler.codec.http.websocketx.CloseWebSocketFrame) Argument(io.micronaut.core.type.Argument) HttpRequest(io.micronaut.http.HttpRequest) BoundExecutable(io.micronaut.core.bind.BoundExecutable) ConversionService(io.micronaut.core.convert.ConversionService) MediaTypeCodecRegistry(io.micronaut.http.codec.MediaTypeCodecRegistry) Logger(org.slf4j.Logger) WebSocketFrame(io.netty.handler.codec.http.websocketx.WebSocketFrame) PingWebSocketFrame(io.netty.handler.codec.http.websocketx.PingWebSocketFrame) Publisher(org.reactivestreams.Publisher) IOException(java.io.IOException) MethodExecutionHandle(io.micronaut.inject.MethodExecutionHandle) Channel(io.netty.channel.Channel) BinaryWebSocketFrame(io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame) Consumer(java.util.function.Consumer) Flux(reactor.core.publisher.Flux) WebSocketStateBinderRegistry(io.micronaut.websocket.bind.WebSocketStateBinderRegistry) TextWebSocketFrame(io.netty.handler.codec.http.websocketx.TextWebSocketFrame) SimpleChannelInboundHandler(io.netty.channel.SimpleChannelInboundHandler) Consumes(io.micronaut.http.annotation.Consumes) WebSocketPongMessage(io.micronaut.websocket.WebSocketPongMessage) Collections(java.util.Collections) BinaryWebSocketFrame(io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) ByteBuf(io.netty.buffer.ByteBuf) PingWebSocketFrame(io.netty.handler.codec.http.websocketx.PingWebSocketFrame) CompositeByteBuf(io.netty.buffer.CompositeByteBuf) PongWebSocketFrame(io.netty.handler.codec.http.websocketx.PongWebSocketFrame) Consumes(io.micronaut.http.annotation.Consumes) TextWebSocketFrame(io.netty.handler.codec.http.websocketx.TextWebSocketFrame) MediaType(io.micronaut.http.MediaType) CodecException(io.micronaut.http.codec.CodecException) CloseWebSocketFrame(io.netty.handler.codec.http.websocketx.CloseWebSocketFrame) NettyByteBufferFactory(io.micronaut.buffer.netty.NettyByteBufferFactory) ContinuationWebSocketFrame(io.netty.handler.codec.http.websocketx.ContinuationWebSocketFrame) DefaultExecutableBinder(io.micronaut.core.bind.DefaultExecutableBinder) BoundExecutable(io.micronaut.core.bind.BoundExecutable) WebSocketPongMessage(io.micronaut.websocket.WebSocketPongMessage) WebSocketState(io.micronaut.websocket.bind.WebSocketState)

Example 2 with NettyByteBufferFactory

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

the class RoutingInBoundHandler method mapToHttpContent.

private Flux<HttpContent> mapToHttpContent(NettyHttpRequest<?> request, MutableHttpResponse<?> response, Object body, ChannelHandlerContext context) {
    final RouteInfo<?> routeInfo = response.getAttribute(HttpAttributes.ROUTE_INFO, RouteInfo.class).orElse(null);
    final boolean hasRouteInfo = routeInfo != null;
    MediaType mediaType = response.getContentType().orElse(null);
    if (mediaType == null && hasRouteInfo) {
        mediaType = routeExecutor.resolveDefaultResponseContentType(request, routeInfo);
    }
    boolean isJson = mediaType != null && mediaType.getExtension().equals(MediaType.EXTENSION_JSON) && isJsonFormattable(hasRouteInfo ? routeInfo.getBodyType() : null);
    NettyByteBufferFactory byteBufferFactory = new NettyByteBufferFactory(context.alloc());
    Flux<Object> bodyPublisher = Flux.from(Publishers.convertPublisher(body, Publisher.class));
    MediaType finalMediaType = mediaType;
    Flux<HttpContent> httpContentPublisher = bodyPublisher.map(message -> {
        HttpContent httpContent;
        if (message instanceof ByteBuf) {
            httpContent = new DefaultHttpContent((ByteBuf) message);
        } else if (message instanceof ByteBuffer) {
            ByteBuffer<?> byteBuffer = (ByteBuffer<?>) message;
            Object nativeBuffer = byteBuffer.asNativeBuffer();
            if (nativeBuffer instanceof ByteBuf) {
                httpContent = new DefaultHttpContent((ByteBuf) nativeBuffer);
            } else {
                httpContent = new DefaultHttpContent(Unpooled.copiedBuffer(byteBuffer.asNioBuffer()));
            }
        } else if (message instanceof byte[]) {
            httpContent = new DefaultHttpContent(Unpooled.copiedBuffer((byte[]) message));
        } else if (message instanceof HttpContent) {
            httpContent = (HttpContent) message;
        } else {
            MediaTypeCodec codec = mediaTypeCodecRegistry.findCodec(finalMediaType, message.getClass()).orElse(new TextPlainCodec(serverConfiguration.getDefaultCharset()));
            if (LOG.isTraceEnabled()) {
                LOG.trace("Encoding emitted response object [{}] using codec: {}", message, codec);
            }
            ByteBuffer<ByteBuf> encoded;
            if (hasRouteInfo) {
                // noinspection unchecked
                final Argument<Object> bodyType = (Argument<Object>) routeInfo.getBodyType();
                if (bodyType.isInstance(message)) {
                    encoded = codec.encode(bodyType, message, byteBufferFactory);
                } else {
                    encoded = codec.encode(message, byteBufferFactory);
                }
            } else {
                encoded = codec.encode(message, byteBufferFactory);
            }
            httpContent = new DefaultHttpContent(encoded.asNativeBuffer());
        }
        return httpContent;
    });
    if (isJson) {
        // if the Publisher is returning JSON then in order for it to be valid JSON for each emitted element
        // we must wrap the JSON in array and delimit the emitted items
        httpContentPublisher = JsonSubscriber.lift(httpContentPublisher);
    }
    httpContentPublisher = httpContentPublisher.contextWrite(reactorContext -> reactorContext.put(ServerRequestContext.KEY, request)).doOnNext(httpContent -> context.read()).doAfterTerminate(() -> cleanupRequest(context, request));
    return httpContentPublisher;
}
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) NettyByteBufferFactory(io.micronaut.buffer.netty.NettyByteBufferFactory) Argument(io.micronaut.core.type.Argument) DefaultHttpContent(io.netty.handler.codec.http.DefaultHttpContent) Publisher(org.reactivestreams.Publisher) ApplicationEventPublisher(io.micronaut.context.event.ApplicationEventPublisher) ByteBuf(io.netty.buffer.ByteBuf) ByteBuffer(io.micronaut.core.io.buffer.ByteBuffer) TextPlainCodec(io.micronaut.runtime.http.codec.TextPlainCodec) MediaType(io.micronaut.http.MediaType) RouteInfo(io.micronaut.web.router.RouteInfo) HttpContent(io.netty.handler.codec.http.HttpContent) DefaultHttpContent(io.netty.handler.codec.http.DefaultHttpContent) LastHttpContent(io.netty.handler.codec.http.LastHttpContent) MediaTypeCodec(io.micronaut.http.codec.MediaTypeCodec)

Aggregations

NettyByteBufferFactory (io.micronaut.buffer.netty.NettyByteBufferFactory)2 Internal (io.micronaut.core.annotation.Internal)2 Publishers (io.micronaut.core.async.publisher.Publishers)2 ConversionService (io.micronaut.core.convert.ConversionService)2 Argument (io.micronaut.core.type.Argument)2 HttpRequest (io.micronaut.http.HttpRequest)2 MediaType (io.micronaut.http.MediaType)2 MediaTypeCodecRegistry (io.micronaut.http.codec.MediaTypeCodecRegistry)2 ByteBuf (io.netty.buffer.ByteBuf)2 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)2 SimpleChannelInboundHandler (io.netty.channel.SimpleChannelInboundHandler)2 IOException (java.io.IOException)2 Collections (java.util.Collections)2 List (java.util.List)2 Optional (java.util.Optional)2 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)2 AtomicReference (java.util.concurrent.atomic.AtomicReference)2 Publisher (org.reactivestreams.Publisher)2 Logger (org.slf4j.Logger)2 LoggerFactory (org.slf4j.LoggerFactory)2