Search in sources :

Example 6 with StreamedHttpRequest

use of io.micronaut.http.netty.stream.StreamedHttpRequest in project micronaut-core by micronaut-projects.

the class NettyHttpRequest method release.

/**
 * Release and cleanup resources.
 */
@Internal
public void release() {
    Consumer<Object> releaseIfNecessary = this::releaseIfNecessary;
    getBody().ifPresent(releaseIfNecessary);
    receivedContent.forEach(releaseIfNecessary);
    receivedData.values().forEach(releaseIfNecessary);
    if (bodyUnwrapped instanceof ReferenceCounted) {
        ReferenceCounted referenceCounted = (ReferenceCounted) bodyUnwrapped;
        releaseIfNecessary(referenceCounted);
    }
    if (attributes != null) {
        attributes.values().forEach(releaseIfNecessary);
    }
    if (nettyRequest instanceof StreamedHttpRequest) {
        ((StreamedHttpRequest) nettyRequest).closeIfNoSubscriber();
    }
}
Also used : DefaultStreamedHttpRequest(io.micronaut.http.netty.stream.DefaultStreamedHttpRequest) StreamedHttpRequest(io.micronaut.http.netty.stream.StreamedHttpRequest) ReferenceCounted(io.netty.util.ReferenceCounted) Internal(io.micronaut.core.annotation.Internal)

Example 7 with StreamedHttpRequest

use of io.micronaut.http.netty.stream.StreamedHttpRequest in project micronaut-core by micronaut-projects.

the class InputStreamBodyBinder method bind.

@SuppressWarnings("unchecked")
@Override
public BindingResult<InputStream> bind(ArgumentConversionContext<InputStream> context, HttpRequest<?> source) {
    if (source instanceof NettyHttpRequest) {
        NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) source;
        io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
        if (nativeRequest instanceof StreamedHttpRequest) {
            PipedOutputStream outputStream = new PipedOutputStream();
            try {
                PipedInputStream inputStream = new PipedInputStream(outputStream) {

                    private volatile HttpContentProcessor<ByteBufHolder> processor;

                    private synchronized void init() {
                        if (processor == null) {
                            processor = (HttpContentProcessor<ByteBufHolder>) processorResolver.resolve(nettyHttpRequest, context.getArgument());
                            Flux.from(processor).publishOn(Schedulers.fromExecutor(executorService)).subscribe(new CompletionAwareSubscriber<ByteBufHolder>() {

                                @Override
                                protected void doOnSubscribe(Subscription subscription) {
                                    subscription.request(1);
                                }

                                @Override
                                protected synchronized void doOnNext(ByteBufHolder message) {
                                    if (LOG.isTraceEnabled()) {
                                        LOG.trace("Server received streaming message for argument [{}]: {}", context.getArgument(), message);
                                    }
                                    ByteBuf content = message.content();
                                    if (!(content instanceof EmptyByteBuf)) {
                                        try {
                                            byte[] bytes = ByteBufUtil.getBytes(content);
                                            outputStream.write(bytes, 0, bytes.length);
                                        } catch (IOException e) {
                                            subscription.cancel();
                                            return;
                                        } finally {
                                            content.release();
                                        }
                                    }
                                    subscription.request(1);
                                }

                                @Override
                                protected synchronized void doOnError(Throwable t) {
                                    if (LOG.isTraceEnabled()) {
                                        LOG.trace("Server received error for argument [" + context.getArgument() + "]: " + t.getMessage(), t);
                                    }
                                    try {
                                        outputStream.close();
                                    } catch (IOException ignored) {
                                    } finally {
                                        subscription.cancel();
                                    }
                                }

                                @Override
                                protected synchronized void doOnComplete() {
                                    if (LOG.isTraceEnabled()) {
                                        LOG.trace("Done receiving messages for argument: {}", context.getArgument());
                                    }
                                    try {
                                        outputStream.close();
                                    } catch (IOException ignored) {
                                    }
                                }
                            });
                        }
                    }

                    @Override
                    public synchronized int read(byte[] b, int off, int len) throws IOException {
                        init();
                        return super.read(b, off, len);
                    }

                    @Override
                    public synchronized int read() throws IOException {
                        init();
                        return super.read();
                    }
                };
                return () -> Optional.of(inputStream);
            } catch (IOException e) {
                context.reject(e);
            }
        }
    }
    return BindingResult.EMPTY;
}
Also used : EmptyByteBuf(io.netty.buffer.EmptyByteBuf) PipedOutputStream(java.io.PipedOutputStream) PipedInputStream(java.io.PipedInputStream) IOException(java.io.IOException) ByteBuf(io.netty.buffer.ByteBuf) EmptyByteBuf(io.netty.buffer.EmptyByteBuf) StreamedHttpRequest(io.micronaut.http.netty.stream.StreamedHttpRequest) HttpContentProcessor(io.micronaut.http.server.netty.HttpContentProcessor) ByteBufHolder(io.netty.buffer.ByteBufHolder) NettyHttpRequest(io.micronaut.http.server.netty.NettyHttpRequest) Subscription(org.reactivestreams.Subscription)

Example 8 with StreamedHttpRequest

use of io.micronaut.http.netty.stream.StreamedHttpRequest in project micronaut-core by micronaut-projects.

the class PublisherBodyBinder method bind.

@Override
public BindingResult<Publisher> bind(ArgumentConversionContext<Publisher> context, HttpRequest<?> source) {
    if (source instanceof NettyHttpRequest) {
        NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) source;
        io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
        if (nativeRequest instanceof StreamedHttpRequest) {
            Argument<?> targetType = context.getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT);
            HttpContentProcessor<?> processor = httpContentProcessorResolver.resolve(nettyHttpRequest, targetType);
            // noinspection unchecked
            return () -> Optional.of(subscriber -> processor.subscribe(new TypedSubscriber<Object>((Argument) context.getArgument()) {

                Subscription s;

                @Override
                protected void doOnSubscribe(Subscription subscription) {
                    this.s = subscription;
                    subscriber.onSubscribe(subscription);
                }

                @Override
                protected void doOnNext(Object message) {
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("Server received streaming message for argument [{}]: {}", context.getArgument(), message);
                    }
                    if (message instanceof ByteBufHolder) {
                        message = ((ByteBufHolder) message).content();
                        if (message instanceof EmptyByteBuf) {
                            return;
                        }
                    }
                    ArgumentConversionContext<?> conversionContext = context.with(targetType);
                    Optional<?> converted = conversionService.convert(message, conversionContext);
                    if (converted.isPresent()) {
                        subscriber.onNext(converted.get());
                    } else {
                        try {
                            Optional<ConversionError> lastError = conversionContext.getLastError();
                            if (lastError.isPresent()) {
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug("Cannot convert message for argument [" + context.getArgument() + "] and value: " + message, lastError.get());
                                }
                                subscriber.onError(new ConversionErrorException(context.getArgument(), lastError.get()));
                            } else {
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug("Cannot convert message for argument [{}] and value: {}", context.getArgument(), message);
                                }
                                subscriber.onError(UnsatisfiedRouteException.create(context.getArgument()));
                            }
                        } finally {
                            s.cancel();
                        }
                    }
                    if (message instanceof ReferenceCounted) {
                        ((ReferenceCounted) message).release();
                    }
                }

                @Override
                protected void doOnError(Throwable t) {
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("Server received error for argument [" + context.getArgument() + "]: " + t.getMessage(), t);
                    }
                    try {
                        subscriber.onError(t);
                    } finally {
                        s.cancel();
                    }
                }

                @Override
                protected void doOnComplete() {
                    if (LOG.isTraceEnabled()) {
                        LOG.trace("Done receiving messages for argument: {}", context.getArgument());
                    }
                    subscriber.onComplete();
                }
            }));
        }
    }
    return BindingResult.EMPTY;
}
Also used : EmptyByteBuf(io.netty.buffer.EmptyByteBuf) ConversionError(io.micronaut.core.convert.ConversionError) ConversionErrorException(io.micronaut.core.convert.exceptions.ConversionErrorException) StreamedHttpRequest(io.micronaut.http.netty.stream.StreamedHttpRequest) ByteBufHolder(io.netty.buffer.ByteBufHolder) NettyHttpRequest(io.micronaut.http.server.netty.NettyHttpRequest) Subscription(org.reactivestreams.Subscription) TypedSubscriber(io.micronaut.core.async.subscriber.TypedSubscriber) ReferenceCounted(io.netty.util.ReferenceCounted)

Aggregations

StreamedHttpRequest (io.micronaut.http.netty.stream.StreamedHttpRequest)8 NettyHttpRequest (io.micronaut.http.server.netty.NettyHttpRequest)5 ByteBufHolder (io.netty.buffer.ByteBufHolder)5 Subscription (org.reactivestreams.Subscription)5 Internal (io.micronaut.core.annotation.Internal)3 Argument (io.micronaut.core.type.Argument)3 MediaType (io.micronaut.http.MediaType)3 EmptyByteBuf (io.netty.buffer.EmptyByteBuf)3 Optional (java.util.Optional)3 TypedSubscriber (io.micronaut.core.async.subscriber.TypedSubscriber)2 HttpRequest (io.micronaut.http.HttpRequest)2 HttpContentProcessor (io.micronaut.http.server.netty.HttpContentProcessor)2 ByteBuf (io.netty.buffer.ByteBuf)2 Attribute (io.netty.handler.codec.http.multipart.Attribute)2 FileUpload (io.netty.handler.codec.http.multipart.FileUpload)2 HttpData (io.netty.handler.codec.http.multipart.HttpData)2 ReferenceCounted (io.netty.util.ReferenceCounted)2 IOException (java.io.IOException)2 AtomicLong (java.util.concurrent.atomic.AtomicLong)2 Logger (org.slf4j.Logger)2