- add sources.
[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 // TODO(ahutter): Change all VLOGs to DVLOGs after dogfood.
32 namespace autofill {
33 namespace wallet {
34
35 namespace {
36
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;
46
47 // The maximum number of bits in the one time pad that the server is willing to
48 // accept.
49 const size_t kMaxBits = 56;
50
51 // The minimum number of bits in the one time pad that the server is willing to
52 // accept.
53 const size_t kMinBits = 40;
54
55 std::string RiskCapabilityToString(
56     WalletClient::RiskCapability risk_capability) {
57   switch (risk_capability) {
58     case WalletClient::RELOGIN:
59       return "RELOGIN";
60     case WalletClient::VERIFY_CVC:
61       return "VERIFY_CVC";
62   }
63   NOTREACHED();
64   return "NOT_POSSIBLE";
65 }
66
67 WalletClient::ErrorType StringToErrorType(const std::string& error_type) {
68   std::string trimmed;
69   TrimWhitespaceASCII(error_type,
70                       TRIM_ALL,
71                       &trimmed);
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;
84
85   return WalletClient::UNKNOWN_ERROR;
86 }
87
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) {
92   std::string trimmed;
93   TrimWhitespaceASCII(message_type_for_buyer,
94                       TRIM_ALL,
95                       &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::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;
171   }
172
173   NOTREACHED();
174   return AutofillMetrics::WALLET_UNKNOWN_ERROR;
175 }
176
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) {
182     case UNKNOWN_TYPE:
183       return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
184     case CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
185       return AutofillMetrics::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS;
186     case SETUP_WALLET:
187       return AutofillMetrics::SETUP_WALLET;
188     case ACCEPT_TOS:
189       return AutofillMetrics::ACCEPT_TOS;
190     case GAIA_AUTH:
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;
198     case VERIFY_CVV:
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;
204   }
205
206   NOTREACHED();
207   return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
208 }
209
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";
237
238 }  // namespace
239
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) {}
251
252 WalletClient::FullWalletRequest::~FullWalletRequest() {}
253
254 WalletClient::WalletClient(net::URLRequestContextGetter* context_getter,
255                            WalletClientDelegate* delegate,
256                            const GURL& source_url)
257     : context_getter_(context_getter),
258       delegate_(delegate),
259       user_index_(0U),
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());
265   DCHECK(delegate_);
266 }
267
268 WalletClient::~WalletClient() {}
269
270 void WalletClient::AcceptLegalDocuments(
271     const std::vector<WalletItems::LegalDocument*>& documents,
272     const std::string& google_transaction_id) {
273   if (documents.empty())
274     return;
275
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());
279   }
280   DoAcceptLegalDocuments(document_ids, google_transaction_id);
281 }
282
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),
289                                       instrument_id,
290                                       card_verification_number));
291     return;
292   }
293
294   DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
295   request_type_ = AUTHENTICATE_INSTRUMENT;
296
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);
301
302   std::string json_payload;
303   base::JSONWriter::Write(&request_dict, &json_payload);
304
305   std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
306       card_verification_number, true);
307
308   std::string post_body = base::StringPrintf(
309       kEscrowCardVerificationNumberFormat,
310       net::EscapeUrlEncodedData(json_payload, true).c_str(),
311       escaped_card_verification_number.c_str());
312
313   MakeWalletRequest(GetAuthenticateInstrumentUrl(user_index_),
314                     post_body,
315                     kFormEncodedMimeType);
316 }
317
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));
323     return;
324   }
325
326   DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
327   request_type_ = GET_FULL_WALLET;
328
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);
335
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(
340       kMerchantDomainKey,
341       source_url_.GetWithEmptyPath().spec());
342   request_dict.SetString(kGoogleTransactionIdKey,
343                          full_wallet_request.google_transaction_id);
344   request_dict.SetString(kFeatureKey, "REQUEST_AUTOCOMPLETE");
345
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();
350        ++it) {
351     risk_capabilities_list->AppendString(RiskCapabilityToString(*it));
352   }
353   request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
354
355   std::string json_payload;
356   base::JSONWriter::Write(&request_dict, &json_payload);
357
358   crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
359
360   size_t num_bits = one_time_pad_.size() * 8;
361   DCHECK_LE(num_bits, kMaxBits);
362   DCHECK_GE(num_bits, kMinBits);
363
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());
369
370   MakeWalletRequest(GetGetFullWalletUrl(user_index_),
371                     post_body,
372                     kFormEncodedMimeType);
373 }
374
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)));
383     return;
384   }
385
386   DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
387   request_type_ = SAVE_TO_WALLET;
388
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);
396
397   std::string primary_account_number;
398   std::string card_verification_number;
399   if (instrument) {
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);
404
405     if (instrument->object_id().empty()) {
406       request_dict.Set(kInstrumentKey, instrument->ToDictionary().release());
407       request_dict.SetString(kInstrumentPhoneNumberKey,
408                              instrument->address()->phone_number());
409     } else {
410       DCHECK(instrument->address() ||
411              (instrument->expiration_month() > 0 &&
412               instrument->expiration_year() > 0));
413
414       request_dict.SetString(kUpgradedInstrumentIdKey,
415                              instrument->object_id());
416
417       if (instrument->address()) {
418         request_dict.SetString(kInstrumentPhoneNumberKey,
419                                instrument->address()->phone_number());
420         request_dict.Set(
421             kUpgradedBillingAddressKey,
422             instrument->address()->ToDictionaryWithoutID().release());
423       }
424
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());
432       }
433
434       if (request_dict.HasKey(kInstrumentKey))
435         request_dict.SetString(kInstrumentType, "CREDIT_CARD");
436     }
437   }
438   if (address) {
439     request_dict.Set(kShippingAddressKey,
440                      address->ToDictionaryWithID().release());
441   }
442
443   std::string json_payload;
444   base::JSONWriter::Write(&request_dict, &json_payload);
445
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());
454     } else {
455       post_body = base::StringPrintf(
456           kEscrowCardVerificationNumberFormat,
457           net::EscapeUrlEncodedData(json_payload, true).c_str(),
458           card_verification_number.c_str());
459     }
460     MakeWalletRequest(GetSaveToWalletUrl(user_index_),
461                       post_body,
462                       kFormEncodedMimeType);
463   } else {
464     MakeWalletRequest(GetSaveToWalletNoEscrowUrl(user_index_),
465                       json_payload,
466                       kJsonMimeType);
467   }
468 }
469
470 void WalletClient::GetWalletItems() {
471   if (HasRequestInProgress()) {
472     pending_requests_.push(base::Bind(&WalletClient::GetWalletItems,
473                                       base::Unretained(this)));
474     return;
475   }
476
477   DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
478   request_type_ = GET_WALLET_ITEMS;
479
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);
488
489   std::string post_body;
490   base::JSONWriter::Write(&request_dict, &post_body);
491
492   MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
493                     post_body,
494                     kJsonMimeType);
495 }
496
497 bool WalletClient::HasRequestInProgress() const {
498   return request_;
499 }
500
501 void WalletClient::CancelRequests() {
502   request_.reset();
503   request_type_ = NO_PENDING_REQUEST;
504   while (!pending_requests_.empty()) {
505     pending_requests_.pop();
506   }
507 }
508
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),
515                                       document_ids,
516                                       google_transaction_id));
517     return;
518   }
519
520   DCHECK_EQ(NO_PENDING_REQUEST, request_type_);
521   request_type_ = ACCEPT_LEGAL_DOCUMENTS;
522
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) {
531     if (!it->empty())
532       docs_list->AppendString(*it);
533   }
534   request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
535
536   std::string post_body;
537   base::JSONWriter::Write(&request_dict, &post_body);
538
539   MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
540                     post_body,
541                     kJsonMimeType);
542 }
543
544 void WalletClient::MakeWalletRequest(const GURL& url,
545                                      const std::string& post_body,
546                                      const std::string& mime_type) {
547   DCHECK(!HasRequestInProgress());
548
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();
559   request_->Start();
560
561   delegate_->GetMetricLogger().LogWalletErrorMetric(
562       AutofillMetrics::WALLET_ERROR_BASELINE_ISSUED_REQUEST);
563   delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
564       AutofillMetrics::WALLET_REQUIRED_ACTION_BASELINE_ISSUED_REQUEST);
565 }
566
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_);
573
574   DCHECK_EQ(source, request_.get());
575   VLOG(1) << "Got response from " << source->GetOriginalURL();
576
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());
580
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(
585       FROM_HERE,
586       base::Bind(&WalletClient::StartNextPendingRequest,
587                  weak_ptr_factory_.GetWeakPtr()));;
588
589   std::string data;
590   source->GetResponseAsString(&data);
591   VLOG(1) << "Response body: " << data;
592
593   scoped_ptr<base::DictionaryValue> response_dict;
594
595   int response_code = source->GetResponseCode();
596   delegate_->GetMetricLogger().LogWalletResponseCode(response_code);
597
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);
603       return;
604     }
605     // HTTP_OK holds a valid response and HTTP_INTERNAL_SERVER_ERROR holds an
606     // error code and message for the user.
607     case net::HTTP_OK:
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)) {
612         response_dict.reset(
613             static_cast<base::DictionaryValue*>(message_value.release()));
614       }
615       if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
616         request_type_ = NO_PENDING_REQUEST;
617
618         std::string error_type_string;
619         if (!response_dict->GetString(kErrorTypeKey, &error_type_string)) {
620           HandleWalletError(UNKNOWN_ERROR);
621           return;
622         }
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
628           // about the error.
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);
634           }
635         }
636
637         HandleWalletError(error_type);
638         return;
639       }
640       break;
641     }
642
643     // Anything else is an error.
644     default:
645       request_type_ = NO_PENDING_REQUEST;
646       HandleWalletError(NETWORK_ERROR);
647       return;
648   }
649
650   RequestType type = request_type_;
651   request_type_ = NO_PENDING_REQUEST;
652
653   if (type != ACCEPT_LEGAL_DOCUMENTS && !response_dict) {
654     HandleMalformedResponse(type, scoped_request.get());
655     return;
656   }
657
658   switch (type) {
659     case ACCEPT_LEGAL_DOCUMENTS:
660       delegate_->OnDidAcceptLegalDocuments();
661       break;
662
663     case AUTHENTICATE_INSTRUMENT: {
664       std::string auth_result;
665       if (response_dict->GetString(kAuthResultKey, &auth_result)) {
666         std::string trimmed;
667         TrimWhitespaceASCII(auth_result,
668                             TRIM_ALL,
669                             &trimmed);
670         delegate_->OnDidAuthenticateInstrument(
671             LowerCaseEqualsASCII(trimmed, "success"));
672       } else {
673         HandleMalformedResponse(type, scoped_request.get());
674       }
675       break;
676     }
677
678     case GET_FULL_WALLET: {
679       scoped_ptr<FullWallet> full_wallet(
680           FullWallet::CreateFullWallet(*response_dict));
681       if (full_wallet) {
682         full_wallet->set_one_time_pad(one_time_pad_);
683         LogRequiredActions(full_wallet->required_actions());
684         delegate_->OnDidGetFullWallet(full_wallet.Pass());
685       } else {
686         HandleMalformedResponse(type, scoped_request.get());
687       }
688       break;
689     }
690
691     case GET_WALLET_ITEMS: {
692       scoped_ptr<WalletItems> wallet_items(
693           WalletItems::CreateWalletItems(*response_dict));
694       if (wallet_items) {
695         LogRequiredActions(wallet_items->required_actions());
696         delegate_->OnDidGetWalletItems(wallet_items.Pass());
697       } else {
698         HandleMalformedResponse(type, scoped_request.get());
699       }
700       break;
701     }
702
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());
716       } else {
717         LogRequiredActions(required_actions);
718         delegate_->OnDidSaveToWallet(instrument_id,
719                                      shipping_address_id,
720                                      required_actions,
721                                      form_errors);
722       }
723       break;
724     }
725
726     case NO_PENDING_REQUEST:
727       NOTREACHED();
728   }
729 }
730
731 void WalletClient::StartNextPendingRequest() {
732   if (pending_requests_.empty())
733     return;
734
735   base::Closure next_request = pending_requests_.front();
736   pending_requests_.pop();
737   next_request.Run();
738 }
739
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);
748 }
749
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";
755       break;
756     case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
757       error_message = "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
758       break;
759     case WalletClient::BUYER_ACCOUNT_ERROR:
760       error_message = "WALLET_BUYER_ACCOUNT_ERROR";
761       break;
762     case WalletClient::INTERNAL_ERROR:
763       error_message = "WALLET_INTERNAL_ERROR";
764       break;
765     case WalletClient::INVALID_PARAMS:
766       error_message = "WALLET_INVALID_PARAMS";
767       break;
768     case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
769       error_message = "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
770       break;
771     case WalletClient::SERVICE_UNAVAILABLE:
772       error_message = "WALLET_SERVICE_UNAVAILABLE";
773       break;
774     case WalletClient::UNSUPPORTED_API_VERSION:
775       error_message = "WALLET_UNSUPPORTED_API_VERSION";
776       break;
777     case WalletClient::UNSUPPORTED_MERCHANT:
778       error_message = "WALLET_UNSUPPORTED_MERCHANT";
779       break;
780     case WalletClient::MALFORMED_RESPONSE:
781       error_message = "WALLET_MALFORMED_RESPONSE";
782       break;
783     case WalletClient::NETWORK_ERROR:
784       error_message = "WALLET_NETWORK_ERROR";
785       break;
786     case WalletClient::UNKNOWN_ERROR:
787       error_message = "WALLET_UNKNOWN_ERROR";
788       break;
789   }
790
791   VLOG(1) << "Wallet encountered a " << error_message;
792
793   delegate_->OnWalletError(error_type);
794   delegate_->GetMetricLogger().LogWalletErrorMetric(
795       ErrorTypeToUmaMetric(error_type));
796 }
797
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]));
804   }
805 }
806
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;
818     case SAVE_TO_WALLET:
819       return AutofillMetrics::SAVE_TO_WALLET;
820     case NO_PENDING_REQUEST:
821       NOTREACHED();
822       return AutofillMetrics::UNKNOWN_API_CALL;
823   }
824
825   NOTREACHED();
826   return AutofillMetrics::UNKNOWN_API_CALL;
827 }
828
829 }  // namespace wallet
830 }  // namespace autofill