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