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"
31 // TODO(ahutter): Change all VLOGs to DVLOGs after dogfood.
37 const char kFormEncodedMimeType[] = "application/x-www-form-urlencoded";
38 const char kJsonMimeType[] = "application/json";
39 const char kEscrowNewInstrumentFormat[] =
40 "request_content_type=application/json&request=%s&cvn=%s&card_number=%s";
41 const char kEscrowCardVerificationNumberFormat[] =
42 "request_content_type=application/json&request=%s&cvn=%s";
43 const char kGetFullWalletRequestFormat[] =
44 "request_content_type=application/json&request=%s&otp=%s:%s";
45 const size_t kOneTimePadLength = 6;
47 // The maximum number of bits in the one time pad that the server is willing to
49 const size_t kMaxBits = 56;
51 // The minimum number of bits in the one time pad that the server is willing to
53 const size_t kMinBits = 40;
55 std::string RiskCapabilityToString(
56 WalletClient::RiskCapability risk_capability) {
57 switch (risk_capability) {
58 case WalletClient::RELOGIN:
60 case WalletClient::VERIFY_CVC:
64 return "NOT_POSSIBLE";
67 WalletClient::ErrorType StringToErrorType(const std::string& error_type) {
69 TrimWhitespaceASCII(error_type,
72 if (LowerCaseEqualsASCII(trimmed, "buyer_account_error"))
73 return WalletClient::BUYER_ACCOUNT_ERROR;
74 if (LowerCaseEqualsASCII(trimmed, "unsupported_merchant"))
75 return WalletClient::UNSUPPORTED_MERCHANT;
76 if (LowerCaseEqualsASCII(trimmed, "internal_error"))
77 return WalletClient::INTERNAL_ERROR;
78 if (LowerCaseEqualsASCII(trimmed, "invalid_params"))
79 return WalletClient::INVALID_PARAMS;
80 if (LowerCaseEqualsASCII(trimmed, "service_unavailable"))
81 return WalletClient::SERVICE_UNAVAILABLE;
82 if (LowerCaseEqualsASCII(trimmed, "unsupported_api_version"))
83 return WalletClient::UNSUPPORTED_API_VERSION;
85 return WalletClient::UNKNOWN_ERROR;
88 // Get the more specific WalletClient::ErrorType when the error is
89 // |BUYER_ACCOUNT_ERROR|.
90 WalletClient::ErrorType BuyerErrorStringToErrorType(
91 const std::string& message_type_for_buyer) {
93 TrimWhitespaceASCII(message_type_for_buyer,
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::MALFORMED_RESPONSE:
166 return AutofillMetrics::WALLET_MALFORMED_RESPONSE;
167 case WalletClient::NETWORK_ERROR:
168 return AutofillMetrics::WALLET_NETWORK_ERROR;
169 case WalletClient::UNKNOWN_ERROR:
170 return AutofillMetrics::WALLET_UNKNOWN_ERROR;
174 return AutofillMetrics::WALLET_UNKNOWN_ERROR;
177 // Converts the |required_action| to the corresponding value from the stable UMA
178 // metric enumeration.
179 AutofillMetrics::WalletRequiredActionMetric RequiredActionToUmaMetric(
180 RequiredAction required_action) {
181 switch (required_action) {
183 return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
184 case CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
185 return AutofillMetrics::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS;
187 return AutofillMetrics::SETUP_WALLET;
189 return AutofillMetrics::ACCEPT_TOS;
191 return AutofillMetrics::GAIA_AUTH;
192 case UPDATE_EXPIRATION_DATE:
193 return AutofillMetrics::UPDATE_EXPIRATION_DATE;
194 case UPGRADE_MIN_ADDRESS:
195 return AutofillMetrics::UPGRADE_MIN_ADDRESS;
196 case INVALID_FORM_FIELD:
197 return AutofillMetrics::INVALID_FORM_FIELD;
199 return AutofillMetrics::VERIFY_CVV;
200 case PASSIVE_GAIA_AUTH:
201 return AutofillMetrics::PASSIVE_GAIA_AUTH;
202 case REQUIRE_PHONE_NUMBER:
203 return AutofillMetrics::REQUIRE_PHONE_NUMBER;
207 return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
210 // Keys for JSON communication with the Online Wallet server.
211 const char kAcceptedLegalDocumentKey[] = "accepted_legal_document";
212 const char kApiKeyKey[] = "api_key";
213 const char kAuthResultKey[] = "auth_result";
214 const char kErrorTypeKey[] = "wallet_error.error_type";
215 const char kFeatureKey[] = "feature";
216 const char kGoogleTransactionIdKey[] = "google_transaction_id";
217 const char kInstrumentIdKey[] = "instrument_id";
218 const char kInstrumentKey[] = "instrument";
219 const char kInstrumentExpMonthKey[] = "instrument.credit_card.exp_month";
220 const char kInstrumentExpYearKey[] = "instrument.credit_card.exp_year";
221 const char kInstrumentType[] = "instrument.type";
222 const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
223 const char kMerchantDomainKey[] = "merchant_domain";
224 const char kMessageTypeForBuyerKey[] = "wallet_error.message_type_for_buyer";
225 const char kNewWalletUser[] = "new_wallet_user";
226 const char kPhoneNumberRequired[] = "phone_number_required";
227 const char kRiskCapabilitiesKey[] = "supported_risk_challenge";
228 const char kRiskParamsKey[] = "risk_params";
229 const char kSelectedAddressIdKey[] = "selected_address_id";
230 const char kSelectedInstrumentIdKey[] = "selected_instrument_id";
231 const char kShippingAddressIdKey[] = "shipping_address_id";
232 const char kShippingAddressKey[] = "shipping_address";
233 const char kShippingAddressRequired[] = "shipping_address_required";
234 const char kUpgradedBillingAddressKey[] = "upgraded_billing_address";
235 const char kUpgradedInstrumentIdKey[] = "upgraded_instrument_id";
236 const char kUseMinimalAddresses[] = "use_minimal_addresses";
240 WalletClient::FullWalletRequest::FullWalletRequest(
241 const std::string& instrument_id,
242 const std::string& address_id,
243 const std::string& google_transaction_id,
244 const std::vector<RiskCapability> risk_capabilities,
245 bool new_wallet_user)
246 : instrument_id(instrument_id),
247 address_id(address_id),
248 google_transaction_id(google_transaction_id),
249 risk_capabilities(risk_capabilities),
250 new_wallet_user(new_wallet_user) {}
252 WalletClient::FullWalletRequest::~FullWalletRequest() {}
254 WalletClient::WalletClient(net::URLRequestContextGetter* context_getter,
255 WalletClientDelegate* delegate,
256 const GURL& source_url)
257 : context_getter_(context_getter),
260 source_url_(source_url),
261 request_type_(NO_PENDING_REQUEST),
262 one_time_pad_(kOneTimePadLength),
263 weak_ptr_factory_(this) {
264 DCHECK(context_getter_.get());
268 WalletClient::~WalletClient() {}
270 void WalletClient::AcceptLegalDocuments(
271 const std::vector<WalletItems::LegalDocument*>& documents,
272 const std::string& google_transaction_id) {
273 if (documents.empty())
276 std::vector<std::string> document_ids;
277 for (size_t i = 0; i < documents.size(); ++i) {
278 document_ids.push_back(documents[i]->id());
280 DoAcceptLegalDocuments(document_ids, google_transaction_id);
283 void WalletClient::AuthenticateInstrument(
284 const std::string& instrument_id,
285 const std::string& card_verification_number) {
286 if (HasRequestInProgress()) {
287 pending_requests_.push(base::Bind(&WalletClient::AuthenticateInstrument,
288 base::Unretained(this),
290 card_verification_number));
294 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
295 request_type_ = AUTHENTICATE_INSTRUMENT;
297 base::DictionaryValue request_dict;
298 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
299 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
300 request_dict.SetString(kInstrumentIdKey, instrument_id);
302 std::string json_payload;
303 base::JSONWriter::Write(&request_dict, &json_payload);
305 std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
306 card_verification_number, true);
308 std::string post_body = base::StringPrintf(
309 kEscrowCardVerificationNumberFormat,
310 net::EscapeUrlEncodedData(json_payload, true).c_str(),
311 escaped_card_verification_number.c_str());
313 MakeWalletRequest(GetAuthenticateInstrumentUrl(user_index_),
315 kFormEncodedMimeType);
318 void WalletClient::GetFullWallet(const FullWalletRequest& full_wallet_request) {
319 if (HasRequestInProgress()) {
320 pending_requests_.push(base::Bind(&WalletClient::GetFullWallet,
321 base::Unretained(this),
322 full_wallet_request));
326 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
327 request_type_ = GET_FULL_WALLET;
329 base::DictionaryValue request_dict;
330 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
331 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
332 request_dict.SetBoolean(kUseMinimalAddresses, false);
333 request_dict.SetBoolean(kPhoneNumberRequired, true);
334 request_dict.SetBoolean(kNewWalletUser, full_wallet_request.new_wallet_user);
336 request_dict.SetString(kSelectedInstrumentIdKey,
337 full_wallet_request.instrument_id);
338 request_dict.SetString(kSelectedAddressIdKey, full_wallet_request.address_id);
339 request_dict.SetString(
341 source_url_.GetWithEmptyPath().spec());
342 request_dict.SetString(kGoogleTransactionIdKey,
343 full_wallet_request.google_transaction_id);
344 request_dict.SetString(kFeatureKey, "REQUEST_AUTOCOMPLETE");
346 scoped_ptr<base::ListValue> risk_capabilities_list(new base::ListValue());
347 for (std::vector<RiskCapability>::const_iterator it =
348 full_wallet_request.risk_capabilities.begin();
349 it != full_wallet_request.risk_capabilities.end();
351 risk_capabilities_list->AppendString(RiskCapabilityToString(*it));
353 request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
355 std::string json_payload;
356 base::JSONWriter::Write(&request_dict, &json_payload);
358 crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
360 size_t num_bits = one_time_pad_.size() * 8;
361 DCHECK_LE(num_bits, kMaxBits);
362 DCHECK_GE(num_bits, kMinBits);
364 std::string post_body = base::StringPrintf(
365 kGetFullWalletRequestFormat,
366 net::EscapeUrlEncodedData(json_payload, true).c_str(),
367 base::HexEncode(&num_bits, 1).c_str(),
368 base::HexEncode(&(one_time_pad_[0]), one_time_pad_.size()).c_str());
370 MakeWalletRequest(GetGetFullWalletUrl(user_index_),
372 kFormEncodedMimeType);
375 void WalletClient::SaveToWallet(scoped_ptr<Instrument> instrument,
376 scoped_ptr<Address> address) {
377 DCHECK(instrument || address);
378 if (HasRequestInProgress()) {
379 pending_requests_.push(base::Bind(&WalletClient::SaveToWallet,
380 base::Unretained(this),
381 base::Passed(&instrument),
382 base::Passed(&address)));
386 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
387 request_type_ = SAVE_TO_WALLET;
389 base::DictionaryValue request_dict;
390 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
391 request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
392 request_dict.SetString(kMerchantDomainKey,
393 source_url_.GetWithEmptyPath().spec());
394 request_dict.SetBoolean(kUseMinimalAddresses, false);
395 request_dict.SetBoolean(kPhoneNumberRequired, true);
397 std::string primary_account_number;
398 std::string card_verification_number;
400 primary_account_number = net::EscapeUrlEncodedData(
401 UTF16ToUTF8(instrument->primary_account_number()), true);
402 card_verification_number = net::EscapeUrlEncodedData(
403 UTF16ToUTF8(instrument->card_verification_number()), true);
405 if (instrument->object_id().empty()) {
406 request_dict.Set(kInstrumentKey, instrument->ToDictionary().release());
407 request_dict.SetString(kInstrumentPhoneNumberKey,
408 instrument->address()->phone_number());
410 DCHECK(instrument->address() ||
411 (instrument->expiration_month() > 0 &&
412 instrument->expiration_year() > 0));
414 request_dict.SetString(kUpgradedInstrumentIdKey,
415 instrument->object_id());
417 if (instrument->address()) {
418 request_dict.SetString(kInstrumentPhoneNumberKey,
419 instrument->address()->phone_number());
421 kUpgradedBillingAddressKey,
422 instrument->address()->ToDictionaryWithoutID().release());
425 if (instrument->expiration_month() > 0 &&
426 instrument->expiration_year() > 0) {
427 DCHECK(!instrument->card_verification_number().empty());
428 request_dict.SetInteger(kInstrumentExpMonthKey,
429 instrument->expiration_month());
430 request_dict.SetInteger(kInstrumentExpYearKey,
431 instrument->expiration_year());
434 if (request_dict.HasKey(kInstrumentKey))
435 request_dict.SetString(kInstrumentType, "CREDIT_CARD");
439 request_dict.Set(kShippingAddressKey,
440 address->ToDictionaryWithID().release());
443 std::string json_payload;
444 base::JSONWriter::Write(&request_dict, &json_payload);
446 if (!card_verification_number.empty()) {
447 std::string post_body;
448 if (!primary_account_number.empty()) {
449 post_body = base::StringPrintf(
450 kEscrowNewInstrumentFormat,
451 net::EscapeUrlEncodedData(json_payload, true).c_str(),
452 card_verification_number.c_str(),
453 primary_account_number.c_str());
455 post_body = base::StringPrintf(
456 kEscrowCardVerificationNumberFormat,
457 net::EscapeUrlEncodedData(json_payload, true).c_str(),
458 card_verification_number.c_str());
460 MakeWalletRequest(GetSaveToWalletUrl(user_index_),
462 kFormEncodedMimeType);
464 MakeWalletRequest(GetSaveToWalletNoEscrowUrl(user_index_),
470 void WalletClient::GetWalletItems() {
471 if (HasRequestInProgress()) {
472 pending_requests_.push(base::Bind(&WalletClient::GetWalletItems,
473 base::Unretained(this)));
477 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
478 request_type_ = GET_WALLET_ITEMS;
480 base::DictionaryValue request_dict;
481 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
482 request_dict.SetString(kMerchantDomainKey,
483 source_url_.GetWithEmptyPath().spec());
484 request_dict.SetBoolean(kShippingAddressRequired,
485 delegate_->IsShippingAddressRequired());
486 request_dict.SetBoolean(kUseMinimalAddresses, false);
487 request_dict.SetBoolean(kPhoneNumberRequired, true);
489 std::string post_body;
490 base::JSONWriter::Write(&request_dict, &post_body);
492 MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
497 bool WalletClient::HasRequestInProgress() const {
501 void WalletClient::CancelRequests() {
503 request_type_ = NO_PENDING_REQUEST;
504 while (!pending_requests_.empty()) {
505 pending_requests_.pop();
509 void WalletClient::DoAcceptLegalDocuments(
510 const std::vector<std::string>& document_ids,
511 const std::string& google_transaction_id) {
512 if (HasRequestInProgress()) {
513 pending_requests_.push(base::Bind(&WalletClient::DoAcceptLegalDocuments,
514 base::Unretained(this),
516 google_transaction_id));
520 DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
521 request_type_ = ACCEPT_LEGAL_DOCUMENTS;
523 base::DictionaryValue request_dict;
524 request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
525 request_dict.SetString(kGoogleTransactionIdKey, google_transaction_id);
526 request_dict.SetString(kMerchantDomainKey,
527 source_url_.GetWithEmptyPath().spec());
528 scoped_ptr<base::ListValue> docs_list(new base::ListValue());
529 for (std::vector<std::string>::const_iterator it = document_ids.begin();
530 it != document_ids.end(); ++it) {
532 docs_list->AppendString(*it);
534 request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
536 std::string post_body;
537 base::JSONWriter::Write(&request_dict, &post_body);
539 MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
544 void WalletClient::MakeWalletRequest(const GURL& url,
545 const std::string& post_body,
546 const std::string& mime_type) {
547 DCHECK(!HasRequestInProgress());
549 request_.reset(net::URLFetcher::Create(
550 0, url, net::URLFetcher::POST, this));
551 request_->SetRequestContext(context_getter_.get());
552 VLOG(1) << "Making request to " << url << " with post_body=" << post_body;
553 request_->SetUploadData(mime_type, post_body);
554 request_->AddExtraRequestHeader("Authorization: GoogleLogin auth=" +
555 delegate_->GetWalletCookieValue());
556 DVLOG(1) << "Setting authorization header value to "
557 << delegate_->GetWalletCookieValue();
558 request_started_timestamp_ = base::Time::Now();
561 delegate_->GetMetricLogger().LogWalletErrorMetric(
562 AutofillMetrics::WALLET_ERROR_BASELINE_ISSUED_REQUEST);
563 delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
564 AutofillMetrics::WALLET_REQUIRED_ACTION_BASELINE_ISSUED_REQUEST);
567 // TODO(ahutter): Add manual retry logic if it's necessary.
568 void WalletClient::OnURLFetchComplete(
569 const net::URLFetcher* source) {
570 delegate_->GetMetricLogger().LogWalletApiCallDuration(
571 RequestTypeToUmaMetric(request_type_),
572 base::Time::Now() - request_started_timestamp_);
574 DCHECK_EQ(source, request_.get());
575 VLOG(1) << "Got response from " << source->GetOriginalURL();
577 // |request_|, which is aliased to |source|, might continue to be used in this
578 // |method, but should be freed once control leaves the method.
579 scoped_ptr<net::URLFetcher> scoped_request(request_.Pass());
581 // Prepare to start the next pending request. This is queued up as an
582 // asynchronous message because |this| WalletClient instance can be destroyed
583 // before the end of the method in response to the current incoming request.
584 base::MessageLoop::current()->PostTask(
586 base::Bind(&WalletClient::StartNextPendingRequest,
587 weak_ptr_factory_.GetWeakPtr()));;
590 source->GetResponseAsString(&data);
591 VLOG(1) << "Response body: " << data;
593 scoped_ptr<base::DictionaryValue> response_dict;
595 int response_code = source->GetResponseCode();
596 delegate_->GetMetricLogger().LogWalletResponseCode(response_code);
598 switch (response_code) {
599 // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
600 case net::HTTP_BAD_REQUEST: {
601 request_type_ = NO_PENDING_REQUEST;
602 HandleWalletError(BAD_REQUEST);
605 // HTTP_OK holds a valid response and HTTP_INTERNAL_SERVER_ERROR holds an
606 // error code and message for the user.
608 case net::HTTP_INTERNAL_SERVER_ERROR: {
609 scoped_ptr<Value> message_value(base::JSONReader::Read(data));
610 if (message_value.get() &&
611 message_value->IsType(Value::TYPE_DICTIONARY)) {
613 static_cast<base::DictionaryValue*>(message_value.release()));
615 if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
616 request_type_ = NO_PENDING_REQUEST;
618 std::string error_type_string;
619 if (!response_dict->GetString(kErrorTypeKey, &error_type_string)) {
620 HandleWalletError(UNKNOWN_ERROR);
623 WalletClient::ErrorType error_type =
624 StringToErrorType(error_type_string);
625 if (error_type == BUYER_ACCOUNT_ERROR) {
626 // If the error_type is |BUYER_ACCOUNT_ERROR|, then
627 // message_type_for_buyer field contains more specific information
629 std::string message_type_for_buyer_string;
630 if (response_dict->GetString(kMessageTypeForBuyerKey,
631 &message_type_for_buyer_string)) {
632 error_type = BuyerErrorStringToErrorType(
633 message_type_for_buyer_string);
637 HandleWalletError(error_type);
643 // Anything else is an error.
645 request_type_ = NO_PENDING_REQUEST;
646 HandleWalletError(NETWORK_ERROR);
650 RequestType type = request_type_;
651 request_type_ = NO_PENDING_REQUEST;
653 if (type != ACCEPT_LEGAL_DOCUMENTS && !response_dict) {
654 HandleMalformedResponse(type, scoped_request.get());
659 case ACCEPT_LEGAL_DOCUMENTS:
660 delegate_->OnDidAcceptLegalDocuments();
663 case AUTHENTICATE_INSTRUMENT: {
664 std::string auth_result;
665 if (response_dict->GetString(kAuthResultKey, &auth_result)) {
667 TrimWhitespaceASCII(auth_result,
670 delegate_->OnDidAuthenticateInstrument(
671 LowerCaseEqualsASCII(trimmed, "success"));
673 HandleMalformedResponse(type, scoped_request.get());
678 case GET_FULL_WALLET: {
679 scoped_ptr<FullWallet> full_wallet(
680 FullWallet::CreateFullWallet(*response_dict));
682 full_wallet->set_one_time_pad(one_time_pad_);
683 LogRequiredActions(full_wallet->required_actions());
684 delegate_->OnDidGetFullWallet(full_wallet.Pass());
686 HandleMalformedResponse(type, scoped_request.get());
691 case GET_WALLET_ITEMS: {
692 scoped_ptr<WalletItems> wallet_items(
693 WalletItems::CreateWalletItems(*response_dict));
695 LogRequiredActions(wallet_items->required_actions());
696 delegate_->OnDidGetWalletItems(wallet_items.Pass());
698 HandleMalformedResponse(type, scoped_request.get());
703 case SAVE_TO_WALLET: {
704 std::string instrument_id;
705 response_dict->GetString(kInstrumentIdKey, &instrument_id);
706 std::string shipping_address_id;
707 response_dict->GetString(kShippingAddressIdKey,
708 &shipping_address_id);
709 std::vector<RequiredAction> required_actions;
710 GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
711 std::vector<FormFieldError> form_errors;
712 GetFormFieldErrors(*response_dict, &form_errors);
713 if (instrument_id.empty() && shipping_address_id.empty() &&
714 required_actions.empty()) {
715 HandleMalformedResponse(type, scoped_request.get());
717 LogRequiredActions(required_actions);
718 delegate_->OnDidSaveToWallet(instrument_id,
726 case NO_PENDING_REQUEST:
731 void WalletClient::StartNextPendingRequest() {
732 if (pending_requests_.empty())
735 base::Closure next_request = pending_requests_.front();
736 pending_requests_.pop();
740 void WalletClient::HandleMalformedResponse(RequestType request_type,
741 net::URLFetcher* request) {
742 // Called to inform exponential backoff logic of the error.
743 request->ReceivedContentWasMalformed();
744 // Record failed API call in metrics.
745 delegate_->GetMetricLogger().LogWalletMalformedResponseMetric(
746 RequestTypeToUmaMetric(request_type));
747 HandleWalletError(MALFORMED_RESPONSE);
750 void WalletClient::HandleWalletError(WalletClient::ErrorType error_type) {
751 std::string error_message;
752 switch (error_type) {
753 case WalletClient::BAD_REQUEST:
754 error_message = "WALLET_BAD_REQUEST";
756 case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
757 error_message = "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
759 case WalletClient::BUYER_ACCOUNT_ERROR:
760 error_message = "WALLET_BUYER_ACCOUNT_ERROR";
762 case WalletClient::INTERNAL_ERROR:
763 error_message = "WALLET_INTERNAL_ERROR";
765 case WalletClient::INVALID_PARAMS:
766 error_message = "WALLET_INVALID_PARAMS";
768 case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
769 error_message = "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
771 case WalletClient::SERVICE_UNAVAILABLE:
772 error_message = "WALLET_SERVICE_UNAVAILABLE";
774 case WalletClient::UNSUPPORTED_API_VERSION:
775 error_message = "WALLET_UNSUPPORTED_API_VERSION";
777 case WalletClient::UNSUPPORTED_MERCHANT:
778 error_message = "WALLET_UNSUPPORTED_MERCHANT";
780 case WalletClient::MALFORMED_RESPONSE:
781 error_message = "WALLET_MALFORMED_RESPONSE";
783 case WalletClient::NETWORK_ERROR:
784 error_message = "WALLET_NETWORK_ERROR";
786 case WalletClient::UNKNOWN_ERROR:
787 error_message = "WALLET_UNKNOWN_ERROR";
791 VLOG(1) << "Wallet encountered a " << error_message;
793 delegate_->OnWalletError(error_type);
794 delegate_->GetMetricLogger().LogWalletErrorMetric(
795 ErrorTypeToUmaMetric(error_type));
798 // Logs an UMA metric for each of the |required_actions|.
799 void WalletClient::LogRequiredActions(
800 const std::vector<RequiredAction>& required_actions) const {
801 for (size_t i = 0; i < required_actions.size(); ++i) {
802 delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
803 RequiredActionToUmaMetric(required_actions[i]));
807 AutofillMetrics::WalletApiCallMetric WalletClient::RequestTypeToUmaMetric(
808 RequestType request_type) const {
809 switch (request_type) {
810 case ACCEPT_LEGAL_DOCUMENTS:
811 return AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS;
812 case AUTHENTICATE_INSTRUMENT:
813 return AutofillMetrics::AUTHENTICATE_INSTRUMENT;
814 case GET_FULL_WALLET:
815 return AutofillMetrics::GET_FULL_WALLET;
816 case GET_WALLET_ITEMS:
817 return AutofillMetrics::GET_WALLET_ITEMS;
819 return AutofillMetrics::SAVE_TO_WALLET;
820 case NO_PENDING_REQUEST:
822 return AutofillMetrics::UNKNOWN_API_CALL;
826 return AutofillMetrics::UNKNOWN_API_CALL;
829 } // namespace wallet
830 } // namespace autofill