private void decodeAndInvoke(
            ServiceRequestContext ctx, AggregatedHttpRequest req,
            SerializationFormat serializationFormat, CompletableFuture<HttpResponse> httpRes) {

        final int seqId;
        final ThriftFunction f;
        final RpcRequest decodedReq;

        try (HttpData content = req.content()) {
            final ByteBuf buf = content.byteBuf();
            final TByteBufTransport inTransport = new TByteBufTransport(buf);
            final TProtocolFactory protocolFactory = requestProtocolFactories.get(serializationFormat);
            assert protocolFactory != null;
            final TProtocol inProto = protocolFactory.getProtocol(inTransport);

            final TMessage header;
            final TBase<?, ?> args;

            try {
                // Optionally checks the message length before calling `readMessageBegin()` because
                // Thrift 0.9.x and 0.10.x does not support a correct validation of `readMessageBegin()` for
                // some `TProtocol`s.
                ThriftProtocolUtil.maybeCheckMessageLength(serializationFormat, buf, maxRequestStringLength);

                header = inProto.readMessageBegin();
            } catch (Exception e) {
                logger.debug("{} Failed to decode a {} header:", ctx, serializationFormat, e);

                final HttpStatus httpStatus;
                String message;
                if (e instanceof TProtocolException &&
                    ((TProtocolException) e).getType() == TProtocolException.SIZE_LIMIT) {
                    httpStatus = HttpStatus.REQUEST_ENTITY_TOO_LARGE;
                    message = firstNonNull(e.getMessage(), httpStatus.toString());
                } else {
                    httpStatus = HttpStatus.BAD_REQUEST;
                    message = "Failed to decode a " + serializationFormat + " header";
                }
                if (ctx.config().verboseResponses()) {
                    message += '\n' + Exceptions.traceText(e);
                }

                httpRes.complete(HttpResponse.of(httpStatus, MediaType.PLAIN_TEXT_UTF_8, message));
                return;
            }

            seqId = header.seqid;

            final byte typeValue = header.type;
            final int colonIdx = header.name.indexOf(':');
            final String serviceName;
            final String methodName;
            if (colonIdx < 0) {
                serviceName = "";
                methodName = header.name;
            } else {
                serviceName = header.name.substring(0, colonIdx);
                methodName = header.name.substring(colonIdx + 1);
            }

            // Basic sanity check. We usually should never fail here.
            if (typeValue != TMessageType.CALL && typeValue != TMessageType.ONEWAY) {
                final TApplicationException cause = new TApplicationException(
                        TApplicationException.INVALID_MESSAGE_TYPE,
                        "unexpected TMessageType: " + typeString(typeValue));

                handlePreDecodeException(ctx, httpRes, cause, serializationFormat, seqId, methodName);
                return;
            }

            // Ensure that such a method exists.
            final ThriftServiceEntry entry = entries().get(serviceName);
            f = entry != null ? entry.metadata.function(methodName) : null;
            if (f == null) {
                final TApplicationException cause = new TApplicationException(
                        TApplicationException.UNKNOWN_METHOD, "unknown method: " + header.name);

                handlePreDecodeException(ctx, httpRes, cause, serializationFormat, seqId, methodName);
                return;
            }

            // Decode the invocation parameters.
            try {
                args = f.newArgs();
                args.read(inProto);
                inProto.readMessageEnd();

                decodedReq = toRpcRequest(f.serviceType(), header.name, args);
                ctx.logBuilder().requestContent(decodedReq, new ThriftCall(header, args));
            } catch (Exception e) {
                final TApplicationException cause;
                if (ctx.config().verboseResponses()) {
                    cause = new TApplicationException(
                            TApplicationException.PROTOCOL_ERROR, "failed to decode arguments: " + e);
                } else {
                    // The exception could have sensitive information such as the required field.
                    // So we don't include the cause message unless verboseResponses returns true.
                    cause = new TApplicationException(TApplicationException.PROTOCOL_ERROR,
                                                      "failed to decode arguments for " + header.name);
                }
                handlePreDecodeException(ctx, httpRes, cause, serializationFormat, seqId, methodName);
                return;
            }
        } finally {
            ctx.logBuilder().requestContent(null, null);
        }

        if (!f.declaredDecorators().isEmpty()) {
            ctx.setAttr(DECODED_REQUEST, new DecodedRequest(serializationFormat, seqId, f, decodedReq));
            try {
                final HttpService decoratedTHttpService = decoratedTHttpServices.get(f);
                assert decoratedTHttpService != null;
                httpRes.complete(decoratedTHttpService.serve(ctx, req.toHttpRequest()));
            } catch (Exception e) {
                handleException(ctx, httpRes, serializationFormat, seqId, f, e);
            }
            return;
        }

        invoke(ctx, serializationFormat, seqId, f, decodedReq, httpRes);
    }
Returns the default {@link SerializationFormat} of this service.
thrift/thrift0.13/src/main/java/com/linecorp/armeria/server/thrift/THttpService.java