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 namespace autofill {
     32 namespace wallet {
     33 
     34 namespace {
     35 
     36 const char kFormEncodedMimeType[] = "application/x-www-form-urlencoded";
     37 const char kJsonMimeType[] = "application/json";
     38 const char kEscrowNewInstrumentFormat[] =
     39     "request_content_type=application/json&request=%s&cvn=%s&card_number=%s";
     40 const char kEscrowCardVerificationNumberFormat[] =
     41     "request_content_type=application/json&request=%s&cvn=%s";
     42 const char kGetFullWalletRequestFormat[] =
     43     "request_content_type=application/json&request=%s&otp=%s:%s";
     44 const size_t kOneTimePadLength = 6;
     45 
     46 // The maximum number of bits in the one time pad that the server is willing to
     47 // accept.
     48 const size_t kMaxBits = 56;
     49 
     50 // The minimum number of bits in the one time pad that the server is willing to
     51 // accept.
     52 const size_t kMinBits = 40;
     53 
     54 std::string RiskCapabilityToString(
     55     WalletClient::RiskCapability risk_capability) {
     56   switch (risk_capability) {
     57     case WalletClient::RELOGIN:
     58       return "RELOGIN";
     59     case WalletClient::VERIFY_CVC:
     60       return "VERIFY_CVC";
     61   }
     62   NOTREACHED();
     63   return "NOT_POSSIBLE";
     64 }
     65 
     66 WalletClient::ErrorType StringToErrorType(const std::string& error_type) {
     67   std::string trimmed;
     68   base::TrimWhitespaceASCII(error_type, base::TRIM_ALL, &trimmed);
     69   if (LowerCaseEqualsASCII(trimmed, "buyer_account_error"))
     70     return WalletClient::BUYER_ACCOUNT_ERROR;
     71   if (LowerCaseEqualsASCII(trimmed, "unsupported_merchant"))
     72     return WalletClient::UNSUPPORTED_MERCHANT;
     73   if (LowerCaseEqualsASCII(trimmed, "internal_error"))
     74     return WalletClient::INTERNAL_ERROR;
     75   if (LowerCaseEqualsASCII(trimmed, "invalid_params"))
     76     return WalletClient::INVALID_PARAMS;
     77   if (LowerCaseEqualsASCII(trimmed, "service_unavailable"))
     78     return WalletClient::SERVICE_UNAVAILABLE;
     79   if (LowerCaseEqualsASCII(trimmed, "unsupported_api_version"))
     80     return WalletClient::UNSUPPORTED_API_VERSION;
     81   if (LowerCaseEqualsASCII(trimmed, "unsupported_user_agent"))
     82     return WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY;
     83   if (LowerCaseEqualsASCII(trimmed, "spending_limit_exceeded"))
     84     return WalletClient::SPENDING_LIMIT_EXCEEDED;
     85 
     86   DVLOG(1) << "Unknown wallet error string: \"" << error_type << '"';
     87   return WalletClient::UNKNOWN_ERROR;
     88 }
     89 
     90 // Get the more specific WalletClient::ErrorType when the error is
     91 // |BUYER_ACCOUNT_ERROR|.
     92 WalletClient::ErrorType BuyerErrorStringToErrorType(
     93     const std::string& message_type_for_buyer) {
     94   std::string trimmed;
     95   base::TrimWhitespaceASCII(message_type_for_buyer, base::TRIM_ALL, &trimmed);
     96   if (LowerCaseEqualsASCII(trimmed, "bla_country_not_supported"))
     97     return WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
     98   if (LowerCaseEqualsASCII(trimmed, "buyer_kyc_error"))
     99     return WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
    100 
    101   return WalletClient::BUYER_ACCOUNT_ERROR;
    102 }
    103 
    104 // Gets and parses required actions from a SaveToWallet response. Returns
    105 // false if any unknown required actions are seen and true otherwise.
    106 void GetRequiredActionsForSaveToWallet(
    107     const base::DictionaryValue& dict,
    108     std::vector<RequiredAction>* required_actions) {
    109   const base::ListValue* required_action_list;
    110   if (!dict.GetList("required_action", &required_action_list))
    111     return;
    112 
    113   for (size_t i = 0; i < required_action_list->GetSize(); ++i) {
    114     std::string action_string;
    115     if (required_action_list->GetString(i, &action_string)) {
    116       RequiredAction action = ParseRequiredActionFromString(action_string);
    117       if (!ActionAppliesToSaveToWallet(action)) {
    118         DLOG(ERROR) << "Response from Google wallet with bad required action:"
    119                        " \"" << action_string << "\"";
    120         required_actions->clear();
    121         return;
    122       }
    123       required_actions->push_back(action);
    124     }
    125   }
    126 }
    127 
    128 void GetFormFieldErrors(const base::DictionaryValue& dict,
    129                         std::vector<FormFieldError>* form_errors) {
    130   DCHECK(form_errors->empty());
    131   const base::ListValue* form_errors_list;
    132   if (!dict.GetList("form_field_error", &form_errors_list))
    133     return;
    134 
    135   for (size_t i = 0; i < form_errors_list->GetSize(); ++i) {
    136     const base::DictionaryValue* dictionary;
    137     if (form_errors_list->GetDictionary(i, &dictionary))
    138       form_errors->push_back(FormFieldError::CreateFormFieldError(*dictionary));
    139   }
    140 }
    141 
    142 // Converts the |error_type| to the corresponding value from the stable UMA
    143 // metric enumeration.
    144 AutofillMetrics::WalletErrorMetric ErrorTypeToUmaMetric(
    145     WalletClient::ErrorType error_type) {
    146   switch (error_type) {
    147     case WalletClient::BAD_REQUEST:
    148       return AutofillMetrics::WALLET_BAD_REQUEST;
    149     case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
    150       return AutofillMetrics::WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED;
    151     case WalletClient::BUYER_ACCOUNT_ERROR:
    152       return AutofillMetrics::WALLET_BUYER_ACCOUNT_ERROR;
    153     case WalletClient::INTERNAL_ERROR:
    154       return AutofillMetrics::WALLET_INTERNAL_ERROR;
    155     case WalletClient::INVALID_PARAMS:
    156       return AutofillMetrics::WALLET_INVALID_PARAMS;
    157     case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
    158       return AutofillMetrics::WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS;
    159     case WalletClient::SERVICE_UNAVAILABLE:
    160       return AutofillMetrics::WALLET_SERVICE_UNAVAILABLE;
    161     case WalletClient::UNSUPPORTED_API_VERSION:
    162       return AutofillMetrics::WALLET_UNSUPPORTED_API_VERSION;
    163     case WalletClient::UNSUPPORTED_MERCHANT:
    164       return AutofillMetrics::WALLET_UNSUPPORTED_MERCHANT;
    165     case WalletClient::SPENDING_LIMIT_EXCEEDED:
    166       return AutofillMetrics::WALLET_SPENDING_LIMIT_EXCEEDED;
    167     case WalletClient::MALFORMED_RESPONSE:
    168       return AutofillMetrics::WALLET_MALFORMED_RESPONSE;
    169     case WalletClient::NETWORK_ERROR:
    170       return AutofillMetrics::WALLET_NETWORK_ERROR;
    171     case WalletClient::UNKNOWN_ERROR:
    172       return AutofillMetrics::WALLET_UNKNOWN_ERROR;
    173     case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
    174       return AutofillMetrics::WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY;
    175   }
    176 
    177   NOTREACHED();
    178   return AutofillMetrics::WALLET_UNKNOWN_ERROR;
    179 }
    180 
    181 // Converts the |required_action| to the corresponding value from the stable UMA
    182 // metric enumeration.
    183 AutofillMetrics::WalletRequiredActionMetric RequiredActionToUmaMetric(
    184     RequiredAction required_action) {
    185   switch (required_action) {
    186     case UNKNOWN_TYPE:
    187       return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
    188     case CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS:
    189       return AutofillMetrics::CHOOSE_ANOTHER_INSTRUMENT_OR_ADDRESS;
    190     case SETUP_WALLET:
    191       return AutofillMetrics::SETUP_WALLET;
    192     case ACCEPT_TOS:
    193       return AutofillMetrics::ACCEPT_TOS;
    194     case GAIA_AUTH:
    195       return AutofillMetrics::GAIA_AUTH;
    196     case UPDATE_EXPIRATION_DATE:
    197       return AutofillMetrics::UPDATE_EXPIRATION_DATE;
    198     case UPGRADE_MIN_ADDRESS:
    199       return AutofillMetrics::UPGRADE_MIN_ADDRESS;
    200     case INVALID_FORM_FIELD:
    201       return AutofillMetrics::INVALID_FORM_FIELD;
    202     case VERIFY_CVV:
    203       return AutofillMetrics::VERIFY_CVV;
    204     case PASSIVE_GAIA_AUTH:
    205       return AutofillMetrics::PASSIVE_GAIA_AUTH;
    206     case REQUIRE_PHONE_NUMBER:
    207       return AutofillMetrics::REQUIRE_PHONE_NUMBER;
    208   }
    209 
    210   NOTREACHED();
    211   return AutofillMetrics::UNKNOWN_REQUIRED_ACTION;
    212 }
    213 
    214 // Keys for JSON communication with the Online Wallet server.
    215 const char kAcceptedLegalDocumentKey[] = "accepted_legal_document";
    216 const char kApiKeyKey[] = "api_key";
    217 const char kAuthResultKey[] = "auth_result";
    218 const char kErrorTypeKey[] = "wallet_error.error_type";
    219 const char kFeatureKey[] = "feature";
    220 const char kGoogleTransactionIdKey[] = "google_transaction_id";
    221 const char kInstrumentIdKey[] = "instrument_id";
    222 const char kInstrumentKey[] = "instrument";
    223 const char kInstrumentExpMonthKey[] = "instrument.credit_card.exp_month";
    224 const char kInstrumentExpYearKey[] = "instrument.credit_card.exp_year";
    225 const char kInstrumentType[] = "instrument.type";
    226 const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
    227 const char kMerchantDomainKey[] = "merchant_domain";
    228 const char kMessageTypeForBuyerKey[] = "wallet_error.message_type_for_buyer";
    229 const char kNewWalletUser[] = "new_wallet_user";
    230 const char kPhoneNumberRequired[] = "phone_number_required";
    231 const char kRiskCapabilitiesKey[] = "supported_risk_challenge";
    232 const char kRiskParamsKey[] = "risk_params";
    233 const char kSelectedAddressIdKey[] = "selected_address_id";
    234 const char kSelectedInstrumentIdKey[] = "selected_instrument_id";
    235 const char kShippingAddressIdKey[] = "shipping_address_id";
    236 const char kShippingAddressKey[] = "shipping_address";
    237 const char kShippingAddressRequired[] = "shipping_address_required";
    238 const char kTransactionAmountKey[] = "estimated_total_price";
    239 const char kTransactionCurrencyKey[] = "currency_code";
    240 const char kUpgradedBillingAddressKey[] = "upgraded_billing_address";
    241 const char kUpgradedInstrumentIdKey[] = "upgraded_instrument_id";
    242 const char kUseMinimalAddresses[] = "use_minimal_addresses";
    243 
    244 }  // namespace
    245 
    246 WalletClient::FullWalletRequest::FullWalletRequest(
    247     const std::string& instrument_id,
    248     const std::string& address_id,
    249     const std::string& google_transaction_id,
    250     const std::vector<RiskCapability> risk_capabilities,
    251     bool new_wallet_user)
    252     : instrument_id(instrument_id),
    253       address_id(address_id),
    254       google_transaction_id(google_transaction_id),
    255       risk_capabilities(risk_capabilities),
    256       new_wallet_user(new_wallet_user) {}
    257 
    258 WalletClient::FullWalletRequest::~FullWalletRequest() {}
    259 
    260 WalletClient::WalletClient(net::URLRequestContextGetter* context_getter,
    261                            WalletClientDelegate* delegate,
    262                            const GURL& source_url)
    263     : context_getter_(context_getter),
    264       delegate_(delegate),
    265       user_index_(0U),
    266       source_url_(source_url),
    267       request_type_(NO_REQUEST),
    268       one_time_pad_(kOneTimePadLength),
    269       weak_ptr_factory_(this) {
    270   DCHECK(context_getter_.get());
    271   DCHECK(delegate_);
    272 }
    273 
    274 WalletClient::~WalletClient() {}
    275 
    276 void WalletClient::AcceptLegalDocuments(
    277     const std::vector<WalletItems::LegalDocument*>& documents,
    278     const std::string& google_transaction_id) {
    279   if (documents.empty())
    280     return;
    281 
    282   std::vector<std::string> document_ids;
    283   for (size_t i = 0; i < documents.size(); ++i) {
    284     document_ids.push_back(documents[i]->id());
    285   }
    286   DoAcceptLegalDocuments(document_ids, google_transaction_id);
    287 }
    288 
    289 void WalletClient::AuthenticateInstrument(
    290     const std::string& instrument_id,
    291     const std::string& card_verification_number) {
    292   base::DictionaryValue request_dict;
    293   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
    294   request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
    295   request_dict.SetString(kInstrumentIdKey, instrument_id);
    296 
    297   std::string json_payload;
    298   base::JSONWriter::Write(&request_dict, &json_payload);
    299 
    300   std::string escaped_card_verification_number = net::EscapeUrlEncodedData(
    301       card_verification_number, true);
    302 
    303   std::string post_body = base::StringPrintf(
    304       kEscrowCardVerificationNumberFormat,
    305       net::EscapeUrlEncodedData(json_payload, true).c_str(),
    306       escaped_card_verification_number.c_str());
    307 
    308   MakeWalletRequest(GetAuthenticateInstrumentUrl(user_index_),
    309                     post_body,
    310                     kFormEncodedMimeType,
    311                     AUTHENTICATE_INSTRUMENT);
    312 }
    313 
    314 void WalletClient::GetFullWallet(const FullWalletRequest& full_wallet_request) {
    315   base::DictionaryValue request_dict;
    316   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
    317   request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
    318   request_dict.SetBoolean(kUseMinimalAddresses, false);
    319   request_dict.SetBoolean(kPhoneNumberRequired, true);
    320   request_dict.SetBoolean(kNewWalletUser, full_wallet_request.new_wallet_user);
    321 
    322   request_dict.SetString(kSelectedInstrumentIdKey,
    323                          full_wallet_request.instrument_id);
    324   request_dict.SetString(kSelectedAddressIdKey, full_wallet_request.address_id);
    325   request_dict.SetString(
    326       kMerchantDomainKey,
    327       source_url_.GetWithEmptyPath().spec());
    328   request_dict.SetString(kGoogleTransactionIdKey,
    329                          full_wallet_request.google_transaction_id);
    330   request_dict.SetString(kFeatureKey, "REQUEST_AUTOCOMPLETE");
    331 
    332   scoped_ptr<base::ListValue> risk_capabilities_list(new base::ListValue());
    333   for (std::vector<RiskCapability>::const_iterator it =
    334            full_wallet_request.risk_capabilities.begin();
    335        it != full_wallet_request.risk_capabilities.end();
    336        ++it) {
    337     risk_capabilities_list->AppendString(RiskCapabilityToString(*it));
    338   }
    339   request_dict.Set(kRiskCapabilitiesKey, risk_capabilities_list.release());
    340 
    341   std::string json_payload;
    342   base::JSONWriter::Write(&request_dict, &json_payload);
    343 
    344   crypto::RandBytes(&(one_time_pad_[0]), one_time_pad_.size());
    345 
    346   size_t num_bits = one_time_pad_.size() * 8;
    347   DCHECK_LE(num_bits, kMaxBits);
    348   DCHECK_GE(num_bits, kMinBits);
    349 
    350   std::string post_body = base::StringPrintf(
    351       kGetFullWalletRequestFormat,
    352       net::EscapeUrlEncodedData(json_payload, true).c_str(),
    353       base::HexEncode(&num_bits, 1).c_str(),
    354       base::HexEncode(&(one_time_pad_[0]), one_time_pad_.size()).c_str());
    355 
    356   MakeWalletRequest(GetGetFullWalletUrl(user_index_),
    357                     post_body,
    358                     kFormEncodedMimeType,
    359                     GET_FULL_WALLET);
    360 }
    361 
    362 void WalletClient::SaveToWallet(
    363     scoped_ptr<Instrument> instrument,
    364     scoped_ptr<Address> address,
    365     const WalletItems::MaskedInstrument* reference_instrument,
    366     const Address* reference_address) {
    367   DCHECK(instrument || address);
    368 
    369   base::DictionaryValue request_dict;
    370   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
    371   request_dict.SetString(kRiskParamsKey, delegate_->GetRiskData());
    372   request_dict.SetString(kMerchantDomainKey,
    373                          source_url_.GetWithEmptyPath().spec());
    374   request_dict.SetBoolean(kUseMinimalAddresses, false);
    375   request_dict.SetBoolean(kPhoneNumberRequired, true);
    376 
    377   std::string primary_account_number;
    378   std::string card_verification_number;
    379   if (instrument) {
    380     primary_account_number = net::EscapeUrlEncodedData(
    381         base::UTF16ToUTF8(instrument->primary_account_number()), true);
    382     card_verification_number = net::EscapeUrlEncodedData(
    383         base::UTF16ToUTF8(instrument->card_verification_number()), true);
    384 
    385     if (!reference_instrument) {
    386       request_dict.Set(kInstrumentKey, instrument->ToDictionary().release());
    387       request_dict.SetString(kInstrumentPhoneNumberKey,
    388                              instrument->address()->phone_number());
    389     } else {
    390       DCHECK(!reference_instrument->object_id().empty());
    391 
    392       int new_month = instrument->expiration_month();
    393       int new_year = instrument->expiration_year();
    394       bool expiration_date_changed =
    395           new_month != reference_instrument->expiration_month() ||
    396           new_year != reference_instrument->expiration_year();
    397 
    398       DCHECK(instrument->address() || expiration_date_changed);
    399 
    400       request_dict.SetString(kUpgradedInstrumentIdKey,
    401                              reference_instrument->object_id());
    402 
    403       if (instrument->address()) {
    404         request_dict.SetString(kInstrumentPhoneNumberKey,
    405                                instrument->address()->phone_number());
    406         request_dict.Set(
    407             kUpgradedBillingAddressKey,
    408             instrument->address()->ToDictionaryWithoutID().release());
    409       }
    410 
    411       if (expiration_date_changed) {
    412         // Updating expiration date requires a CVC.
    413         DCHECK(!instrument->card_verification_number().empty());
    414         request_dict.SetInteger(kInstrumentExpMonthKey,
    415                                 instrument->expiration_month());
    416         request_dict.SetInteger(kInstrumentExpYearKey,
    417                                 instrument->expiration_year());
    418       }
    419 
    420       if (request_dict.HasKey(kInstrumentKey))
    421         request_dict.SetString(kInstrumentType, "CREDIT_CARD");
    422     }
    423   }
    424   if (address) {
    425     if (reference_address) {
    426       address->set_object_id(reference_address->object_id());
    427       DCHECK(!address->object_id().empty());
    428     }
    429     request_dict.Set(kShippingAddressKey,
    430                      address->ToDictionaryWithID().release());
    431   }
    432 
    433   std::string json_payload;
    434   base::JSONWriter::Write(&request_dict, &json_payload);
    435 
    436   if (!card_verification_number.empty()) {
    437     std::string post_body;
    438     if (!primary_account_number.empty()) {
    439       post_body = base::StringPrintf(
    440           kEscrowNewInstrumentFormat,
    441           net::EscapeUrlEncodedData(json_payload, true).c_str(),
    442           card_verification_number.c_str(),
    443           primary_account_number.c_str());
    444     } else {
    445       post_body = base::StringPrintf(
    446           kEscrowCardVerificationNumberFormat,
    447           net::EscapeUrlEncodedData(json_payload, true).c_str(),
    448           card_verification_number.c_str());
    449     }
    450     MakeWalletRequest(GetSaveToWalletUrl(user_index_),
    451                       post_body,
    452                       kFormEncodedMimeType,
    453                       SAVE_TO_WALLET);
    454   } else {
    455     MakeWalletRequest(GetSaveToWalletNoEscrowUrl(user_index_),
    456                       json_payload,
    457                       kJsonMimeType,
    458                       SAVE_TO_WALLET);
    459   }
    460 }
    461 
    462 void WalletClient::GetWalletItems(const base::string16& amount,
    463                                   const base::string16& currency) {
    464   base::DictionaryValue request_dict;
    465   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
    466   request_dict.SetString(kMerchantDomainKey,
    467                          source_url_.GetWithEmptyPath().spec());
    468   request_dict.SetBoolean(kShippingAddressRequired,
    469                           delegate_->IsShippingAddressRequired());
    470   request_dict.SetBoolean(kUseMinimalAddresses, false);
    471   request_dict.SetBoolean(kPhoneNumberRequired, true);
    472 
    473   if (!amount.empty())
    474     request_dict.SetString(kTransactionAmountKey, amount);
    475   if (!currency.empty())
    476     request_dict.SetString(kTransactionCurrencyKey, currency);
    477 
    478   std::string post_body;
    479   base::JSONWriter::Write(&request_dict, &post_body);
    480 
    481   MakeWalletRequest(GetGetWalletItemsUrl(user_index_),
    482                     post_body,
    483                     kJsonMimeType,
    484                     GET_WALLET_ITEMS);
    485 }
    486 
    487 bool WalletClient::HasRequestInProgress() const {
    488   return request_;
    489 }
    490 
    491 void WalletClient::CancelRequest() {
    492   request_.reset();
    493   request_type_ = NO_REQUEST;
    494 }
    495 
    496 void WalletClient::SetUserIndex(size_t user_index) {
    497   CancelRequest();
    498   user_index_ = user_index;
    499 }
    500 
    501 void WalletClient::DoAcceptLegalDocuments(
    502     const std::vector<std::string>& document_ids,
    503     const std::string& google_transaction_id) {
    504   base::DictionaryValue request_dict;
    505   request_dict.SetString(kApiKeyKey, google_apis::GetAPIKey());
    506   request_dict.SetString(kGoogleTransactionIdKey, google_transaction_id);
    507   request_dict.SetString(kMerchantDomainKey,
    508                          source_url_.GetWithEmptyPath().spec());
    509   scoped_ptr<base::ListValue> docs_list(new base::ListValue());
    510   for (std::vector<std::string>::const_iterator it = document_ids.begin();
    511        it != document_ids.end(); ++it) {
    512     if (!it->empty())
    513       docs_list->AppendString(*it);
    514   }
    515   request_dict.Set(kAcceptedLegalDocumentKey, docs_list.release());
    516 
    517   std::string post_body;
    518   base::JSONWriter::Write(&request_dict, &post_body);
    519 
    520   MakeWalletRequest(GetAcceptLegalDocumentsUrl(user_index_),
    521                     post_body,
    522                     kJsonMimeType,
    523                     ACCEPT_LEGAL_DOCUMENTS);
    524 }
    525 
    526 void WalletClient::MakeWalletRequest(const GURL& url,
    527                                      const std::string& post_body,
    528                                      const std::string& mime_type,
    529                                      RequestType request_type) {
    530   DCHECK_EQ(request_type_, NO_REQUEST);
    531   request_type_ = request_type;
    532 
    533   request_.reset(net::URLFetcher::Create(
    534       0, url, net::URLFetcher::POST, this));
    535   request_->SetRequestContext(context_getter_.get());
    536   DVLOG(1) << "Making request to " << url << " with post_body=" << post_body;
    537   request_->SetUploadData(mime_type, post_body);
    538   request_->AddExtraRequestHeader("Authorization: GoogleLogin auth=" +
    539                                   delegate_->GetWalletCookieValue());
    540   DVLOG(1) << "Setting authorization header value to "
    541            << delegate_->GetWalletCookieValue();
    542   request_started_timestamp_ = base::Time::Now();
    543   request_->Start();
    544 
    545   delegate_->GetMetricLogger().LogWalletErrorMetric(
    546       AutofillMetrics::WALLET_ERROR_BASELINE_ISSUED_REQUEST);
    547   delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
    548       AutofillMetrics::WALLET_REQUIRED_ACTION_BASELINE_ISSUED_REQUEST);
    549 }
    550 
    551 // TODO(ahutter): Add manual retry logic if it's necessary.
    552 void WalletClient::OnURLFetchComplete(
    553     const net::URLFetcher* source) {
    554   delegate_->GetMetricLogger().LogWalletApiCallDuration(
    555       RequestTypeToUmaMetric(request_type_),
    556       base::Time::Now() - request_started_timestamp_);
    557 
    558   DCHECK_EQ(source, request_.get());
    559   DVLOG(1) << "Got response from " << source->GetOriginalURL();
    560 
    561   // |request_|, which is aliased to |source|, might continue to be used in this
    562   // |method, but should be freed once control leaves the method.
    563   scoped_ptr<net::URLFetcher> scoped_request(request_.Pass());
    564 
    565   std::string data;
    566   source->GetResponseAsString(&data);
    567   DVLOG(1) << "Response body: " << data;
    568 
    569   scoped_ptr<base::DictionaryValue> response_dict;
    570 
    571   int response_code = source->GetResponseCode();
    572   delegate_->GetMetricLogger().LogWalletResponseCode(response_code);
    573 
    574   switch (response_code) {
    575     // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
    576     case net::HTTP_BAD_REQUEST: {
    577       request_type_ = NO_REQUEST;
    578       HandleWalletError(BAD_REQUEST);
    579       return;
    580     }
    581 
    582     // Valid response.
    583     case net::HTTP_OK: {
    584       scoped_ptr<base::Value> message_value(base::JSONReader::Read(data));
    585       if (message_value.get() &&
    586           message_value->IsType(base::Value::TYPE_DICTIONARY)) {
    587         response_dict.reset(
    588             static_cast<base::DictionaryValue*>(message_value.release()));
    589       }
    590       break;
    591     }
    592 
    593     // Response contains an error to show the user.
    594     case net::HTTP_FORBIDDEN:
    595     case net::HTTP_INTERNAL_SERVER_ERROR: {
    596       scoped_ptr<base::Value> message_value(base::JSONReader::Read(data));
    597       if (message_value.get() &&
    598           message_value->IsType(base::Value::TYPE_DICTIONARY)) {
    599         response_dict.reset(
    600             static_cast<base::DictionaryValue*>(message_value.release()));
    601       }
    602 
    603       request_type_ = NO_REQUEST;
    604 
    605       std::string error_type_string;
    606       if (!response_dict->GetString(kErrorTypeKey, &error_type_string)) {
    607         HandleWalletError(UNKNOWN_ERROR);
    608         return;
    609       }
    610       WalletClient::ErrorType error_type = StringToErrorType(error_type_string);
    611       if (error_type == BUYER_ACCOUNT_ERROR) {
    612         // If the error_type is |BUYER_ACCOUNT_ERROR|, then
    613         // message_type_for_buyer field contains more specific information
    614         // about the error.
    615         std::string message_type_for_buyer_string;
    616         if (response_dict->GetString(kMessageTypeForBuyerKey,
    617                                      &message_type_for_buyer_string)) {
    618           error_type =
    619               BuyerErrorStringToErrorType(message_type_for_buyer_string);
    620         }
    621       }
    622 
    623       HandleWalletError(error_type);
    624       return;
    625     }
    626 
    627     // Handle anything else as a generic error.
    628     default:
    629       request_type_ = NO_REQUEST;
    630       HandleWalletError(NETWORK_ERROR);
    631       return;
    632   }
    633 
    634   RequestType type = request_type_;
    635   request_type_ = NO_REQUEST;
    636 
    637   if (type != ACCEPT_LEGAL_DOCUMENTS && !response_dict) {
    638     HandleMalformedResponse(type, scoped_request.get());
    639     return;
    640   }
    641 
    642   switch (type) {
    643     case ACCEPT_LEGAL_DOCUMENTS:
    644       delegate_->OnDidAcceptLegalDocuments();
    645       break;
    646 
    647     case AUTHENTICATE_INSTRUMENT: {
    648       std::string auth_result;
    649       if (response_dict->GetString(kAuthResultKey, &auth_result)) {
    650         std::string trimmed;
    651         base::TrimWhitespaceASCII(auth_result, base::TRIM_ALL, &trimmed);
    652         delegate_->OnDidAuthenticateInstrument(
    653             LowerCaseEqualsASCII(trimmed, "success"));
    654       } else {
    655         HandleMalformedResponse(type, scoped_request.get());
    656       }
    657       break;
    658     }
    659 
    660     case GET_FULL_WALLET: {
    661       scoped_ptr<FullWallet> full_wallet(
    662           FullWallet::CreateFullWallet(*response_dict));
    663       if (full_wallet) {
    664         full_wallet->set_one_time_pad(one_time_pad_);
    665         LogRequiredActions(full_wallet->required_actions());
    666         delegate_->OnDidGetFullWallet(full_wallet.Pass());
    667       } else {
    668         HandleMalformedResponse(type, scoped_request.get());
    669       }
    670       break;
    671     }
    672 
    673     case GET_WALLET_ITEMS: {
    674       scoped_ptr<WalletItems> wallet_items(
    675           WalletItems::CreateWalletItems(*response_dict));
    676       if (wallet_items) {
    677         LogRequiredActions(wallet_items->required_actions());
    678         delegate_->OnDidGetWalletItems(wallet_items.Pass());
    679       } else {
    680         HandleMalformedResponse(type, scoped_request.get());
    681       }
    682       break;
    683     }
    684 
    685     case SAVE_TO_WALLET: {
    686       std::string instrument_id;
    687       response_dict->GetString(kInstrumentIdKey, &instrument_id);
    688       std::string shipping_address_id;
    689       response_dict->GetString(kShippingAddressIdKey,
    690                                &shipping_address_id);
    691       std::vector<RequiredAction> required_actions;
    692       GetRequiredActionsForSaveToWallet(*response_dict, &required_actions);
    693       std::vector<FormFieldError> form_errors;
    694       GetFormFieldErrors(*response_dict, &form_errors);
    695       if (instrument_id.empty() && shipping_address_id.empty() &&
    696           required_actions.empty()) {
    697         HandleMalformedResponse(type, scoped_request.get());
    698       } else {
    699         LogRequiredActions(required_actions);
    700         delegate_->OnDidSaveToWallet(instrument_id,
    701                                      shipping_address_id,
    702                                      required_actions,
    703                                      form_errors);
    704       }
    705       break;
    706     }
    707 
    708     case NO_REQUEST:
    709       NOTREACHED();
    710   }
    711 }
    712 
    713 void WalletClient::HandleMalformedResponse(RequestType request_type,
    714                                            net::URLFetcher* request) {
    715   // Called to inform exponential backoff logic of the error.
    716   request->ReceivedContentWasMalformed();
    717   // Record failed API call in metrics.
    718   delegate_->GetMetricLogger().LogWalletMalformedResponseMetric(
    719     RequestTypeToUmaMetric(request_type));
    720   HandleWalletError(MALFORMED_RESPONSE);
    721 }
    722 
    723 void WalletClient::HandleWalletError(WalletClient::ErrorType error_type) {
    724   std::string error_message;
    725   switch (error_type) {
    726     case WalletClient::BAD_REQUEST:
    727       error_message = "WALLET_BAD_REQUEST";
    728       break;
    729     case WalletClient::BUYER_LEGAL_ADDRESS_NOT_SUPPORTED:
    730       error_message = "WALLET_BUYER_LEGAL_ADDRESS_NOT_SUPPORTED";
    731       break;
    732     case WalletClient::BUYER_ACCOUNT_ERROR:
    733       error_message = "WALLET_BUYER_ACCOUNT_ERROR";
    734       break;
    735     case WalletClient::INTERNAL_ERROR:
    736       error_message = "WALLET_INTERNAL_ERROR";
    737       break;
    738     case WalletClient::INVALID_PARAMS:
    739       error_message = "WALLET_INVALID_PARAMS";
    740       break;
    741     case WalletClient::UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS:
    742       error_message = "WALLET_UNVERIFIED_KNOW_YOUR_CUSTOMER_STATUS";
    743       break;
    744     case WalletClient::SPENDING_LIMIT_EXCEEDED:
    745       error_message = "SPENDING_LIMIT_EXCEEDED";
    746       break;
    747     case WalletClient::SERVICE_UNAVAILABLE:
    748       error_message = "WALLET_SERVICE_UNAVAILABLE";
    749       break;
    750     case WalletClient::UNSUPPORTED_API_VERSION:
    751       error_message = "WALLET_UNSUPPORTED_API_VERSION";
    752       break;
    753     case WalletClient::UNSUPPORTED_MERCHANT:
    754       error_message = "WALLET_UNSUPPORTED_MERCHANT";
    755       break;
    756     case WalletClient::MALFORMED_RESPONSE:
    757       error_message = "WALLET_MALFORMED_RESPONSE";
    758       break;
    759     case WalletClient::NETWORK_ERROR:
    760       error_message = "WALLET_NETWORK_ERROR";
    761       break;
    762     case WalletClient::UNKNOWN_ERROR:
    763       error_message = "WALLET_UNKNOWN_ERROR";
    764       break;
    765     case WalletClient::UNSUPPORTED_USER_AGENT_OR_API_KEY:
    766       error_message = "WALLET_UNSUPPORTED_USER_AGENT_OR_API_KEY";
    767       break;
    768   }
    769 
    770   DVLOG(1) << "Wallet encountered a " << error_message;
    771 
    772   delegate_->OnWalletError(error_type);
    773   delegate_->GetMetricLogger().LogWalletErrorMetric(
    774       ErrorTypeToUmaMetric(error_type));
    775 }
    776 
    777 // Logs an UMA metric for each of the |required_actions|.
    778 void WalletClient::LogRequiredActions(
    779     const std::vector<RequiredAction>& required_actions) const {
    780   for (size_t i = 0; i < required_actions.size(); ++i) {
    781     delegate_->GetMetricLogger().LogWalletRequiredActionMetric(
    782         RequiredActionToUmaMetric(required_actions[i]));
    783   }
    784 }
    785 
    786 AutofillMetrics::WalletApiCallMetric WalletClient::RequestTypeToUmaMetric(
    787     RequestType request_type) const {
    788   switch (request_type) {
    789     case ACCEPT_LEGAL_DOCUMENTS:
    790       return AutofillMetrics::ACCEPT_LEGAL_DOCUMENTS;
    791     case AUTHENTICATE_INSTRUMENT:
    792       return AutofillMetrics::AUTHENTICATE_INSTRUMENT;
    793     case GET_FULL_WALLET:
    794       return AutofillMetrics::GET_FULL_WALLET;
    795     case GET_WALLET_ITEMS:
    796       return AutofillMetrics::GET_WALLET_ITEMS;
    797     case SAVE_TO_WALLET:
    798       return AutofillMetrics::SAVE_TO_WALLET;
    799     case NO_REQUEST:
    800       NOTREACHED();
    801       return AutofillMetrics::UNKNOWN_API_CALL;
    802   }
    803 
    804   NOTREACHED();
    805   return AutofillMetrics::UNKNOWN_API_CALL;
    806 }
    807 
    808 }  // namespace wallet
    809 }  // namespace autofill
    810