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.
32namespace autofill {
33namespace wallet {
34
35namespace {
36
37const char kFormEncodedMimeType[] = "application/x-www-form-urlencoded";
38const char kJsonMimeType[] = "application/json";
39const char kEscrowNewInstrumentFormat[] =
40    "request_content_type=application/json&request=%s&cvn=%s&card_number=%s";
41const char kEscrowCardVerificationNumberFormat[] =
42    "request_content_type=application/json&request=%s&cvn=%s";
43const char kGetFullWalletRequestFormat[] =
44    "request_content_type=application/json&request=%s&otp=%s:%s";
45const size_t kOneTimePadLength = 6;
46
47// The maximum number of bits in the one time pad that the server is willing to
48// accept.
49const size_t kMaxBits = 56;
50
51// The minimum number of bits in the one time pad that the server is willing to
52// accept.
53const size_t kMinBits = 40;
54
55std::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
67WalletClient::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|.
90WalletClient::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.
106void 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
128void 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.
144AutofillMetrics::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.
179AutofillMetrics::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.
211const char kAcceptedLegalDocumentKey[] = "accepted_legal_document";
212const char kApiKeyKey[] = "api_key";
213const char kAuthResultKey[] = "auth_result";
214const char kErrorTypeKey[] = "wallet_error.error_type";
215const char kFeatureKey[] = "feature";
216const char kGoogleTransactionIdKey[] = "google_transaction_id";
217const char kInstrumentIdKey[] = "instrument_id";
218const char kInstrumentKey[] = "instrument";
219const char kInstrumentExpMonthKey[] = "instrument.credit_card.exp_month";
220const char kInstrumentExpYearKey[] = "instrument.credit_card.exp_year";
221const char kInstrumentType[] = "instrument.type";
222const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
223const char kMerchantDomainKey[] = "merchant_domain";
224const char kMessageTypeForBuyerKey[] = "wallet_error.message_type_for_buyer";
225const char kNewWalletUser[] = "new_wallet_user";
226const char kPhoneNumberRequired[] = "phone_number_required";
227const char kRiskCapabilitiesKey[] = "supported_risk_challenge";
228const char kRiskParamsKey[] = "risk_params";
229const char kSelectedAddressIdKey[] = "selected_address_id";
230const char kSelectedInstrumentIdKey[] = "selected_instrument_id";
231const char kShippingAddressIdKey[] = "shipping_address_id";
232const char kShippingAddressKey[] = "shipping_address";
233const char kShippingAddressRequired[] = "shipping_address_required";
234const char kUpgradedBillingAddressKey[] = "upgraded_billing_address";
235const char kUpgradedInstrumentIdKey[] = "upgraded_instrument_id";
236const char kUseMinimalAddresses[] = "use_minimal_addresses";
237
238}  // namespace
239
240WalletClient::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
252WalletClient::FullWalletRequest::~FullWalletRequest() {}
253
254WalletClient::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
268WalletClient::~WalletClient() {}
269
270void 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
283void WalletClient::AuthenticateInstrument(
284    const std::string& instrument_id,
285    const std::string& card_verification_number) {
286  base::DictionaryValue request_dict;
287  request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
288  request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
289  request_dict.SetString(kInstrumentIdKey, instrument_id);
290
291  std::string json_payload;
292  base::JSONWriter::Write(&request_dict, &json_payload);
293
294  std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
295      card_verification_number, true);
296
297  std::string post_body = base::StringPrintf(
298      kEscrowCardVerificationNumberFormat,
299      net::EscapeUrlEncodedData(json_payload, true).c_str(),
300      escaped_card_verification_number.c_str());
301
302  MakeWalletRequest(GetAuthenticateInstrumentUrl(user_index_),
303                    post_body,
304                    kFormEncodedMimeType,
305                    AUTHENTICATE_INSTRUMENT);
306}
307
308void WalletClient::GetFullWallet(const FullWalletRequest& full_wallet_request) {
309  base::DictionaryValue request_dict;
310  request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
311  request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
312  request_dict.SetBoolean(kUseMinimalAddresses, false);
313  request_dict.SetBoolean(kPhoneNumberRequired, true);
314  request_dict.SetBoolean(kNewWalletUser, full_wallet_request.new_wallet_user);
315
316  request_dict.SetString(kSelectedInstrumentIdKey,
317                         full_wallet_request.instrument_id);
318  request_dict.SetString(kSelectedAddressIdKey, full_wallet_request.address_id);
319  request_dict.SetString(
320      kMerchantDomainKey,
321      source_url_.GetWithEmptyPath().spec());
322  request_dict.SetString(kGoogleTransactionIdKey,
323                         full_wallet_request.google_transaction_id);
324  request_dict.SetString(kFeatureKey, "REQUEST_AUTOCOMPLETE");
325
326  scoped_ptr<base::ListValue> risk_capabilities_list(new base::ListValue());
327  for (std::vector<RiskCapability>::const_iterator it =
328           full_wallet_request.risk_capabilities.begin();
329       it != full_wallet_request.risk_capabilities.end();
330       ++it) {
331    risk_capabilities_list->AppendString(RiskCapabilityToString(*it));
332  }
333  request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
334
335  std::string json_payload;
336  base::JSONWriter::Write(&request_dict, &json_payload);
337
338  crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
339
340  size_t num_bits = one_time_pad_.size() * 8;
341  DCHECK_LE(num_bits, kMaxBits);
342  DCHECK_GE(num_bits, kMinBits);
343
344  std::string post_body = base::StringPrintf(
345      kGetFullWalletRequestFormat,
346      net::EscapeUrlEncodedData(json_payload, true).c_str(),
347      base::HexEncode(&num_bits, 1).c_str(),
348      base::HexEncode(&(one_time_pad_[0]), one_time_pad_.size()).c_str());
349
350  MakeWalletRequest(GetGetFullWalletUrl(user_index_),
351                    post_body,
352                    kFormEncodedMimeType,
353                    GET_FULL_WALLET);
354}
355
356void WalletClient::SaveToWallet(
357    scoped_ptr<Instrument> instrument,
358    scoped_ptr<Address> address,
359    const WalletItems::MaskedInstrument* reference_instrument,
360    const Address* reference_address) {
361  DCHECK(instrument || address);
362
363  base::DictionaryValue request_dict;
364  request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
365  request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
366  request_dict.SetString(kMerchantDomainKey,
367                         source_url_.GetWithEmptyPath().spec());
368  request_dict.SetBoolean(kUseMinimalAddresses, false);
369  request_dict.SetBoolean(kPhoneNumberRequired, true);
370
371  std::string primary_account_number;
372  std::string card_verification_number;
373  if (instrument) {
374    primary_account_number = net::EscapeUrlEncodedData(
375        UTF16ToUTF8(instrument->primary_account_number()), true);
376    card_verification_number = net::EscapeUrlEncodedData(
377        UTF16ToUTF8(instrument->card_verification_number()), true);
378
379    if (!reference_instrument) {
380      request_dict.Set(kInstrumentKey, instrument->ToDictionary().release());
381      request_dict.SetString(kInstrumentPhoneNumberKey,
382                             instrument->address()->phone_number());
383    } else {
384      DCHECK(!reference_instrument->object_id().empty());
385
386      int new_month = instrument->expiration_month();
387      int new_year = instrument->expiration_year();
388      bool expiration_date_changed =
389          new_month != reference_instrument->expiration_month() ||
390          new_year != reference_instrument->expiration_year();
391
392      DCHECK(instrument->address() || expiration_date_changed);
393
394      request_dict.SetString(kUpgradedInstrumentIdKey,
395                             reference_instrument->object_id());
396
397      if (instrument->address()) {
398        request_dict.SetString(kInstrumentPhoneNumberKey,
399                               instrument->address()->phone_number());
400        request_dict.Set(
401            kUpgradedBillingAddressKey,
402            instrument->address()->ToDictionaryWithoutID().release());
403      }
404
405      if (expiration_date_changed) {
406        // Updating expiration date requires a CVC.
407        DCHECK(!instrument->card_verification_number().empty());
408        request_dict.SetInteger(kInstrumentExpMonthKey,
409                                instrument->expiration_month());
410        request_dict.SetInteger(kInstrumentExpYearKey,
411                                instrument->expiration_year());
412      }
413
414      if (request_dict.HasKey(kInstrumentKey))
415        request_dict.SetString(kInstrumentType, "CREDIT_CARD");
416    }
417  }
418  if (address) {
419    if (reference_address) {
420      address->set_object_id(reference_address->object_id());
421      DCHECK(!address->object_id().empty());
422    }
423    request_dict.Set(kShippingAddressKey,
424                     address->ToDictionaryWithID().release());
425  }
426
427  std::string json_payload;
428  base::JSONWriter::Write(&request_dict, &json_payload);
429
430  if (!card_verification_number.empty()) {
431    std::string post_body;
432    if (!primary_account_number.empty()) {
433      post_body = base::StringPrintf(
434          kEscrowNewInstrumentFormat,
435          net::EscapeUrlEncodedData(json_payload, true).c_str(),
436          card_verification_number.c_str(),
437          primary_account_number.c_str());
438    } else {
439      post_body = base::StringPrintf(
440          kEscrowCardVerificationNumberFormat,
441          net::EscapeUrlEncodedData(json_payload, true).c_str(),
442          card_verification_number.c_str());
443    }
444    MakeWalletRequest(GetSaveToWalletUrl(user_index_),
445                      post_body,
446                      kFormEncodedMimeType,
447                      SAVE_TO_WALLET);
448  } else {
449    MakeWalletRequest(GetSaveToWalletNoEscrowUrl(user_index_),
450                      json_payload,
451                      kJsonMimeType,
452                      SAVE_TO_WALLET);
453  }
454}
455
456void WalletClient::GetWalletItems() {
457  base::DictionaryValue request_dict;
458  request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
459  request_dict.SetString(kMerchantDomainKey,
460                         source_url_.GetWithEmptyPath().spec());
461  request_dict.SetBoolean(kShippingAddressRequired,
462                          delegate_->IsShippingAddressRequired());
463  request_dict.SetBoolean(kUseMinimalAddresses, false);
464  request_dict.SetBoolean(kPhoneNumberRequired, true);
465
466  std::string post_body;
467  base::JSONWriter::Write(&request_dict, &post_body);
468
469  MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
470                    post_body,
471                    kJsonMimeType,
472                    GET_WALLET_ITEMS);
473}
474
475bool WalletClient::HasRequestInProgress() const {
476  return request_;
477}
478
479void WalletClient::CancelRequests() {
480  request_.reset();
481  request_type_ = NO_PENDING_REQUEST;
482  while (!pending_requests_.empty()) {
483    pending_requests_.pop();
484  }
485}
486
487void WalletClient::SetUserIndex(size_t user_index) {
488  CancelRequests();
489  user_index_ = user_index;
490}
491
492void WalletClient::DoAcceptLegalDocuments(
493    const std::vector<std::string>& document_ids,
494    const std::string& google_transaction_id) {
495  base::DictionaryValue request_dict;
496  request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
497  request_dict.SetString(kGoogleTransactionIdKey, google_transaction_id);
498  request_dict.SetString(kMerchantDomainKey,
499                         source_url_.GetWithEmptyPath().spec());
500  scoped_ptr<base::ListValue> docs_list(new base::ListValue());
501  for (std::vector<std::string>::const_iterator it = document_ids.begin();
502       it != document_ids.end(); ++it) {
503    if (!it->empty())
504      docs_list->AppendString(*it);
505  }
506  request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
507
508  std::string post_body;
509  base::JSONWriter::Write(&request_dict, &post_body);
510
511  MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
512                    post_body,
513                    kJsonMimeType,
514                    ACCEPT_LEGAL_DOCUMENTS);
515}
516
517void WalletClient::MakeWalletRequest(const GURL& url,
518                                     const std::string& post_body,
519                                     const std::string& mime_type,
520                                     RequestType request_type) {
521  if (HasRequestInProgress()) {
522    pending_requests_.push(base::Bind(&WalletClient::MakeWalletRequest,
523                                      base::Unretained(this),
524                                      url,
525                                      post_body,
526                                      mime_type,
527                                      request_type));
528    return;
529  }
530
531  DCHECK_EQ(request_type_, NO_PENDING_REQUEST);
532  request_type_ = request_type;
533
534  request_.reset(net::URLFetcher::Create(
535      0, url, net::URLFetcher::POST, this));
536  request_->SetRequestContext(context_getter_.get());
537  VLOG(1) << "Making request to " << url << " with post_body=" << post_body;
538  request_->SetUploadData(mime_type, post_body);
539  request_->AddExtraRequestHeader("Authorization: GoogleLogin auth=" +
540                                  delegate_->GetWalletCookieValue());
541  DVLOG(1) << "Setting authorization header value to "
542           << delegate_->GetWalletCookieValue();
543  request_started_timestamp_ = base::Time::Now();
544  request_->Start();
545
546  delegate_->GetMetricLogger().LogWalletErrorMetric(
547      AutofillMetrics::WALLET_ERROR_BASELINE_ISSUED_REQUEST);
548  delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
549      AutofillMetrics::WALLET_REQUIRED_ACTION_BASELINE_ISSUED_REQUEST);
550}
551
552// TODO(ahutter): Add manual retry logic if it's necessary.
553void WalletClient::OnURLFetchComplete(
554    const net::URLFetcher* source) {
555  delegate_->GetMetricLogger().LogWalletApiCallDuration(
556      RequestTypeToUmaMetric(request_type_),
557      base::Time::Now() - request_started_timestamp_);
558
559  DCHECK_EQ(source, request_.get());
560  VLOG(1) << "Got response from " << source->GetOriginalURL();
561
562  // |request_|, which is aliased to |source|, might continue to be used in this
563  // |method, but should be freed once control leaves the method.
564  scoped_ptr<net::URLFetcher> scoped_request(request_.Pass());
565
566  // Prepare to start the next pending request.  This is queued up as an
567  // asynchronous message because |this| WalletClient instance can be destroyed
568  // before the end of the method in response to the current incoming request.
569  base::MessageLoop::current()->PostTask(
570      FROM_HERE,
571      base::Bind(&WalletClient::StartNextPendingRequest,
572                 weak_ptr_factory_.GetWeakPtr()));;
573
574  std::string data;
575  source->GetResponseAsString(&data);
576  VLOG(1) << "Response body: " << data;
577
578  scoped_ptr<base::DictionaryValue> response_dict;
579
580  int response_code = source->GetResponseCode();
581  delegate_->GetMetricLogger().LogWalletResponseCode(response_code);
582
583  switch (response_code) {
584    // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
585    case net::HTTP_BAD_REQUEST: {
586      request_type_ = NO_PENDING_REQUEST;
587      HandleWalletError(BAD_REQUEST);
588      return;
589    }
590    // HTTP_OK holds a valid response and HTTP_INTERNAL_SERVER_ERROR holds an
591    // error code and message for the user.
592    case net::HTTP_OK:
593    case net::HTTP_INTERNAL_SERVER_ERROR: {
594      scoped_ptr<Value> message_value(base::JSONReader::Read(data));
595      if (message_value.get() &&
596          message_value->IsType(Value::TYPE_DICTIONARY)) {
597        response_dict.reset(
598            static_cast<base::DictionaryValue*>(message_value.release()));
599      }
600      if (response_code == net::HTTP_INTERNAL_SERVER_ERROR) {
601        request_type_ = NO_PENDING_REQUEST;
602
603        std::string error_type_string;
604        if (!response_dict->GetString(kErrorTypeKey, &error_type_string)) {
605          HandleWalletError(UNKNOWN_ERROR);
606          return;
607        }
608        WalletClient::ErrorType error_type =
609            StringToErrorType(error_type_string);
610        if (error_type == BUYER_ACCOUNT_ERROR) {
611          // If the error_type is |BUYER_ACCOUNT_ERROR|, then
612          // message_type_for_buyer field contains more specific information
613          // about the error.
614          std::string message_type_for_buyer_string;
615          if (response_dict->GetString(kMessageTypeForBuyerKey,
616                                       &message_type_for_buyer_string)) {
617            error_type = BuyerErrorStringToErrorType(
618                message_type_for_buyer_string);
619          }
620        }
621
622        HandleWalletError(error_type);
623        return;
624      }
625      break;
626    }
627
628    // Anything else is an error.
629    default:
630      request_type_ = NO_PENDING_REQUEST;
631      HandleWalletError(NETWORK_ERROR);
632      return;
633  }
634
635  RequestType type = request_type_;
636  request_type_ = NO_PENDING_REQUEST;
637
638  if (type != ACCEPT_LEGAL_DOCUMENTS && !response_dict) {
639    HandleMalformedResponse(type, scoped_request.get());
640    return;
641  }
642
643  switch (type) {
644    case ACCEPT_LEGAL_DOCUMENTS:
645      delegate_->OnDidAcceptLegalDocuments();
646      break;
647
648    case AUTHENTICATE_INSTRUMENT: {
649      std::string auth_result;
650      if (response_dict->GetString(kAuthResultKey, &auth_result)) {
651        std::string trimmed;
652        TrimWhitespaceASCII(auth_result,
653                            TRIM_ALL,
654                            &trimmed);
655        delegate_->OnDidAuthenticateInstrument(
656            LowerCaseEqualsASCII(trimmed, "success"));
657      } else {
658        HandleMalformedResponse(type, scoped_request.get());
659      }
660      break;
661    }
662
663    case GET_FULL_WALLET: {
664      scoped_ptr<FullWallet> full_wallet(
665          FullWallet::CreateFullWallet(*response_dict));
666      if (full_wallet) {
667        full_wallet->set_one_time_pad(one_time_pad_);
668        LogRequiredActions(full_wallet->required_actions());
669        delegate_->OnDidGetFullWallet(full_wallet.Pass());
670      } else {
671        HandleMalformedResponse(type, scoped_request.get());
672      }
673      break;
674    }
675
676    case GET_WALLET_ITEMS: {
677      scoped_ptr<WalletItems> wallet_items(
678          WalletItems::CreateWalletItems(*response_dict));
679      if (wallet_items) {
680        LogRequiredActions(wallet_items->required_actions());
681        delegate_->OnDidGetWalletItems(wallet_items.Pass());
682      } else {
683        HandleMalformedResponse(type, scoped_request.get());
684      }
685      break;
686    }
687
688    case SAVE_TO_WALLET: {
689      std::string instrument_id;
690      response_dict->GetString(kInstrumentIdKey, &instrument_id);
691      std::string shipping_address_id;
692      response_dict->GetString(kShippingAddressIdKey,
693                               &shipping_address_id);
694      std::vector<RequiredAction> required_actions;
695      GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
696      std::vector<FormFieldError> form_errors;
697      GetFormFieldErrors(*response_dict, &form_errors);
698      if (instrument_id.empty() && shipping_address_id.empty() &&
699          required_actions.empty()) {
700        HandleMalformedResponse(type, scoped_request.get());
701      } else {
702        LogRequiredActions(required_actions);
703        delegate_->OnDidSaveToWallet(instrument_id,
704                                     shipping_address_id,
705                                     required_actions,
706                                     form_errors);
707      }
708      break;
709    }
710
711    case NO_PENDING_REQUEST:
712      NOTREACHED();
713  }
714}
715
716void WalletClient::StartNextPendingRequest() {
717  if (pending_requests_.empty())
718    return;
719
720  base::Closure next_request = pending_requests_.front();
721  pending_requests_.pop();
722  next_request.Run();
723}
724
725void WalletClient::HandleMalformedResponse(RequestType request_type,
726                                           net::URLFetcher* request) {
727  // Called to inform exponential backoff logic of the error.
728  request->ReceivedContentWasMalformed();
729  // Record failed API call in metrics.
730  delegate_->GetMetricLogger().LogWalletMalformedResponseMetric(
731    RequestTypeToUmaMetric(request_type));
732  HandleWalletError(MALFORMED_RESPONSE);
733}
734
735void WalletClient::HandleWalletError(WalletClient::ErrorType error_type) {
736  std::string error_message;
737  switch (error_type) {
738    case WalletClient::BAD_REQUEST:
739      error_message = "WALLET_BAD_REQUEST";
740      break;
741    case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
742      error_message = "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
743      break;
744    case WalletClient::BUYER_ACCOUNT_ERROR:
745      error_message = "WALLET_BUYER_ACCOUNT_ERROR";
746      break;
747    case WalletClient::INTERNAL_ERROR:
748      error_message = "WALLET_INTERNAL_ERROR";
749      break;
750    case WalletClient::INVALID_PARAMS:
751      error_message = "WALLET_INVALID_PARAMS";
752      break;
753    case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
754      error_message = "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
755      break;
756    case WalletClient::SERVICE_UNAVAILABLE:
757      error_message = "WALLET_SERVICE_UNAVAILABLE";
758      break;
759    case WalletClient::UNSUPPORTED_API_VERSION:
760      error_message = "WALLET_UNSUPPORTED_API_VERSION";
761      break;
762    case WalletClient::UNSUPPORTED_MERCHANT:
763      error_message = "WALLET_UNSUPPORTED_MERCHANT";
764      break;
765    case WalletClient::MALFORMED_RESPONSE:
766      error_message = "WALLET_MALFORMED_RESPONSE";
767      break;
768    case WalletClient::NETWORK_ERROR:
769      error_message = "WALLET_NETWORK_ERROR";
770      break;
771    case WalletClient::UNKNOWN_ERROR:
772      error_message = "WALLET_UNKNOWN_ERROR";
773      break;
774  }
775
776  VLOG(1) << "Wallet encountered a " << error_message;
777
778  delegate_->OnWalletError(error_type);
779  delegate_->GetMetricLogger().LogWalletErrorMetric(
780      ErrorTypeToUmaMetric(error_type));
781}
782
783// Logs an UMA metric for each of the |required_actions|.
784void WalletClient::LogRequiredActions(
785    const std::vector<RequiredAction>& required_actions) const {
786  for (size_t i = 0; i < required_actions.size(); ++i) {
787    delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
788        RequiredActionToUmaMetric(required_actions[i]));
789  }
790}
791
792AutofillMetrics::WalletApiCallMetric WalletClient::RequestTypeToUmaMetric(
793    RequestType request_type) const {
794  switch (request_type) {
795    case ACCEPT_LEGAL_DOCUMENTS:
796      return AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS;
797    case AUTHENTICATE_INSTRUMENT:
798      return AutofillMetrics::AUTHENTICATE_INSTRUMENT;
799    case GET_FULL_WALLET:
800      return AutofillMetrics::GET_FULL_WALLET;
801    case GET_WALLET_ITEMS:
802      return AutofillMetrics::GET_WALLET_ITEMS;
803    case SAVE_TO_WALLET:
804      return AutofillMetrics::SAVE_TO_WALLET;
805    case NO_PENDING_REQUEST:
806      NOTREACHED();
807      return AutofillMetrics::UNKNOWN_API_CALL;
808  }
809
810  NOTREACHED();
811  return AutofillMetrics::UNKNOWN_API_CALL;
812}
813
814}  // namespace wallet
815}  // namespace autofill
816