@Override
    public void onNext(DeframedMessage message) {
        if (GrpcSerializationFormats.isGrpcWeb(serializationFormat) && message.isTrailer()) {
            final ByteBuf buf;
            try {
                buf = messageBuf(message, ctx.alloc());
            } catch (Throwable t) {
                cancel(null, t);
                return;
            }
            try {
                final HttpHeaders trailers = InternalGrpcWebUtil.parseGrpcWebTrailers(buf);
                if (trailers == null) {
                    // Malformed trailers.
                    close(Status.INTERNAL.withDescription(serializationFormat.uriText() +
                                                          " trailers malformed: " +
                                                          buf.toString(StandardCharsets.UTF_8)),
                          new Metadata());
                } else {
                    GrpcWebTrailers.set(ctx, trailers);
                    GrpcStatus.reportStatus(trailers, this);
                }
            } finally {
                buf.release();
            }
            return;
        }

        try {
            final boolean grpcWebText = GrpcSerializationFormats.isGrpcWebText(serializationFormat);
            final O msg = marshaller.deserializeResponse(message, grpcWebText);
            if (firstResponse == null) {
                firstResponse = msg;
            }

            final ByteBuf buf = message.buf();
            if (unsafeWrapResponseBuffers && buf != null && !grpcWebText) {
                GrpcUnsafeBufferUtil.storeBuffer(buf, msg, ctx);
            }

            executor.execute(() -> {
                try (SafeCloseable ignored = ctx.push()) {
                    assert listener != null;
                    listener.onMessage(msg);
                } catch (Throwable t) {
                    closeWhenListenerThrows(t);
                }
            });
        } catch (Throwable t) {
            final StatusAndMetadata statusAndMetadata = exceptionHandler.handle(ctx, t);
            close(statusAndMetadata.status(), statusAndMetadata.metadata());
        }
    }
Encapsulates the state of a single client call, writing messages from the client and reading responses
from the server, passing to business logic via {@link ClientCall.Listener}.
grpc/src/main/java/com/linecorp/armeria/internal/client/grpc/ArmeriaClientCall.java