Home | History | Annotate | Download | only in wallet
      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   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 
    308 void 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 
    356 void 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 
    456 void 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 
    475 bool WalletClient::HasRequestInProgress() const {
    476   return request_;
    477 }
    478 
    479 void WalletClient::CancelRequests() {
    480   request_.reset();
    481   request_type_ = NO_PENDING_REQUEST;
    482   while (!pending_requests_.empty()) {
    483     pending_requests_.pop();
    484   }
    485 }
    486 
    487 void WalletClient::SetUserIndex(size_t user_index) {
    488   CancelRequests();
    489   user_index_ = user_index;
    490 }
    491 
    492 void 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 
    517 void 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.
    553 void 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 
    716 void 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 
    725 void 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 
    735 void 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|.
    784 void 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 
    792 AutofillMetrics::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