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
);
584 scoped_ptr
<base::Value
> message_value(base::JSONReader::Read(data
));
585 if (message_value
.get() &&
586 message_value
->IsType(base::Value::TYPE_DICTIONARY
)) {
588 static_cast<base::DictionaryValue
*>(message_value
.release()));
593 // Response contains an error to show the user.
594 case net::HTTP_FORBIDDEN
:
595 case net::HTTP_INTERNAL_SERVER_ERROR
: {
596 scoped_ptr
<base::Value
> message_value(base::JSONReader::Read(data
));
597 if (message_value
.get() &&
598 message_value
->IsType(base::Value::TYPE_DICTIONARY
)) {
600 static_cast<base::DictionaryValue
*>(message_value
.release()));
603 request_type_
= NO_REQUEST
;
605 std::string error_type_string
;
606 if (!response_dict
->GetString(kErrorTypeKey
, &error_type_string
)) {
607 HandleWalletError(UNKNOWN_ERROR
);
610 WalletClient::ErrorType error_type
= StringToErrorType(error_type_string
);
611 if (error_type
== BUYER_ACCOUNT_ERROR
) {
612 // If the error_type is |BUYER_ACCOUNT_ERROR|, then
613 // message_type_for_buyer field contains more specific information
615 std::string message_type_for_buyer_string
;
616 if (response_dict
->GetString(kMessageTypeForBuyerKey
,
617 &message_type_for_buyer_string
)) {
619 BuyerErrorStringToErrorType(message_type_for_buyer_string
);
623 HandleWalletError(error_type
);
627 // Handle anything else as a generic error.
629 request_type_
= NO_REQUEST
;
630 HandleWalletError(NETWORK_ERROR
);
634 RequestType type
= request_type_
;
635 request_type_
= NO_REQUEST
;
637 if (type
!= ACCEPT_LEGAL_DOCUMENTS
&& !response_dict
) {
638 HandleMalformedResponse(type
, scoped_request
.get());
643 case ACCEPT_LEGAL_DOCUMENTS
:
644 delegate_
->OnDidAcceptLegalDocuments();
647 case AUTHENTICATE_INSTRUMENT
: {
648 std::string auth_result
;
649 if (response_dict
->GetString(kAuthResultKey
, &auth_result
)) {
651 base::TrimWhitespaceASCII(auth_result
, base::TRIM_ALL
, &trimmed
);
652 delegate_
->OnDidAuthenticateInstrument(
653 LowerCaseEqualsASCII(trimmed
, "success"));
655 HandleMalformedResponse(type
, scoped_request
.get());
660 case GET_FULL_WALLET
: {
661 scoped_ptr
<FullWallet
> full_wallet(
662 FullWallet::CreateFullWallet(*response_dict
));
664 full_wallet
->set_one_time_pad(one_time_pad_
);
665 LogRequiredActions(full_wallet
->required_actions());
666 delegate_
->OnDidGetFullWallet(full_wallet
.Pass());
668 HandleMalformedResponse(type
, scoped_request
.get());
673 case GET_WALLET_ITEMS
: {
674 scoped_ptr
<WalletItems
> wallet_items(
675 WalletItems::CreateWalletItems(*response_dict
));
677 LogRequiredActions(wallet_items
->required_actions());
678 delegate_
->OnDidGetWalletItems(wallet_items
.Pass());
680 HandleMalformedResponse(type
, scoped_request
.get());
685 case SAVE_TO_WALLET
: {
686 std::string instrument_id
;
687 response_dict
->GetString(kInstrumentIdKey
, &instrument_id
);
688 std::string shipping_address_id
;
689 response_dict
->GetString(kShippingAddressIdKey
,
690 &shipping_address_id
);
691 std::vector
<RequiredAction
> required_actions
;
692 GetRequiredActionsForSaveToWallet(*response_dict
, &required_actions
);
693 std::vector
<FormFieldError
> form_errors
;
694 GetFormFieldErrors(*response_dict
, &form_errors
);
695 if (instrument_id
.empty() && shipping_address_id
.empty() &&
696 required_actions
.empty()) {
697 HandleMalformedResponse(type
, scoped_request
.get());
699 LogRequiredActions(required_actions
);
700 delegate_
->OnDidSaveToWallet(instrument_id
,
713 void WalletClient::HandleMalformedResponse(RequestType request_type
,
714 net::URLFetcher
* request
) {
715 // Called to inform exponential backoff logic of the error.
716 request
->ReceivedContentWasMalformed();
717 // Record failed API call in metrics.
718 delegate_
->GetMetricLogger().LogWalletMalformedResponseMetric(
719 RequestTypeToUmaMetric(request_type
));
720 HandleWalletError(MALFORMED_RESPONSE
);
723 void WalletClient::HandleWalletError(WalletClient::ErrorType error_type
) {
724 std::string error_message
;
725 switch (error_type
) {
726 case WalletClient::BAD_REQUEST
:
727 error_message
= "WALLET_BAD_REQUEST";
729 case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED
:
730 error_message
= "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
732 case WalletClient::BUYER_ACCOUNT_ERROR
:
733 error_message
= "WALLET_BUYER_ACCOUNT_ERROR";
735 case WalletClient::INTERNAL_ERROR
:
736 error_message
= "WALLET_INTERNAL_ERROR";
738 case WalletClient::INVALID_PARAMS
:
739 error_message
= "WALLET_INVALID_PARAMS";
741 case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS
:
742 error_message
= "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
744 case WalletClient::SPENDING_LIMIT_EXCEEDED
:
745 error_message
= "SPENDING_LIMIT_EXCEEDED";
747 case WalletClient::SERVICE_UNAVAILABLE
:
748 error_message
= "WALLET_SERVICE_UNAVAILABLE";
750 case WalletClient::UNSUPPORTED_API_VERSION
:
751 error_message
= "WALLET_UNSUPPORTED_API_VERSION";
753 case WalletClient::UNSUPPORTED_MERCHANT
:
754 error_message
= "WALLET_UNSUPPORTED_MERCHANT";
756 case WalletClient::MALFORMED_RESPONSE
:
757 error_message
= "WALLET_MALFORMED_RESPONSE";
759 case WalletClient::NETWORK_ERROR
:
760 error_message
= "WALLET_NETWORK_ERROR";
762 case WalletClient::UNKNOWN_ERROR
:
763 error_message
= "WALLET_UNKNOWN_ERROR";
765 case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY
:
766 error_message
= "WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY";
770 DVLOG(1) << "Wallet encountered a " << error_message
;
772 delegate_
->OnWalletError(error_type
);
773 delegate_
->GetMetricLogger().LogWalletErrorMetric(
774 ErrorTypeToUmaMetric(error_type
));
777 // Logs an UMA metric for each of the |required_actions|.
778 void WalletClient::LogRequiredActions(
779 const std::vector
<RequiredAction
>& required_actions
) const {
780 for (size_t i
= 0; i
< required_actions
.size(); ++i
) {
781 delegate_
->GetMetricLogger().LogWalletRequiredActionMetric(
782 RequiredActionToUmaMetric(required_actions
[i
]));
786 AutofillMetrics::WalletApiCallMetric
WalletClient::RequestTypeToUmaMetric(
787 RequestType request_type
) const {
788 switch (request_type
) {
789 case ACCEPT_LEGAL_DOCUMENTS
:
790 return AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS
;
791 case AUTHENTICATE_INSTRUMENT
:
792 return AutofillMetrics::AUTHENTICATE_INSTRUMENT
;
793 case GET_FULL_WALLET
:
794 return AutofillMetrics::GET_FULL_WALLET
;
795 case GET_WALLET_ITEMS
:
796 return AutofillMetrics::GET_WALLET_ITEMS
;
798 return AutofillMetrics::SAVE_TO_WALLET
;
801 return AutofillMetrics::UNKNOWN_API_CALL
;
805 return AutofillMetrics::UNKNOWN_API_CALL
;
808 } // namespace wallet
809 } // namespace autofill