@Override
    public void processHeaders(HttpHeaders headers, StreamDecoderOutput<DeframedMessage> out) {
        if (headers instanceof RequestHeaders) {
            // RequestHeaders is handled by (Un)FramedGrpcService.
            return;
        }

        final String statusText = headers.get(HttpHeaderNames.STATUS);
        if (statusText == null) {
            // Not allowed to have empty leading headers, kill the stream hard.
            transportStatusListener.transportReportStatus(
                    Status.INTERNAL.withDescription("Missing HTTP status code"));
            return;
        }

        final HttpStatus status = HttpStatus.valueOf(statusText);
        if (!status.equals(HttpStatus.OK)) {
            // Just mark trailers as received since a non-OK response may not have trailers.
            trailersReceived = true;
            transportStatusListener.transportReportStatus(
                    GrpcStatus.httpStatusToGrpcStatus(status.code()));
            return;
        }

        final String grpcStatus = headers.get(GrpcHeaderNames.GRPC_STATUS);
        if (grpcStatus != null) {
            assert deframedStreamMessage != null;
            trailersReceived = true;
            GrpcStatus.reportStatusLater(headers, deframedStreamMessage, transportStatusListener);
        }

        // Headers without grpc-status are the leading headers of a non-failing response, prepare to receive
        // messages.
        final String grpcEncoding = headers.get(GrpcHeaderNames.GRPC_ENCODING);
        if (grpcEncoding != null) {
            final io.grpc.Decompressor decompressor = decompressorRegistry.lookupDecompressor(grpcEncoding);
            if (decompressor == null) {
                transportStatusListener.transportReportStatus(Status.INTERNAL.withDescription(
                        "Can't find decompressor for " + grpcEncoding));
                return;
            }
            try {
                decompressor(ForwardingDecompressor.forGrpc(decompressor));
            } catch (Throwable t) {
                final StatusAndMetadata statusAndMetadata = exceptionHandler.handle(ctx, t);
                transportStatusListener.transportReportStatus(statusAndMetadata.status(),
                                                              statusAndMetadata.metadata());
                return;
            }
        }

        if (grpcStatus == null) {
            // exclude trailers-only responses from triggering the callback
            final Metadata metadata = MetadataUtil.copyFromHeaders(headers);
            // Note: this implementation slightly differs from upstream in that
            // we don't check if the content-type is valid before invoking this callback.
            transportStatusListener.transportReportHeaders(metadata);
        }
    }
Sets the deframed {@link StreamMessage}.
Note that the {@code deframedStreamMessage} should be set before processing the first {@link HttpObject}.
grpc/src/main/java/com/linecorp/armeria/internal/common/grpc/HttpStreamDeframer.java