Search in sources :

Example 1 with EMPTY_LAST_CONTENT

use of io.netty.handler.codec.http.LastHttpContent.EMPTY_LAST_CONTENT in project styx by ExpediaGroup.

the class HttpResponseWriter method write.

// CHECKSTYLE:OFF
public CompletableFuture<Void> write(LiveHttpResponse response) {
    CompletableFuture<Void> future = new CompletableFuture<>();
    try {
        writeHeaders(response).addListener((ChannelFutureListener) writeOp -> {
            if (writeOp.isSuccess()) {
                writeOpsAcked.incrementAndGet();
            } else {
                LOGGER.warn("Unable to send response headers. Written content bytes {}/{} (ackd/sent). Write events {}/{} (ackd/writes). Exception={}", new Object[] { contentBytesAcked.get(), contentBytesWritten.get(), writeOpsAcked.get(), writeOps.get(), writeOp.cause() });
                future.completeExceptionally(writeOp.cause());
            }
        });
        response.body().subscribe(new BaseSubscriber<Buffer>() {

            @Override
            public void hookOnSubscribe(Subscription subscription) {
                future.handle((ignore, cause) -> {
                    if (future.isCompletedExceptionally() && cause instanceof CancellationException) {
                        subscription.cancel();
                    }
                    return null;
                });
                subscription.request(1);
            }

            @Override
            public void hookOnComplete() {
                if (!future.isDone()) {
                    nettyWriteAndFlush(EMPTY_LAST_CONTENT).addListener((ChannelFutureListener) this::onWriteEmptyLastChunkOutcome);
                    contentCompleted.set(true);
                    completeIfAllSent(future);
                }
            }

            @Override
            public void hookOnError(Throwable cause) {
                LOGGER.warn("Content observable error. Written content bytes {}/{} (ackd/sent). Write events {}/{} (ackd/writes). Exception={}", new Object[] { contentBytesAcked.get(), contentBytesWritten.get(), writeOpsAcked.get(), writeOps.get(), cause });
                future.completeExceptionally(cause);
            }

            @Override
            public void hookOnNext(Buffer buffer) {
                ByteBuf byteBuf = Buffers.toByteBuf(buffer);
                if (future.isDone()) {
                    byteBuf.release();
                } else {
                    long bufSize = (long) byteBuf.readableBytes();
                    contentBytesWritten.addAndGet(bufSize);
                    nettyWriteAndFlush(new DefaultHttpContent(byteBuf)).addListener(it -> onWriteOutcome((ChannelFuture) it, bufSize));
                }
            }

            private void onWriteOutcome(ChannelFuture writeOp, long bufSize) {
                if (writeOp.isSuccess()) {
                    contentBytesAcked.addAndGet(bufSize);
                    writeOpsAcked.incrementAndGet();
                    request(1);
                    completeIfAllSent(future);
                } else if (!future.isDone()) {
                    // Suppress messages if future has already failed, or completed for other reason:
                    cancel();
                    LOGGER.warn("Write error. Written content bytes {}/{} (ackd/sent). Write events {}/{} (ackd/writes), Exception={}", new Object[] { contentBytesAcked.get(), contentBytesWritten.get(), writeOpsAcked.get(), writeOps.get(), response, writeOp.cause() });
                    future.completeExceptionally(writeOp.cause());
                }
            }

            private void onWriteEmptyLastChunkOutcome(ChannelFuture writeOp) {
                writeOpsAcked.incrementAndGet();
                completeIfAllSent(future);
                cancel();
            }
        });
        return future;
    } catch (Throwable cause) {
        LOGGER.warn("Failed to convert response headers. response={}, Cause={}", new Object[] { response, cause });
        toObservable(response.body()).forEach(it -> Buffers.toByteBuf(it).release());
        future.completeExceptionally(cause);
        return future;
    }
}
Also used : RxReactiveStreams.toObservable(rx.RxReactiveStreams.toObservable) Logger(org.slf4j.Logger) CancellationException(java.util.concurrent.CancellationException) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) CompletableFuture(java.util.concurrent.CompletableFuture) EMPTY_LAST_CONTENT(io.netty.handler.codec.http.LastHttpContent.EMPTY_LAST_CONTENT) Buffer(com.hotels.styx.api.Buffer) ChannelFuture(io.netty.channel.ChannelFuture) BaseSubscriber(reactor.core.publisher.BaseSubscriber) DefaultHttpContent(io.netty.handler.codec.http.DefaultHttpContent) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) AtomicLong(java.util.concurrent.atomic.AtomicLong) LiveHttpResponse(com.hotels.styx.api.LiveHttpResponse) ByteBuf(io.netty.buffer.ByteBuf) Buffers(com.hotels.styx.api.Buffers) ChannelFutureListener(io.netty.channel.ChannelFutureListener) Subscription(org.reactivestreams.Subscription) Objects.requireNonNull(java.util.Objects.requireNonNull) HttpHeaders.setTransferEncodingChunked(io.netty.handler.codec.http.HttpHeaders.setTransferEncodingChunked) Buffer(com.hotels.styx.api.Buffer) ChannelFuture(io.netty.channel.ChannelFuture) DefaultHttpContent(io.netty.handler.codec.http.DefaultHttpContent) ByteBuf(io.netty.buffer.ByteBuf) CompletableFuture(java.util.concurrent.CompletableFuture) CancellationException(java.util.concurrent.CancellationException) Subscription(org.reactivestreams.Subscription)

Aggregations

Buffer (com.hotels.styx.api.Buffer)1 Buffers (com.hotels.styx.api.Buffers)1 LiveHttpResponse (com.hotels.styx.api.LiveHttpResponse)1 ByteBuf (io.netty.buffer.ByteBuf)1 ChannelFuture (io.netty.channel.ChannelFuture)1 ChannelFutureListener (io.netty.channel.ChannelFutureListener)1 ChannelHandlerContext (io.netty.channel.ChannelHandlerContext)1 DefaultHttpContent (io.netty.handler.codec.http.DefaultHttpContent)1 HttpHeaders.setTransferEncodingChunked (io.netty.handler.codec.http.HttpHeaders.setTransferEncodingChunked)1 EMPTY_LAST_CONTENT (io.netty.handler.codec.http.LastHttpContent.EMPTY_LAST_CONTENT)1 Objects.requireNonNull (java.util.Objects.requireNonNull)1 CancellationException (java.util.concurrent.CancellationException)1 CompletableFuture (java.util.concurrent.CompletableFuture)1 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)1 AtomicLong (java.util.concurrent.atomic.AtomicLong)1 Subscription (org.reactivestreams.Subscription)1 Logger (org.slf4j.Logger)1 LoggerFactory (org.slf4j.LoggerFactory)1 BaseSubscriber (reactor.core.publisher.BaseSubscriber)1 RxReactiveStreams.toObservable (rx.RxReactiveStreams.toObservable)1