1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/autofill/content/browser/wallet/wallet_client.h"
8 #include "base/json/json_reader.h"
9 #include "base/json/json_writer.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "components/autofill/content/browser/wallet/form_field_error.h"
18 #include "components/autofill/content/browser/wallet/instrument.h"
19 #include "components/autofill/content/browser/wallet/wallet_address.h"
20 #include "components/autofill/content/browser/wallet/wallet_client_delegate.h"
21 #include "components/autofill/content/browser/wallet/wallet_items.h"
22 #include "components/autofill/content/browser/wallet/wallet_service_url.h"
23 #include "components/autofill/core/browser/autofill_metrics.h"
24 #include "crypto/random.h"
25 #include "google_apis/google_api_keys.h"
26 #include "net/base/escape.h"
27 #include "net/http/http_status_code.h"
28 #include "net/url_request/url_fetcher.h"
29 #include "net/url_request/url_request_context_getter.h"
36 const char kFormEncodedMimeType[] = "application/x-www-form-urlencoded";
37 const char kJsonMimeType[] = "application/json";
38 const char kEscrowNewInstrumentFormat[] =
39 "request_content_type=application/json&request=%s&cvn=%s&card_number=%s";
40 const char kEscrowCardVerificationNumberFormat[] =
41 "request_content_type=application/json&request=%s&cvn=%s";
42 const char kGetFullWalletRequestFormat[] =
43 "request_content_type=application/json&request=%s&otp=%s:%s";
44 const size_t kOneTimePadLength = 6;
46 // The maximum number of bits in the one time pad that the server is willing to
48 const size_t kMaxBits = 56;
50 // The minimum number of bits in the one time pad that the server is willing to
52 const size_t kMinBits = 40;
54 std::string RiskCapabilityToString(
55 WalletClient::RiskCapability risk_capability) {
56 switch (risk_capability) {
57 case WalletClient::RELOGIN:
59 case WalletClient::VERIFY_CVC:
63 return "NOT_POSSIBLE";
66 WalletClient::ErrorType StringToErrorType(const std::string& error_type) {
68 base::TrimWhitespaceASCII(error_type, base::TRIM_ALL, &trimmed);
69 if (LowerCaseEqualsASCII(trimmed, "buyer_account_error"))
70 return WalletClient::BUYER_ACCOUNT_ERROR;
71 if (LowerCaseEqualsASCII(trimmed, "unsupported_merchant"))
72 return WalletClient::UNSUPPORTED_MERCHANT;
73 if (LowerCaseEqualsASCII(trimmed, "internal_error"))
74 return WalletClient::INTERNAL_ERROR;
75 if (LowerCaseEqualsASCII(trimmed, "invalid_params"))
76 return WalletClient::INVALID_PARAMS;
77 if (LowerCaseEqualsASCII(trimmed, "service_unavailable"))
78 return WalletClient::SERVICE_UNAVAILABLE;
79 if (LowerCaseEqualsASCII(trimmed, "unsupported_api_version"))
80 return WalletClient::UNSUPPORTED_API_VERSION;
81 if (LowerCaseEqualsASCII(trimmed, "unsupported_user_agent"))
82 return WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY;
83 if (LowerCaseEqualsASCII(trimmed, "spending_limit_exceeded"))
84 return WalletClient::SPENDING_LIMIT_EXCEEDED;
86 DVLOG(1) << "Unknown wallet error string: \"" << error_type << '"';
87 return WalletClient::UNKNOWN_ERROR;
90 // Get the more specific WalletClient::ErrorType when the error is
91 // |BUYER_ACCOUNT_ERROR|.
92 WalletClient::ErrorType BuyerErrorStringToErrorType(
93 const std::string& message_type_for_buyer) {
95 base::TrimWhitespaceASCII(message_type_for_buyer, base::TRIM_ALL, &trimmed);
96 if (LowerCaseEqualsASCII(trimmed, "bla_country_not_supported"))
97 return WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
98 if (LowerCaseEqualsASCII(trimmed, "buyer_kyc_error"))
99 return WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
101 return WalletClient::BUYER_ACCOUNT_ERROR;
104 // Gets and parses required actions from a SaveToWallet response. Returns
105 // false if any unknown required actions are seen and true otherwise.
106 void GetRequiredActionsForSaveToWallet(
107 const base::DictionaryValue& dict,
108 std::vector<RequiredAction>* required_actions) {
109 const base::ListValue* required_action_list;
110 if (!dict.GetList("required_action", &required_action_list))
113 for (size_t i = 0; i < required_action_list->GetSize(); ++i) {
114 std::string action_string;
115 if (required_action_list->GetString(i, &action_string)) {
116 RequiredAction action = ParseRequiredActionFromString(action_string);
117 if (!ActionAppliesToSaveToWallet(action)) {
118 DLOG(ERROR) << "Response from Google wallet with bad required action:"
119 " \"" << action_string << "\"";
120 required_actions->clear();
123 required_actions->push_back(action);
128 void GetFormFieldErrors(const base::DictionaryValue& dict,
129 std::vector<FormFieldError>* form_errors) {
130 DCHECK(form_errors->empty());
131 const base::ListValue* form_errors_list;
132 if (!dict.GetList("form_field_error", &form_errors_list))
135 for (size_t i = 0; i < form_errors_list->GetSize(); ++i) {
136 const base::DictionaryValue* dictionary;
137 if (form_errors_list->GetDictionary(i, &dictionary))
138 form_errors->push_back(FormFieldError::CreateFormFieldError(*dictionary));
142 // Converts the |error_type| to the corresponding value from the stable UMA
143 // metric enumeration.
144 AutofillMetrics::WalletErrorMetric ErrorTypeToUmaMetric(
145 WalletClient::ErrorType error_type) {
146 switch (error_type) {
147 case WalletClient::BAD_REQUEST:
148 return AutofillMetrics::WALLET_BAD_REQUEST;
149 case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
150 return AutofillMetrics::WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
151 case WalletClient::BUYER_ACCOUNT_ERROR:
152 return AutofillMetrics::WALLET_BUYER_ACCOUNT_ERROR;
153 case WalletClient::INTERNAL_ERROR:
154 return AutofillMetrics::WALLET_INTERNAL_ERROR;
155 case WalletClient::INVALID_PARAMS:
156 return AutofillMetrics::WALLET_INVALID_PARAMS;
157 case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
158 return AutofillMetrics::WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
159 case WalletClient::SERVICE_UNAVAILABLE:
160 return AutofillMetrics::WALLET_SERVICE_UNAVAILABLE;
161 case WalletClient::UNSUPPORTED_API_VERSION:
162 return AutofillMetrics::WALLET_UNSUPPORTED_API_VERSION;
163 case WalletClient::UNSUPPORTED_MERCHANT:
164 return AutofillMetrics::WALLET_UNSUPPORTED_MERCHANT;
165 case WalletClient::SPENDING_LIMIT_EXCEEDED:
166 return AutofillMetrics::WALLET_SPENDING_LIMIT_EXCEEDED;
167 case WalletClient::MALFORMED_RESPONSE:
168 return AutofillMetrics::WALLET_MALFORMED_RESPONSE;
169 case WalletClient::NETWORK_ERROR:
170 return AutofillMetrics::WALLET_NETWORK_ERROR;
171 case WalletClient::UNKNOWN_ERROR:
172 return AutofillMetrics::WALLET_UNKNOWN_ERROR;
173 case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
174 return AutofillMetrics::WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY;
178 return AutofillMetrics::WALLET_UNKNOWN_ERROR;
181 // Converts the |required_action| to the corresponding value from the stable UMA
182 // metric enumeration.
183 AutofillMetrics::WalletRequiredActionMetric RequiredActionToUmaMetric(
184 RequiredAction required_action) {
185 switch (required_action) {
187 return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
188 case CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
189 return AutofillMetrics::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS;
191 return AutofillMetrics::SETUP_WALLET;
193 return AutofillMetrics::ACCEPT_TOS;
195 return AutofillMetrics::GAIA_AUTH;
196 case UPDATE_EXPIRATION_DATE:
197 return AutofillMetrics::UPDATE_EXPIRATION_DATE;
198 case UPGRADE_MIN_ADDRESS:
199 return AutofillMetrics::UPGRADE_MIN_ADDRESS;
200 case INVALID_FORM_FIELD:
201 return AutofillMetrics::INVALID_FORM_FIELD;
203 return AutofillMetrics::VERIFY_CVV;
204 case PASSIVE_GAIA_AUTH:
205 return AutofillMetrics::PASSIVE_GAIA_AUTH;
206 case REQUIRE_PHONE_NUMBER:
207 return AutofillMetrics::REQUIRE_PHONE_NUMBER;
211 return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
214 // Keys for JSON communication with the Online Wallet server.
215 const char kAcceptedLegalDocumentKey[] = "accepted_legal_document";
216 const char kApiKeyKey[] = "api_key";
217 const char kAuthResultKey[] = "auth_result";
218 const char kErrorTypeKey[] = "wallet_error.error_type";
219 const char kFeatureKey[] = "feature";
220 const char kGoogleTransactionIdKey[] = "google_transaction_id";
221 const char kInstrumentIdKey[] = "instrument_id";
222 const char kInstrumentKey[] = "instrument";
223 const char kInstrumentExpMonthKey[] = "instrument.credit_card.exp_month";
224 const char kInstrumentExpYearKey[] = "instrument.credit_card.exp_year";
225 const char kInstrumentType[] = "instrument.type";
226 const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
227 const char kMerchantDomainKey[] = "merchant_domain";
228 const char kMessageTypeForBuyerKey[] = "wallet_error.message_type_for_buyer";
229 const char kNewWalletUser[] = "new_wallet_user";
230 const char kPhoneNumberRequired[] = "phone_number_required";
231 const char kRiskCapabilitiesKey[] = "supported_risk_challenge";
232 const char kRiskParamsKey[] = "risk_params";
233 const char kSelectedAddressIdKey[] = "selected_address_id";
234 const char kSelectedInstrumentIdKey[] = "selected_instrument_id";
235 const char kShippingAddressIdKey[] = "shipping_address_id";
236 const char kShippingAddressKey[] = "shipping_address";
237 const char kShippingAddressRequired[] = "shipping_address_required";
238 const char kTransactionAmountKey[] = "estimated_total_price";
239 const char kTransactionCurrencyKey[] = "currency_code";
240 const char kUpgradedBillingAddressKey[] = "upgraded_billing_address";
241 const char kUpgradedInstrumentIdKey[] = "upgraded_instrument_id";
242 const char kUseMinimalAddresses[] = "use_minimal_addresses";
246 WalletClient::FullWalletRequest::FullWalletRequest(
247 const std::string& instrument_id,
248 const std::string& address_id,
249 const std::string& google_transaction_id,
250 const std::vector<RiskCapability> risk_capabilities,
251 bool new_wallet_user)
252 : instrument_id(instrument_id),
253 address_id(address_id),
254 google_transaction_id(google_transaction_id),
255 risk_capabilities(risk_capabilities),
256 new_wallet_user(new_wallet_user) {}
258 WalletClient::FullWalletRequest::~FullWalletRequest() {}
260 WalletClient::WalletClient(net::URLRequestContextGetter* context_getter,
261 WalletClientDelegate* delegate,
262 const GURL& source_url)
263 : context_getter_(context_getter),
266 source_url_(source_url),
267 request_type_(NO_REQUEST),
268 one_time_pad_(kOneTimePadLength),
269 weak_ptr_factory_(this) {
270 DCHECK(context_getter_.get());
274 WalletClient::~WalletClient() {}
276 void WalletClient::AcceptLegalDocuments(
277 const std::vector<WalletItems::LegalDocument*>& documents,
278 const std::string& google_transaction_id) {
279 if (documents.empty())
282 std::vector<std::string> document_ids;
283 for (size_t i = 0; i < documents.size(); ++i) {
284 document_ids.push_back(documents[i]->id());
286 DoAcceptLegalDocuments(document_ids, google_transaction_id);
289 void WalletClient::AuthenticateInstrument(
290 const std::string& instrument_id,
291 const std::string& card_verification_number) {
292 base::DictionaryValue request_dict;
293 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
294 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
295 request_dict.SetString(kInstrumentIdKey, instrument_id);
297 std::string json_payload;
298 base::JSONWriter::Write(&request_dict, &json_payload);
300 std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
301 card_verification_number, true);
303 std::string post_body = base::StringPrintf(
304 kEscrowCardVerificationNumberFormat,
305 net::EscapeUrlEncodedData(json_payload, true).c_str(),
306 escaped_card_verification_number.c_str());
308 MakeWalletRequest(GetAuthenticateInstrumentUrl(user_index_),
310 kFormEncodedMimeType,
311 AUTHENTICATE_INSTRUMENT);
314 void WalletClient::GetFullWallet(const FullWalletRequest& full_wallet_request) {
315 base::DictionaryValue request_dict;
316 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
317 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
318 request_dict.SetBoolean(kUseMinimalAddresses, false);
319 request_dict.SetBoolean(kPhoneNumberRequired, true);
320 request_dict.SetBoolean(kNewWalletUser, full_wallet_request.new_wallet_user);
322 request_dict.SetString(kSelectedInstrumentIdKey,
323 full_wallet_request.instrument_id);
324 request_dict.SetString(kSelectedAddressIdKey, full_wallet_request.address_id);
325 request_dict.SetString(
327 source_url_.GetWithEmptyPath().spec());
328 request_dict.SetString(kGoogleTransactionIdKey,
329 full_wallet_request.google_transaction_id);
330 request_dict.SetString(kFeatureKey, "REQUEST_AUTOCOMPLETE");
332 scoped_ptr<base::ListValue> risk_capabilities_list(new base::ListValue());
333 for (std::vector<RiskCapability>::const_iterator it =
334 full_wallet_request.risk_capabilities.begin();
335 it != full_wallet_request.risk_capabilities.end();
337 risk_capabilities_list->AppendString(RiskCapabilityToString(*it));
339 request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
341 std::string json_payload;
342 base::JSONWriter::Write(&request_dict, &json_payload);
344 crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
346 size_t num_bits = one_time_pad_.size() * 8;
347 DCHECK_LE(num_bits, kMaxBits);
348 DCHECK_GE(num_bits, kMinBits);
350 std::string post_body = base::StringPrintf(
351 kGetFullWalletRequestFormat,
352 net::EscapeUrlEncodedData(json_payload, true).c_str(),
353 base::HexEncode(&num_bits, 1).c_str(),
354 base::HexEncode(&(one_time_pad_[0]), one_time_pad_.size()).c_str());
356 MakeWalletRequest(GetGetFullWalletUrl(user_index_),
358 kFormEncodedMimeType,
362 void WalletClient::SaveToWallet(
363 scoped_ptr<Instrument> instrument,
364 scoped_ptr<Address> address,
365 const WalletItems::MaskedInstrument* reference_instrument,
366 const Address* reference_address) {
367 DCHECK(instrument || address);
369 base::DictionaryValue request_dict;
370 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
371 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
372 request_dict.SetString(kMerchantDomainKey,
373 source_url_.GetWithEmptyPath().spec());
374 request_dict.SetBoolean(kUseMinimalAddresses, false);
375 request_dict.SetBoolean(kPhoneNumberRequired, true);
377 std::string primary_account_number;
378 std::string card_verification_number;
380 primary_account_number = net::EscapeUrlEncodedData(
381 base::UTF16ToUTF8(instrument->primary_account_number()), true);
382 card_verification_number = net::EscapeUrlEncodedData(
383 base::UTF16ToUTF8(instrument->card_verification_number()), true);
385 if (!reference_instrument) {
386 request_dict.Set(kInstrumentKey, instrument->ToDictionary().release());
387 request_dict.SetString(kInstrumentPhoneNumberKey,
388 instrument->address()->phone_number());
390 DCHECK(!reference_instrument->object_id().empty());
392 int new_month = instrument->expiration_month();
393 int new_year = instrument->expiration_year();
394 bool expiration_date_changed =
395 new_month != reference_instrument->expiration_month() ||
396 new_year != reference_instrument->expiration_year();
398 DCHECK(instrument->address() || expiration_date_changed);
400 request_dict.SetString(kUpgradedInstrumentIdKey,
401 reference_instrument->object_id());
403 if (instrument->address()) {
404 request_dict.SetString(kInstrumentPhoneNumberKey,
405 instrument->address()->phone_number());
407 kUpgradedBillingAddressKey,
408 instrument->address()->ToDictionaryWithoutID().release());
411 if (expiration_date_changed) {
412 // Updating expiration date requires a CVC.
413 DCHECK(!instrument->card_verification_number().empty());
414 request_dict.SetInteger(kInstrumentExpMonthKey,
415 instrument->expiration_month());
416 request_dict.SetInteger(kInstrumentExpYearKey,
417 instrument->expiration_year());
420 if (request_dict.HasKey(kInstrumentKey))
421 request_dict.SetString(kInstrumentType, "CREDIT_CARD");
425 if (reference_address) {
426 address->set_object_id(reference_address->object_id());
427 DCHECK(!address->object_id().empty());
429 request_dict.Set(kShippingAddressKey,
430 address->ToDictionaryWithID().release());
433 std::string json_payload;
434 base::JSONWriter::Write(&request_dict, &json_payload);
436 if (!card_verification_number.empty()) {
437 std::string post_body;
438 if (!primary_account_number.empty()) {
439 post_body = base::StringPrintf(
440 kEscrowNewInstrumentFormat,
441 net::EscapeUrlEncodedData(json_payload, true).c_str(),
442 card_verification_number.c_str(),
443 primary_account_number.c_str());
445 post_body = base::StringPrintf(
446 kEscrowCardVerificationNumberFormat,
447 net::EscapeUrlEncodedData(json_payload, true).c_str(),
448 card_verification_number.c_str());
450 MakeWalletRequest(GetSaveToWalletUrl(user_index_),
452 kFormEncodedMimeType,
455 MakeWalletRequest(GetSaveToWalletNoEscrowUrl(user_index_),
462 void WalletClient::GetWalletItems(const base::string16& amount,
463 const base::string16& currency) {
464 base::DictionaryValue request_dict;
465 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
466 request_dict.SetString(kMerchantDomainKey,
467 source_url_.GetWithEmptyPath().spec());
468 request_dict.SetBoolean(kShippingAddressRequired,
469 delegate_->IsShippingAddressRequired());
470 request_dict.SetBoolean(kUseMinimalAddresses, false);
471 request_dict.SetBoolean(kPhoneNumberRequired, true);
474 request_dict.SetString(kTransactionAmountKey, amount);
475 if (!currency.empty())
476 request_dict.SetString(kTransactionCurrencyKey, currency);
478 std::string post_body;
479 base::JSONWriter::Write(&request_dict, &post_body);
481 MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
487 bool WalletClient::HasRequestInProgress() const {
491 void WalletClient::CancelRequest() {
493 request_type_ = NO_REQUEST;
496 void WalletClient::SetUserIndex(size_t user_index) {
498 user_index_ = user_index;
501 void WalletClient::DoAcceptLegalDocuments(
502 const std::vector<std::string>& document_ids,
503 const std::string& google_transaction_id) {
504 base::DictionaryValue request_dict;
505 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
506 request_dict.SetString(kGoogleTransactionIdKey, google_transaction_id);
507 request_dict.SetString(kMerchantDomainKey,
508 source_url_.GetWithEmptyPath().spec());
509 scoped_ptr<base::ListValue> docs_list(new base::ListValue());
510 for (std::vector<std::string>::const_iterator it = document_ids.begin();
511 it != document_ids.end(); ++it) {
513 docs_list->AppendString(*it);
515 request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
517 std::string post_body;
518 base::JSONWriter::Write(&request_dict, &post_body);
520 MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
523 ACCEPT_LEGAL_DOCUMENTS);
526 void WalletClient::MakeWalletRequest(const GURL& url,
527 const std::string& post_body,
528 const std::string& mime_type,
529 RequestType request_type) {
530 DCHECK_EQ(request_type_, NO_REQUEST);
531 request_type_ = request_type;
533 request_.reset(net::URLFetcher::Create(
534 0, url, net::URLFetcher::POST, this));
535 request_->SetRequestContext(context_getter_.get());
536 DVLOG(1) << "Making request to " << url << " with post_body=" << post_body;
537 request_->SetUploadData(mime_type, post_body);
538 request_->AddExtraRequestHeader("Authorization: GoogleLogin auth=" +
539 delegate_->GetWalletCookieValue());
540 DVLOG(1) << "Setting authorization header value to "
541 << delegate_->GetWalletCookieValue();
542 request_started_timestamp_ = base::Time::Now();
545 delegate_->GetMetricLogger().LogWalletErrorMetric(
546 AutofillMetrics::WALLET_ERROR_BASELINE_ISSUED_REQUEST);
547 delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
548 AutofillMetrics::WALLET_REQUIRED_ACTION_BASELINE_ISSUED_REQUEST);
551 // TODO(ahutter): Add manual retry logic if it's necessary.
552 void WalletClient::OnURLFetchComplete(
553 const net::URLFetcher* source) {
554 delegate_->GetMetricLogger().LogWalletApiCallDuration(
555 RequestTypeToUmaMetric(request_type_),
556 base::Time::Now() - request_started_timestamp_);
558 DCHECK_EQ(source, request_.get());
559 DVLOG(1) << "Got response from " << source->GetOriginalURL();
561 // |request_|, which is aliased to |source|, might continue to be used in this
562 // |method, but should be freed once control leaves the method.
563 scoped_ptr<net::URLFetcher> scoped_request(request_.Pass());
566 source->GetResponseAsString(&data);
567 DVLOG(1) << "Response body: " << data;
569 scoped_ptr<base::DictionaryValue> response_dict;
571 int response_code = source->GetResponseCode();
572 delegate_->GetMetricLogger().LogWalletResponseCode(response_code);
574 switch (response_code) {
575 // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
576 case net::HTTP_BAD_REQUEST: {
577 request_type_ = NO_REQUEST;
578 HandleWalletError(BAD_REQUEST);
581 // HTTP_OK holds a valid response and HTTP_INTERNAL_SERVER_ERROR holds an
582 // error code and message for the user.
584 case net::HTTP_INTERNAL_SERVER_ERROR: {
585 scoped_ptr<base::Value> message_value(base::JSONReader::Read(data));
586 if (message_value.get() &&
587 message_value->IsType(base::Value::TYPE_DICTIONARY)) {
589 static_cast<base::DictionaryValue*>(message_value.release()));
591 if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
592 request_type_ = NO_REQUEST;
594 std::string error_type_string;
595 if (!response_dict->GetString(kErrorTypeKey, &error_type_string)) {
596 HandleWalletError(UNKNOWN_ERROR);
599 WalletClient::ErrorType error_type =
600 StringToErrorType(error_type_string);
601 if (error_type == BUYER_ACCOUNT_ERROR) {
602 // If the error_type is |BUYER_ACCOUNT_ERROR|, then
603 // message_type_for_buyer field contains more specific information
605 std::string message_type_for_buyer_string;
606 if (response_dict->GetString(kMessageTypeForBuyerKey,
607 &message_type_for_buyer_string)) {
608 error_type = BuyerErrorStringToErrorType(
609 message_type_for_buyer_string);
613 HandleWalletError(error_type);
619 // Anything else is an error.
621 request_type_ = NO_REQUEST;
622 HandleWalletError(NETWORK_ERROR);
626 RequestType type = request_type_;
627 request_type_ = NO_REQUEST;
629 if (type != ACCEPT_LEGAL_DOCUMENTS && !response_dict) {
630 HandleMalformedResponse(type, scoped_request.get());
635 case ACCEPT_LEGAL_DOCUMENTS:
636 delegate_->OnDidAcceptLegalDocuments();
639 case AUTHENTICATE_INSTRUMENT: {
640 std::string auth_result;
641 if (response_dict->GetString(kAuthResultKey, &auth_result)) {
643 base::TrimWhitespaceASCII(auth_result, base::TRIM_ALL, &trimmed);
644 delegate_->OnDidAuthenticateInstrument(
645 LowerCaseEqualsASCII(trimmed, "success"));
647 HandleMalformedResponse(type, scoped_request.get());
652 case GET_FULL_WALLET: {
653 scoped_ptr<FullWallet> full_wallet(
654 FullWallet::CreateFullWallet(*response_dict));
656 full_wallet->set_one_time_pad(one_time_pad_);
657 LogRequiredActions(full_wallet->required_actions());
658 delegate_->OnDidGetFullWallet(full_wallet.Pass());
660 HandleMalformedResponse(type, scoped_request.get());
665 case GET_WALLET_ITEMS: {
666 scoped_ptr<WalletItems> wallet_items(
667 WalletItems::CreateWalletItems(*response_dict));
669 LogRequiredActions(wallet_items->required_actions());
670 delegate_->OnDidGetWalletItems(wallet_items.Pass());
672 HandleMalformedResponse(type, scoped_request.get());
677 case SAVE_TO_WALLET: {
678 std::string instrument_id;
679 response_dict->GetString(kInstrumentIdKey, &instrument_id);
680 std::string shipping_address_id;
681 response_dict->GetString(kShippingAddressIdKey,
682 &shipping_address_id);
683 std::vector<RequiredAction> required_actions;
684 GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
685 std::vector<FormFieldError> form_errors;
686 GetFormFieldErrors(*response_dict, &form_errors);
687 if (instrument_id.empty() && shipping_address_id.empty() &&
688 required_actions.empty()) {
689 HandleMalformedResponse(type, scoped_request.get());
691 LogRequiredActions(required_actions);
692 delegate_->OnDidSaveToWallet(instrument_id,
705 void WalletClient::HandleMalformedResponse(RequestType request_type,
706 net::URLFetcher* request) {
707 // Called to inform exponential backoff logic of the error.
708 request->ReceivedContentWasMalformed();
709 // Record failed API call in metrics.
710 delegate_->GetMetricLogger().LogWalletMalformedResponseMetric(
711 RequestTypeToUmaMetric(request_type));
712 HandleWalletError(MALFORMED_RESPONSE);
715 void WalletClient::HandleWalletError(WalletClient::ErrorType error_type) {
716 std::string error_message;
717 switch (error_type) {
718 case WalletClient::BAD_REQUEST:
719 error_message = "WALLET_BAD_REQUEST";
721 case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
722 error_message = "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
724 case WalletClient::BUYER_ACCOUNT_ERROR:
725 error_message = "WALLET_BUYER_ACCOUNT_ERROR";
727 case WalletClient::INTERNAL_ERROR:
728 error_message = "WALLET_INTERNAL_ERROR";
730 case WalletClient::INVALID_PARAMS:
731 error_message = "WALLET_INVALID_PARAMS";
733 case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
734 error_message = "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
736 case WalletClient::SPENDING_LIMIT_EXCEEDED:
737 error_message = "SPENDING_LIMIT_EXCEEDED";
739 case WalletClient::SERVICE_UNAVAILABLE:
740 error_message = "WALLET_SERVICE_UNAVAILABLE";
742 case WalletClient::UNSUPPORTED_API_VERSION:
743 error_message = "WALLET_UNSUPPORTED_API_VERSION";
745 case WalletClient::UNSUPPORTED_MERCHANT:
746 error_message = "WALLET_UNSUPPORTED_MERCHANT";
748 case WalletClient::MALFORMED_RESPONSE:
749 error_message = "WALLET_MALFORMED_RESPONSE";
751 case WalletClient::NETWORK_ERROR:
752 error_message = "WALLET_NETWORK_ERROR";
754 case WalletClient::UNKNOWN_ERROR:
755 error_message = "WALLET_UNKNOWN_ERROR";
757 case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
758 error_message = "WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY";
762 DVLOG(1) << "Wallet encountered a " << error_message;
764 delegate_->OnWalletError(error_type);
765 delegate_->GetMetricLogger().LogWalletErrorMetric(
766 ErrorTypeToUmaMetric(error_type));
769 // Logs an UMA metric for each of the |required_actions|.
770 void WalletClient::LogRequiredActions(
771 const std::vector<RequiredAction>& required_actions) const {
772 for (size_t i = 0; i < required_actions.size(); ++i) {
773 delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
774 RequiredActionToUmaMetric(required_actions[i]));
778 AutofillMetrics::WalletApiCallMetric WalletClient::RequestTypeToUmaMetric(
779 RequestType request_type) const {
780 switch (request_type) {
781 case ACCEPT_LEGAL_DOCUMENTS:
782 return AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS;
783 case AUTHENTICATE_INSTRUMENT:
784 return AutofillMetrics::AUTHENTICATE_INSTRUMENT;
785 case GET_FULL_WALLET:
786 return AutofillMetrics::GET_FULL_WALLET;
787 case GET_WALLET_ITEMS:
788 return AutofillMetrics::GET_WALLET_ITEMS;
790 return AutofillMetrics::SAVE_TO_WALLET;
793 return AutofillMetrics::UNKNOWN_API_CALL;
797 return AutofillMetrics::UNKNOWN_API_CALL;
800 } // namespace wallet
801 } // namespace autofill