use of io.micronaut.http.server.netty.HttpContentProcessor in project micronaut-core by micronaut-projects.
the class MultipartBodyArgumentBinder method bind.
@Override
public BindingResult<MultipartBody> bind(ArgumentConversionContext<MultipartBody> context, HttpRequest<?> source) {
if (source instanceof NettyHttpRequest) {
NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) source;
io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
if (nativeRequest instanceof StreamedHttpRequest) {
HttpContentProcessor<?> processor = beanLocator.findBean(HttpContentSubscriberFactory.class, new ConsumesMediaTypeQualifier<>(MediaType.MULTIPART_FORM_DATA_TYPE)).map(factory -> factory.build(nettyHttpRequest)).orElse(new DefaultHttpContentProcessor(nettyHttpRequest, httpServerConfiguration.get()));
// noinspection unchecked
return () -> Optional.of(subscriber -> processor.subscribe(new TypedSubscriber<Object>((Argument) context.getArgument()) {
Subscription s;
AtomicLong partsRequested = new AtomicLong(0);
@Override
protected void doOnSubscribe(Subscription subscription) {
this.s = subscription;
subscriber.onSubscribe(new Subscription() {
@Override
public void request(long n) {
if (partsRequested.getAndUpdate(prev -> prev + n) == 0) {
s.request(n);
}
}
@Override
public void cancel() {
subscription.cancel();
}
});
}
@Override
protected void doOnNext(Object message) {
if (LOG.isTraceEnabled()) {
LOG.trace("Server received streaming message for argument [{}]: {}", context.getArgument(), message);
}
if (message instanceof ByteBufHolder && ((ByteBufHolder) message).content() instanceof EmptyByteBuf) {
return;
}
if (message instanceof HttpData) {
HttpData data = (HttpData) message;
if (data.isCompleted()) {
partsRequested.decrementAndGet();
if (data instanceof FileUpload) {
subscriber.onNext(new NettyCompletedFileUpload((FileUpload) data, false));
} else if (data instanceof Attribute) {
subscriber.onNext(new NettyCompletedAttribute((Attribute) data, false));
}
// If the user didn't release the data, we should
if (data.refCnt() > 0) {
data.release();
}
}
}
if (partsRequested.get() > 0) {
s.request(1);
}
}
@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;
}
use of io.micronaut.http.server.netty.HttpContentProcessor 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;
}
Aggregations