FOLLY_NODISCARD folly::exception_wrapper processFirstResponseHelper()

in thrift/lib/cpp2/transport/rocket/server/RocketThriftRequests.cpp [137:352]


FOLLY_NODISCARD folly::exception_wrapper processFirstResponseHelper(
    ResponseRpcMetadata& metadata,
    std::unique_ptr<folly::IOBuf>& payload,
    int32_t version) noexcept {
  try {
    std::string methodNameIgnore;
    MessageType mtype;
    int32_t seqIdIgnore;
    ProtocolReader reader;
    reader.setInput(payload.get());
    reader.readMessageBegin(methodNameIgnore, mtype, seqIdIgnore);

    switch (mtype) {
      case MessageType::T_REPLY: {
        auto prefixSize = reader.getCursorPosition();

        protocol::TType ftype;
        int16_t fid;
        reader.readStructBegin(methodNameIgnore);
        reader.readFieldBegin(methodNameIgnore, ftype, fid);

        while (payload->length() < prefixSize) {
          prefixSize -= payload->length();
          payload = payload->pop();
        }
        payload->trimStart(prefixSize);

        PayloadMetadata payloadMetadata;
        if (fid == 0) {
          payloadMetadata.set_responseMetadata(PayloadResponseMetadata());
        } else {
          preprocessProxiedExceptionHeaders(metadata, version);

          PayloadExceptionMetadataBase exceptionMetadataBase;
          PayloadDeclaredExceptionMetadata declaredExceptionMetadata;
          if (auto otherMetadataRef = metadata.otherMetadata_ref()) {
            // defined in sync with
            // thrift/lib/cpp2/transport/core/RpcMetadataUtil.h

            // Setting user exception name and content
            static const auto uex =
                std::string(apache::thrift::detail::kHeaderUex);
            if (auto uexPtr = folly::get_ptr(*otherMetadataRef, uex)) {
              exceptionMetadataBase.name_utf8_ref() = *uexPtr;
              otherMetadataRef->erase(uex);
            }
            static const auto uexw =
                std::string(apache::thrift::detail::kHeaderUexw);
            if (auto uexwPtr = folly::get_ptr(*otherMetadataRef, uexw)) {
              exceptionMetadataBase.what_utf8_ref() = *uexwPtr;
              otherMetadataRef->erase(uexw);
            }

            // Setting user declared exception classification
            static const auto exMeta =
                std::string(apache::thrift::detail::kHeaderExMeta);
            if (auto metaPtr = folly::get_ptr(*otherMetadataRef, exMeta)) {
              ErrorClassification errorClassification =
                  apache::thrift::detail::deserializeErrorClassification(
                      *metaPtr);
              declaredExceptionMetadata.errorClassification_ref() =
                  std::move(errorClassification);
            }
          }
          PayloadExceptionMetadata exceptionMetadata;
          exceptionMetadata.set_declaredException(
              std::move(declaredExceptionMetadata));
          exceptionMetadataBase.metadata_ref() = std::move(exceptionMetadata);
          payloadMetadata.set_exceptionMetadata(
              std::move(exceptionMetadataBase));
        }
        metadata.payloadMetadata_ref() = std::move(payloadMetadata);
        break;
      }
      case MessageType::T_EXCEPTION: {
        DCHECK_GE(version, 2);

        preprocessProxiedExceptionHeaders(metadata, version);

        TApplicationException ex;
        ::apache::thrift::detail::deserializeExceptionBody(&reader, &ex);

        PayloadExceptionMetadataBase exceptionMetadataBase;
        exceptionMetadataBase.what_utf8_ref() = ex.getMessage();

        auto otherMetadataRef = metadata.otherMetadata_ref();
        DCHECK(
            !otherMetadataRef ||
            !folly::get_ptr(*otherMetadataRef, "servicerouter:sr_error"));
        if (auto proxyErrorPtr = otherMetadataRef
                ? folly::get_ptr(
                      *otherMetadataRef, "servicerouter:sr_internal_error")
                : nullptr) {
          exceptionMetadataBase.name_utf8_ref() = "ProxyException";
          PayloadExceptionMetadata exceptionMetadata;
          exceptionMetadata.set_proxyException(PayloadProxyExceptionMetadata());
          exceptionMetadataBase.metadata_ref() = std::move(exceptionMetadata);

          payload = protocol::base64Decode(*proxyErrorPtr);

          otherMetadataRef->erase("servicerouter:sr_internal_error");
          otherMetadataRef->erase("ex");
        } else {
          DCHECK_GE(version, 3);

          auto exPtr = otherMetadataRef
              ? folly::get_ptr(*otherMetadataRef, "ex")
              : nullptr;
          auto uexPtr = otherMetadataRef
              ? folly::get_ptr(*otherMetadataRef, "uex")
              : nullptr;
          if (auto errorCode = [&]() -> folly::Optional<ResponseRpcErrorCode> {
                if (exPtr) {
                  if (*exPtr == kQueueOverloadedErrorCode &&
                      ex.getType() == TApplicationException::LOADSHEDDING) {
                    return ResponseRpcErrorCode::SHUTDOWN;
                  }

                  static const auto& errorCodeMap = *new std::unordered_map<
                      std::string,
                      ResponseRpcErrorCode>(
                      {{kUnknownErrorCode, ResponseRpcErrorCode::UNKNOWN},
                       {kOverloadedErrorCode, ResponseRpcErrorCode::OVERLOAD},
                       {kAppOverloadedErrorCode,
                        ResponseRpcErrorCode::APP_OVERLOAD},
                       {kTaskExpiredErrorCode,
                        ResponseRpcErrorCode::TASK_EXPIRED},
                       {kQueueOverloadedErrorCode,
                        ResponseRpcErrorCode::QUEUE_OVERLOADED},
                       {kInjectedFailureErrorCode,
                        ResponseRpcErrorCode::INJECTED_FAILURE},
                       {kServerQueueTimeoutErrorCode,
                        ResponseRpcErrorCode::QUEUE_TIMEOUT},
                       {kResponseTooBigErrorCode,
                        ResponseRpcErrorCode::RESPONSE_TOO_BIG},
                       {kMethodUnknownErrorCode,
                        ResponseRpcErrorCode::UNKNOWN_METHOD},
                       {kRequestTypeDoesntMatchServiceFunctionType,
                        ResponseRpcErrorCode::WRONG_RPC_KIND},
                       {kInteractionIdUnknownErrorCode,
                        ResponseRpcErrorCode::UNKNOWN_INTERACTION_ID},
                       {kInteractionConstructorErrorErrorCode,
                        ResponseRpcErrorCode::INTERACTION_CONSTRUCTOR_ERROR},
                       {kRequestParsingErrorCode,
                        ResponseRpcErrorCode::REQUEST_PARSING_FAILURE},
                       {kChecksumMismatchErrorCode,
                        ResponseRpcErrorCode::CHECKSUM_MISMATCH},
                       {kUnimplementedMethodErrorCode,
                        ResponseRpcErrorCode::UNIMPLEMENTED_METHOD}});
                  if (auto errorCode = folly::get_ptr(errorCodeMap, *exPtr)) {
                    return *errorCode;
                  }
                }

                return folly::none;
              }()) {
            return makeResponseRpcError(*errorCode, ex.getMessage(), metadata);
          }
          if (uexPtr) {
            exceptionMetadataBase.name_utf8_ref() = *uexPtr;
            otherMetadataRef->erase("uex");
          }
          PayloadExceptionMetadata exceptionMetadata;
          if (exPtr && *exPtr == kAppClientErrorCode) {
            if (version < 8) {
              exceptionMetadata.set_DEPRECATED_appClientException(
                  PayloadAppClientExceptionMetadata());
            } else {
              PayloadAppUnknownExceptionMetdata aue;
              aue.errorClassification_ref().ensure().blame_ref() =
                  ErrorBlame::CLIENT;
              exceptionMetadata.set_appUnknownException(std::move(aue));
            }
          } else {
            if (version < 8) {
              exceptionMetadata.set_DEPRECATED_appServerException(
                  PayloadAppServerExceptionMetadata());
            } else {
              PayloadAppUnknownExceptionMetdata aue;
              aue.errorClassification_ref().ensure().blame_ref() =
                  ErrorBlame::SERVER;
              exceptionMetadata.set_appUnknownException(std::move(aue));
            }
          }
          exceptionMetadataBase.metadata_ref() = std::move(exceptionMetadata);

          payload->clear();

          if (otherMetadataRef) {
            otherMetadataRef->erase("ex");
            otherMetadataRef->erase("uexw");
          }
        }

        PayloadMetadata payloadMetadata;
        payloadMetadata.set_exceptionMetadata(std::move(exceptionMetadataBase));
        metadata.payloadMetadata_ref() = std::move(payloadMetadata);

        break;
      }
      default:
        DCHECK_GE(version, 3);
        return makeResponseRpcError(
            ResponseRpcErrorCode::UNKNOWN, "Invalid message type", metadata);
    }
  } catch (...) {
    DCHECK_GE(version, 3);
    return makeResponseRpcError(
        ResponseRpcErrorCode::UNKNOWN,
        fmt::format(
            "Invalid response payload envelope: {}",
            folly::exceptionStr(std::current_exception()).toStdString()),
        metadata);
  }
  return {};
}