public HttpData writePayload(ByteBuf message, boolean webTrailers) {
        verifyNotClosed();
        final boolean compressed = messageCompression && compressor != null;
        final int messageLength = message.readableBytes();
        try {
            final ByteBuf buf;
            if (messageLength != 0 && compressed) {
                buf = writeCompressed(message, webTrailers);
            } else {
                buf = writeUncompressed(message, webTrailers);
            }

            final ByteBuf maybeEncodedBuf;
            if (encodeBase64) {
                try {
                    maybeEncodedBuf = Base64.encode(buf, false);
                } finally {
                    buf.release();
                }
                final int length = maybeEncodedBuf.readableBytes();
                if (maxMessageLength >= 0 && length > maxMessageLength) {
                    maybeEncodedBuf.release();
                    throw newMessageTooLargeException(length);
                }
            } else {
                maybeEncodedBuf = buf;
            }

            return HttpData.wrap(maybeEncodedBuf).withEndOfStream(webTrailers);
        } catch (ArmeriaStatusException e) {
            throw e;
        } catch (IOException | RuntimeException e) {
            // IOException will not be thrown, since sink#deliverFrame doesn't throw.
            throw new ArmeriaStatusException(StatusCodes.INTERNAL, "Failed to frame message", e);
        }
    }
Writes out a payload message.

@param message the message to be written out. Ownership is taken by {@link ArmeriaMessageFramer}.
@param webTrailers tells whether the payload is web trailers

@return an {@link HttpData} with the framed payload. Ownership is passed to caller. If the specified
        {@code webTrailers} is {@code true}, {@link HttpData#isEndOfStream()} returns {@code true}.
grpc-protocol/src/main/java/com/linecorp/armeria/common/grpc/protocol/ArmeriaMessageFramer.java