public void write()

in servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/HttpObjectEncoder.java [124:219]


    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        if (msg instanceof HttpMetaData) {
            if (state == CONTENT_LEN_CHUNKED) {
                // The user didn't write any trailers, so just send the last chunk.
                encodeAndWriteTrailers(ctx, EmptyHttpHeaders.INSTANCE, promise);
            } else if (state > 0) {
                tryTooLittleContent(ctx, msg, promise);
                return;
            } else if (state == -1) {
                unknownContentLengthNewRequest(ctx);
            }

            T metaData = castMetaData(msg);
            closeHandler.protocolPayloadBeginOutbound(ctx);
            if (shouldClose(metaData)) {
                closeHandler.protocolClosingOutbound(ctx);
            }

            // We prefer a direct allocation here because it is expected the resulted encoded Buffer will be written
            // to a socket. In order to do the write to the socket the memory typically needs to be allocated in direct
            // memory and will be copied to direct memory if not. Using a direct buffer will avoid the copy.
            ByteBuf byteBuf = ctx.alloc().directBuffer((int) headersEncodedSizeAccumulator);
            try {
                Buffer stBuf = newBufferFrom(byteBuf);

                // Encode the message.
                encodeInitialLine(stBuf, metaData);
                if (isContentAlwaysEmpty(metaData)) {
                    state = CONTENT_LEN_EMPTY;
                    closeHandler.protocolPayloadEndOutbound(ctx, promise);
                } else if (isTransferEncodingChunked(metaData.headers())) {
                    state = CONTENT_LEN_CHUNKED;
                } else {
                    state = getContentLength(metaData);
                    assert state > CONTENT_LEN_LARGEST_VALUE;
                    if (state == 0) {
                        state = CONTENT_LEN_CONSUMED;
                        closeHandler.protocolPayloadEndOutbound(ctx, promise);
                    }
                }

                sanitizeHeadersBeforeEncode(metaData);

                encodeHeaders(metaData.headers(), byteBuf, stBuf);
                writeShortBE(byteBuf, CRLF_SHORT);
                headersEncodedSizeAccumulator = HEADERS_WEIGHT_NEW * padSizeForAccumulation(byteBuf.readableBytes()) +
                                                HEADERS_WEIGHT_HISTORICAL * headersEncodedSizeAccumulator;
            } catch (Throwable e) {
                // Encoding of meta-data can fail or cause expansion of the initial ByteBuf capacity that can fail
                byteBuf.release();
                tryIoException(ctx, e, promise);
                return;
            }

            ctx.write(byteBuf, promise);
        } else if (msg instanceof Buffer) {
            final Buffer stBuffer = (Buffer) msg;
            final int readableBytes = stBuffer.readableBytes();
            if (readableBytes <= 0) {
                ctx.write(EMPTY_BUFFER, promise);
            } else if (state == CONTENT_LEN_CHUNKED) {
                PromiseCombiner promiseCombiner = new PromiseCombiner(ctx.executor());
                encodeChunkedContent(ctx, stBuffer, stBuffer.readableBytes(), promiseCombiner);
                promiseCombiner.finish(promise);
            } else if (state <= CONTENT_LEN_LARGEST_VALUE || state >= 0 && (state -= readableBytes) < 0) {
                // state may be <0 if there is no content-length or transfer-encoding, so let this pass through, but if
                // state would go negative (or already zeroed) then fail.
                tryTooMuchContent(ctx, readableBytes, promise);
            } else {
                if (state == 0) {
                    state = CONTENT_LEN_CONSUMED;
                    closeHandler.protocolPayloadEndOutbound(ctx, promise);
                }
                ctx.write(encodeAndRetain(stBuffer), promise);
            }
        } else if (msg instanceof HttpHeaders) {
            final boolean isChunked = state == CONTENT_LEN_CHUNKED;
            state = CONTENT_LEN_INIT;
            final HttpHeaders trailers = (HttpHeaders) msg;
            if (isChunked) {
                closeHandler.protocolPayloadEndOutbound(ctx, promise);
                encodeAndWriteTrailers(ctx, trailers, promise);
            } else if (!trailers.isEmpty()) {
                tryFailNonEmptyTrailers(ctx, trailers, promise);
            } else if (state > 0) {
                tryTooLittleContent(ctx, promise);
            } else {
                // Allow trailers to be written as a marker indicating the request is done.
                if (state != CONTENT_LEN_CONSUMED) {
                    closeHandler.protocolPayloadEndOutbound(ctx, promise);
                }
                state = CONTENT_LEN_INIT;
                ctx.write(EMPTY_BUFFER, promise);
            }
        }
    }