1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/manta/manta_service_callbacks.h"
#include <memory>
#include <string>
#include <string_view>
#include "base/containers/fixed_flat_map.h"
#include "base/functional/callback.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "components/endpoint_fetcher/endpoint_fetcher.h"
#include "components/manta/manta_status.h"
#include "components/manta/proto/manta.pb.h"
#include "components/manta/proto/rpc_status.pb.h"
#include "net/http/http_status_code.h"
namespace manta {
namespace {
constexpr char kTypeUrlRpcErrorInfo[] =
"type.googleapis.com/google.rpc.ErrorInfo";
constexpr char kTypeUrlRpcLocalizedMessage[] =
"type.googleapis.com/google.rpc.LocalizedMessage";
constexpr char kExpectedEndPointDomain[] = "aratea-pa.googleapis.com";
// Maps the RpcErrorInfo.reason to MantaStatusCode.
std::optional<MantaStatusCode> MapServerFailureReasonToMantaStatusCode(
const std::string& reason) {
static constexpr auto reason_map =
base::MakeFixedFlatMap<std::string_view, MantaStatusCode>({
{"MISSING_INPUT", MantaStatusCode::kInvalidInput},
{"INVALID_INPUT", MantaStatusCode::kInvalidInput},
{"UNSUPPORTED_LANGUAGE", MantaStatusCode::kUnsupportedLanguage},
{"RESTRICTED_COUNTRY", MantaStatusCode::kRestrictedCountry},
{"RESOURCE_EXHAUSTED", MantaStatusCode::kResourceExhausted},
{"PER_USER_QUOTA_EXCEEDED", MantaStatusCode::kPerUserQuotaExceeded},
});
const auto iter = reason_map.find(reason);
return iter != reason_map.end() ? std::optional<MantaStatusCode>(iter->second)
: std::nullopt;
}
// Maps the RpcStatus.code to MantaStatusCode.
// The RpcStatus.code is an enum value of google.rpc.Code.
std::optional<MantaStatusCode> MapServerStatusCodeToMantaStatusCode(
const int32_t server_status_code) {
// TODO(b/288019728): add more items when needed.
static constexpr auto code_map =
base::MakeFixedFlatMap<int32_t, MantaStatusCode>({
{3 /*INVALID_ARGUMENT*/, MantaStatusCode::kInvalidInput},
{8 /*RESOURCE_EXHAUSTED*/, MantaStatusCode::kResourceExhausted},
});
const auto iter = code_map.find(server_status_code);
return iter != code_map.end() ? std::optional<MantaStatusCode>(iter->second)
: std::nullopt;
}
void LogTimeCost(const MantaMetricType request_type,
base::TimeDelta time_cost) {
switch (request_type) {
case MantaMetricType::kOrca:
base::UmaHistogramTimes("Ash.MantaService.OrcaProvider.TimeCost",
time_cost);
break;
case MantaMetricType::kScanner:
base::UmaHistogramTimes("Ash.MantaService.ScannerProvider.TimeCost",
time_cost);
break;
case MantaMetricType::kSnapper:
base::UmaHistogramTimes("Ash.MantaService.SnapperProvider.TimeCost",
time_cost);
break;
case MantaMetricType::kMahiSummary:
base::UmaHistogramTimes("Ash.MantaService.MahiProvider.Summary.TimeCost",
time_cost);
break;
case MantaMetricType::kMahiElucidation:
base::UmaHistogramTimes(
"Ash.MantaService.MahiProvider.Elucidation.TimeCost", time_cost);
break;
case MantaMetricType::kMahiQA:
base::UmaHistogramTimes("Ash.MantaService.MahiProvider.QA.TimeCost",
time_cost);
break;
case MantaMetricType::kAnchovy:
base::UmaHistogramTimes("Ash.MantaService.AnchovyProvider.TimeCost",
time_cost);
break;
case MantaMetricType::kWalrus:
base::UmaHistogramTimes("Ash.MantaService.WalrusProvider.TimeCost",
time_cost);
break;
}
}
void LogMantaStatusCode(const MantaMetricType request_type,
const MantaStatusCode status_code) {
switch (request_type) {
case MantaMetricType::kOrca:
base::UmaHistogramEnumeration("Ash.MantaService.OrcaProvider.StatusCode",
status_code);
break;
case MantaMetricType::kScanner:
base::UmaHistogramEnumeration(
"Ash.MantaService.ScannerProvider.StatusCode", status_code);
break;
case MantaMetricType::kSnapper:
base::UmaHistogramEnumeration(
"Ash.MantaService.SnapperProvider.StatusCode", status_code);
break;
case MantaMetricType::kMahiSummary:
base::UmaHistogramEnumeration(
"Ash.MantaService.MahiProvider.Summary.StatusCode", status_code);
break;
case MantaMetricType::kMahiElucidation:
base::UmaHistogramEnumeration(
"Ash.MantaService.MahiProvider.Elucidation.StatusCode", status_code);
break;
case MantaMetricType::kMahiQA:
base::UmaHistogramEnumeration(
"Ash.MantaService.MahiProvider.QA.StatusCode", status_code);
break;
case MantaMetricType::kAnchovy:
base::UmaHistogramEnumeration(
"Ash.MantaService.AnchovyProvider.StatusCode", status_code);
break;
case MantaMetricType::kWalrus:
base::UmaHistogramEnumeration(
"Ash.MantaService.WalrusProvider.StatusCode", status_code);
break;
}
}
} // namespace
void OnEndpointFetcherComplete(
MantaProtoResponseCallback callback,
base::Time start_time,
const MantaMetricType request_type,
std::unique_ptr<endpoint_fetcher::EndpointFetcher> fetcher,
std::unique_ptr<endpoint_fetcher::EndpointResponse> responses) {
// Tries to parse the response as a Response proto and return to the
// `callback` together with a OK status, or capture the errors and return a
// proper error status.
base::TimeDelta time_cost = base::Time::Now() - start_time;
std::string message, locale;
if (!responses) {
LogMantaStatusCode(request_type, MantaStatusCode::kBackendFailure);
std::move(callback).Run(nullptr,
{MantaStatusCode::kBackendFailure, message});
return;
}
// Tries to parse the unexpected response as RpcStatus and passes back the
// error messages.
if (responses->error_type.has_value() ||
responses->http_status_code != net::HTTP_OK) {
MantaStatusCode manta_status_code = MantaStatusCode::kBackendFailure;
if (responses->error_type.has_value() &&
responses->error_type.value() ==
endpoint_fetcher::FetchErrorType::kNetError) {
manta_status_code = MantaStatusCode::kNoInternetConnection;
}
proto::RpcStatus rpc_status;
if (!rpc_status.ParseFromString(responses->response)) {
DVLOG(1) << "Got unexpected failed response but failed to parse a "
"RpcStatus proto";
LogMantaStatusCode(request_type, manta_status_code);
std::move(callback).Run(nullptr, {manta_status_code, message});
return;
}
// Tries to map RpcStatus.code to a more specific manta status code.
auto maybe_updated_status_code =
MapServerStatusCodeToMantaStatusCode(rpc_status.code());
if (maybe_updated_status_code != std::nullopt) {
manta_status_code = maybe_updated_status_code.value();
}
// Extracts clearer error code and user-friendly messages from details.
for (const proto::Proto3Any& detail : rpc_status.details()) {
if (detail.type_url() == kTypeUrlRpcErrorInfo) {
proto::RpcErrorInfo error_info;
error_info.ParseFromString(detail.value());
// Tries to map ErrorInfo.reason to a more specific manta status code.
maybe_updated_status_code =
MapServerFailureReasonToMantaStatusCode(error_info.reason());
if (error_info.domain() == kExpectedEndPointDomain &&
maybe_updated_status_code != std::nullopt) {
manta_status_code = maybe_updated_status_code.value();
}
} else if (detail.type_url() == kTypeUrlRpcLocalizedMessage) {
proto::RpcLocalizedMessage localize_message;
localize_message.ParseFromString(detail.value());
message = localize_message.message();
locale = localize_message.locale();
}
}
LogMantaStatusCode(request_type, manta_status_code);
std::move(callback).Run(nullptr, {manta_status_code, message, locale});
return;
}
auto manta_response = std::make_unique<proto::Response>();
if (!manta_response->ParseFromString(responses->response)) {
DVLOG(1) << "Failed to parse MantaResponse as a Response proto";
LogMantaStatusCode(request_type, MantaStatusCode::kMalformedResponse);
std::move(callback).Run(nullptr,
{MantaStatusCode::kMalformedResponse, message});
return;
}
LogTimeCost(request_type, time_cost);
LogMantaStatusCode(request_type, MantaStatusCode::kOk);
std::move(callback).Run(std::move(manta_response),
{MantaStatusCode::kOk, message});
}
} // namespace manta
|