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