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
31namespace autofill {
32namespace wallet {
33
34namespace {
35
36const char kFormEncodedMimeType[] = "application/x-www-form-urlencoded";
37const char kJsonMimeType[] = "application/json";
38const char kEscrowNewInstrumentFormat[] =
39    "request_content_type=application/json&request=%s&cvn=%s&card_number=%s";
40const char kEscrowCardVerificationNumberFormat[] =
41    "request_content_type=application/json&request=%s&cvn=%s";
42const char kGetFullWalletRequestFormat[] =
43    "request_content_type=application/json&request=%s&otp=%s:%s";
44const size_t kOneTimePadLength = 6;
45
46// The maximum number of bits in the one time pad that the server is willing to
47// accept.
48const size_t kMaxBits = 56;
49
50// The minimum number of bits in the one time pad that the server is willing to
51// accept.
52const size_t kMinBits = 40;
53
54std::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
66WalletClient::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|.
92WalletClient::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.
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::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.
183AutofillMetrics::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.
215const char kAcceptedLegalDocumentKey[] = "accepted_legal_document";
216const char kApiKeyKey[] = "api_key";
217const char kAuthResultKey[] = "auth_result";
218const char kErrorTypeKey[] = "wallet_error.error_type";
219const char kFeatureKey[] = "feature";
220const char kGoogleTransactionIdKey[] = "google_transaction_id";
221const char kInstrumentIdKey[] = "instrument_id";
222const char kInstrumentKey[] = "instrument";
223const char kInstrumentExpMonthKey[] = "instrument.credit_card.exp_month";
224const char kInstrumentExpYearKey[] = "instrument.credit_card.exp_year";
225const char kInstrumentType[] = "instrument.type";
226const char kInstrumentPhoneNumberKey[] = "instrument_phone_number";
227const char kMerchantDomainKey[] = "merchant_domain";
228const char kMessageTypeForBuyerKey[] = "wallet_error.message_type_for_buyer";
229const char kNewWalletUser[] = "new_wallet_user";
230const char kPhoneNumberRequired[] = "phone_number_required";
231const char kRiskCapabilitiesKey[] = "supported_risk_challenge";
232const char kRiskParamsKey[] = "risk_params";
233const char kSelectedAddressIdKey[] = "selected_address_id";
234const char kSelectedInstrumentIdKey[] = "selected_instrument_id";
235const char kShippingAddressIdKey[] = "shipping_address_id";
236const char kShippingAddressKey[] = "shipping_address";
237const char kShippingAddressRequired[] = "shipping_address_required";
238const char kTransactionAmountKey[] = "estimated_total_price";
239const char kTransactionCurrencyKey[] = "currency_code";
240const char kUpgradedBillingAddressKey[] = "upgraded_billing_address";
241const char kUpgradedInstrumentIdKey[] = "upgraded_instrument_id";
242const char kUseMinimalAddresses[] = "use_minimal_addresses";
243
244}  // namespace
245
246WalletClient::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
258WalletClient::FullWalletRequest::~FullWalletRequest() {}
259
260WalletClient::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
274WalletClient::~WalletClient() {}
275
276void 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
289void 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
314void 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
362void 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
462void 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
487bool WalletClient::HasRequestInProgress() const {
488  return request_;
489}
490
491void WalletClient::CancelRequest() {
492  request_.reset();
493  request_type_ = NO_REQUEST;
494}
495
496void WalletClient::SetUserIndex(size_t user_index) {
497  CancelRequest();
498  user_index_ = user_index;
499}
500
501void 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
526void 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.
552void 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
713void 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
723void 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|.
778void 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
786AutofillMetrics::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