Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / components / autofill / content / browser / wallet / wallet_client.cc
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.
4
5 #include "components/autofill/content/browser/wallet/wallet_client.h"
6
7 #include "base/bind.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"
30
31 namespace autofill {
32 namespace wallet {
33
34 namespace {
35
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;
45
46 // The maximum number of bits in the one time pad that the server is willing to
47 // accept.
48 const size_t kMaxBits = 56;
49
50 // The minimum number of bits in the one time pad that the server is willing to
51 // accept.
52 const size_t kMinBits = 40;
53
54 std::string RiskCapabilityToString(
55     WalletClient::RiskCapability risk_capability) {
56   switch (risk_capability) {
57     case WalletClient::RELOGIN:
58       return "RELOGIN";
59     case WalletClient::VERIFY_CVC:
60       return "VERIFY_CVC";
61   }
62   NOTREACHED();
63   return "NOT_POSSIBLE";
64 }
65
66 WalletClient::ErrorType StringToErrorType(const std::string& error_type) {
67   std::string trimmed;
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;
85
86   DVLOG(1) << "Unknown wallet error string: \"" << error_type << '"';
87   return WalletClient::UNKNOWN_ERROR;
88 }
89
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) {
94   std::string trimmed;
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;
100
101   return WalletClient::BUYER_ACCOUNT_ERROR;
102 }
103
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))
111     return;
112
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();
121         return;
122       }
123       required_actions->push_back(action);
124     }
125   }
126 }
127
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))
133     return;
134
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));
139   }
140 }
141
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;
175   }
176
177   NOTREACHED();
178   return AutofillMetrics::WALLET_UNKNOWN_ERROR;
179 }
180
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) {
186     case UNKNOWN_TYPE:
187       return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
188     case CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
189       return AutofillMetrics::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS;
190     case SETUP_WALLET:
191       return AutofillMetrics::SETUP_WALLET;
192     case ACCEPT_TOS:
193       return AutofillMetrics::ACCEPT_TOS;
194     case GAIA_AUTH:
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;
202     case VERIFY_CVV:
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;
208   }
209
210   NOTREACHED();
211   return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
212 }
213
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";
243
244 }  // namespace
245
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) {}
257
258 WalletClient::FullWalletRequest::~FullWalletRequest() {}
259
260 WalletClient::WalletClient(net::URLRequestContextGetter* context_getter,
261                            WalletClientDelegate* delegate,
262                            const GURL& source_url)
263     : context_getter_(context_getter),
264       delegate_(delegate),
265       user_index_(0U),
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());
271   DCHECK(delegate_);
272 }
273
274 WalletClient::~WalletClient() {}
275
276 void WalletClient::AcceptLegalDocuments(
277     const std::vector<WalletItems::LegalDocument*>& documents,
278     const std::string& google_transaction_id) {
279   if (documents.empty())
280     return;
281
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());
285   }
286   DoAcceptLegalDocuments(document_ids, google_transaction_id);
287 }
288
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);
296
297   std::string json_payload;
298   base::JSONWriter::Write(&request_dict, &json_payload);
299
300   std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
301       card_verification_number, true);
302
303   std::string post_body = base::StringPrintf(
304       kEscrowCardVerificationNumberFormat,
305       net::EscapeUrlEncodedData(json_payload, true).c_str(),
306       escaped_card_verification_number.c_str());
307
308   MakeWalletRequest(GetAuthenticateInstrumentUrl(user_index_),
309                     post_body,
310                     kFormEncodedMimeType,
311                     AUTHENTICATE_INSTRUMENT);
312 }
313
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);
321
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(
326       kMerchantDomainKey,
327       source_url_.GetWithEmptyPath().spec());
328   request_dict.SetString(kGoogleTransactionIdKey,
329                          full_wallet_request.google_transaction_id);
330   request_dict.SetString(kFeatureKey, "REQUEST_AUTOCOMPLETE");
331
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();
336        ++it) {
337     risk_capabilities_list->AppendString(RiskCapabilityToString(*it));
338   }
339   request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
340
341   std::string json_payload;
342   base::JSONWriter::Write(&request_dict, &json_payload);
343
344   crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
345
346   size_t num_bits = one_time_pad_.size() * 8;
347   DCHECK_LE(num_bits, kMaxBits);
348   DCHECK_GE(num_bits, kMinBits);
349
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());
355
356   MakeWalletRequest(GetGetFullWalletUrl(user_index_),
357                     post_body,
358                     kFormEncodedMimeType,
359                     GET_FULL_WALLET);
360 }
361
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);
368
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);
376
377   std::string primary_account_number;
378   std::string card_verification_number;
379   if (instrument) {
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);
384
385     if (!reference_instrument) {
386       request_dict.Set(kInstrumentKey, instrument->ToDictionary().release());
387       request_dict.SetString(kInstrumentPhoneNumberKey,
388                              instrument->address()->phone_number());
389     } else {
390       DCHECK(!reference_instrument->object_id().empty());
391
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();
397
398       DCHECK(instrument->address() || expiration_date_changed);
399
400       request_dict.SetString(kUpgradedInstrumentIdKey,
401                              reference_instrument->object_id());
402
403       if (instrument->address()) {
404         request_dict.SetString(kInstrumentPhoneNumberKey,
405                                instrument->address()->phone_number());
406         request_dict.Set(
407             kUpgradedBillingAddressKey,
408             instrument->address()->ToDictionaryWithoutID().release());
409       }
410
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());
418       }
419
420       if (request_dict.HasKey(kInstrumentKey))
421         request_dict.SetString(kInstrumentType, "CREDIT_CARD");
422     }
423   }
424   if (address) {
425     if (reference_address) {
426       address->set_object_id(reference_address->object_id());
427       DCHECK(!address->object_id().empty());
428     }
429     request_dict.Set(kShippingAddressKey,
430                      address->ToDictionaryWithID().release());
431   }
432
433   std::string json_payload;
434   base::JSONWriter::Write(&request_dict, &json_payload);
435
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());
444     } else {
445       post_body = base::StringPrintf(
446           kEscrowCardVerificationNumberFormat,
447           net::EscapeUrlEncodedData(json_payload, true).c_str(),
448           card_verification_number.c_str());
449     }
450     MakeWalletRequest(GetSaveToWalletUrl(user_index_),
451                       post_body,
452                       kFormEncodedMimeType,
453                       SAVE_TO_WALLET);
454   } else {
455     MakeWalletRequest(GetSaveToWalletNoEscrowUrl(user_index_),
456                       json_payload,
457                       kJsonMimeType,
458                       SAVE_TO_WALLET);
459   }
460 }
461
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);
472
473   if (!amount.empty())
474     request_dict.SetString(kTransactionAmountKey, amount);
475   if (!currency.empty())
476     request_dict.SetString(kTransactionCurrencyKey, currency);
477
478   std::string post_body;
479   base::JSONWriter::Write(&request_dict, &post_body);
480
481   MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
482                     post_body,
483                     kJsonMimeType,
484                     GET_WALLET_ITEMS);
485 }
486
487 bool WalletClient::HasRequestInProgress() const {
488   return request_;
489 }
490
491 void WalletClient::CancelRequest() {
492   request_.reset();
493   request_type_ = NO_REQUEST;
494 }
495
496 void WalletClient::SetUserIndex(size_t user_index) {
497   CancelRequest();
498   user_index_ = user_index;
499 }
500
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) {
512     if (!it->empty())
513       docs_list->AppendString(*it);
514   }
515   request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
516
517   std::string post_body;
518   base::JSONWriter::Write(&request_dict, &post_body);
519
520   MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
521                     post_body,
522                     kJsonMimeType,
523                     ACCEPT_LEGAL_DOCUMENTS);
524 }
525
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;
532
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();
543   request_->Start();
544
545   delegate_->GetMetricLogger().LogWalletErrorMetric(
546       AutofillMetrics::WALLET_ERROR_BASELINE_ISSUED_REQUEST);
547   delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
548       AutofillMetrics::WALLET_REQUIRED_ACTION_BASELINE_ISSUED_REQUEST);
549 }
550
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_);
557
558   DCHECK_EQ(source, request_.get());
559   DVLOG(1) << "Got response from " << source->GetOriginalURL();
560
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());
564
565   std::string data;
566   source->GetResponseAsString(&data);
567   DVLOG(1) << "Response body: " << data;
568
569   scoped_ptr<base::DictionaryValue> response_dict;
570
571   int response_code = source->GetResponseCode();
572   delegate_->GetMetricLogger().LogWalletResponseCode(response_code);
573
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);
579       return;
580     }
581     // HTTP_OK holds a valid response and HTTP_INTERNAL_SERVER_ERROR holds an
582     // error code and message for the user.
583     case net::HTTP_OK:
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)) {
588         response_dict.reset(
589             static_cast<base::DictionaryValue*>(message_value.release()));
590       }
591       if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
592         request_type_ = NO_REQUEST;
593
594         std::string error_type_string;
595         if (!response_dict->GetString(kErrorTypeKey, &error_type_string)) {
596           HandleWalletError(UNKNOWN_ERROR);
597           return;
598         }
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
604           // about the error.
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);
610           }
611         }
612
613         HandleWalletError(error_type);
614         return;
615       }
616       break;
617     }
618
619     // Anything else is an error.
620     default:
621       request_type_ = NO_REQUEST;
622       HandleWalletError(NETWORK_ERROR);
623       return;
624   }
625
626   RequestType type = request_type_;
627   request_type_ = NO_REQUEST;
628
629   if (type != ACCEPT_LEGAL_DOCUMENTS && !response_dict) {
630     HandleMalformedResponse(type, scoped_request.get());
631     return;
632   }
633
634   switch (type) {
635     case ACCEPT_LEGAL_DOCUMENTS:
636       delegate_->OnDidAcceptLegalDocuments();
637       break;
638
639     case AUTHENTICATE_INSTRUMENT: {
640       std::string auth_result;
641       if (response_dict->GetString(kAuthResultKey, &auth_result)) {
642         std::string trimmed;
643         base::TrimWhitespaceASCII(auth_result, base::TRIM_ALL, &trimmed);
644         delegate_->OnDidAuthenticateInstrument(
645             LowerCaseEqualsASCII(trimmed, "success"));
646       } else {
647         HandleMalformedResponse(type, scoped_request.get());
648       }
649       break;
650     }
651
652     case GET_FULL_WALLET: {
653       scoped_ptr<FullWallet> full_wallet(
654           FullWallet::CreateFullWallet(*response_dict));
655       if (full_wallet) {
656         full_wallet->set_one_time_pad(one_time_pad_);
657         LogRequiredActions(full_wallet->required_actions());
658         delegate_->OnDidGetFullWallet(full_wallet.Pass());
659       } else {
660         HandleMalformedResponse(type, scoped_request.get());
661       }
662       break;
663     }
664
665     case GET_WALLET_ITEMS: {
666       scoped_ptr<WalletItems> wallet_items(
667           WalletItems::CreateWalletItems(*response_dict));
668       if (wallet_items) {
669         LogRequiredActions(wallet_items->required_actions());
670         delegate_->OnDidGetWalletItems(wallet_items.Pass());
671       } else {
672         HandleMalformedResponse(type, scoped_request.get());
673       }
674       break;
675     }
676
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());
690       } else {
691         LogRequiredActions(required_actions);
692         delegate_->OnDidSaveToWallet(instrument_id,
693                                      shipping_address_id,
694                                      required_actions,
695                                      form_errors);
696       }
697       break;
698     }
699
700     case NO_REQUEST:
701       NOTREACHED();
702   }
703 }
704
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);
713 }
714
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";
720       break;
721     case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
722       error_message = "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
723       break;
724     case WalletClient::BUYER_ACCOUNT_ERROR:
725       error_message = "WALLET_BUYER_ACCOUNT_ERROR";
726       break;
727     case WalletClient::INTERNAL_ERROR:
728       error_message = "WALLET_INTERNAL_ERROR";
729       break;
730     case WalletClient::INVALID_PARAMS:
731       error_message = "WALLET_INVALID_PARAMS";
732       break;
733     case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
734       error_message = "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
735       break;
736     case WalletClient::SPENDING_LIMIT_EXCEEDED:
737       error_message = "SPENDING_LIMIT_EXCEEDED";
738       break;
739     case WalletClient::SERVICE_UNAVAILABLE:
740       error_message = "WALLET_SERVICE_UNAVAILABLE";
741       break;
742     case WalletClient::UNSUPPORTED_API_VERSION:
743       error_message = "WALLET_UNSUPPORTED_API_VERSION";
744       break;
745     case WalletClient::UNSUPPORTED_MERCHANT:
746       error_message = "WALLET_UNSUPPORTED_MERCHANT";
747       break;
748     case WalletClient::MALFORMED_RESPONSE:
749       error_message = "WALLET_MALFORMED_RESPONSE";
750       break;
751     case WalletClient::NETWORK_ERROR:
752       error_message = "WALLET_NETWORK_ERROR";
753       break;
754     case WalletClient::UNKNOWN_ERROR:
755       error_message = "WALLET_UNKNOWN_ERROR";
756       break;
757     case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
758       error_message = "WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY";
759       break;
760   }
761
762   DVLOG(1) << "Wallet encountered a " << error_message;
763
764   delegate_->OnWalletError(error_type);
765   delegate_->GetMetricLogger().LogWalletErrorMetric(
766       ErrorTypeToUmaMetric(error_type));
767 }
768
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]));
775   }
776 }
777
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;
789     case SAVE_TO_WALLET:
790       return AutofillMetrics::SAVE_TO_WALLET;
791     case NO_REQUEST:
792       NOTREACHED();
793       return AutofillMetrics::UNKNOWN_API_CALL;
794   }
795
796   NOTREACHED();
797   return AutofillMetrics::UNKNOWN_API_CALL;
798 }
799
800 }  // namespace wallet
801 }  // namespace autofill