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 {};
}