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();
}
}
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;
}
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;
}
Aggregations