OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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/core/browser/payments/payments_client.h" |
| 6 |
| 7 #include <memory> |
| 8 #include <utility> |
| 9 #include <vector> |
| 10 |
| 11 #include "base/command_line.h" |
| 12 #include "base/json/json_reader.h" |
| 13 #include "base/json/json_writer.h" |
| 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/string_util.h" |
| 17 #include "base/strings/stringprintf.h" |
| 18 #include "base/strings/utf_string_conversions.h" |
| 19 #include "base/values.h" |
| 20 #include "build/build_config.h" |
| 21 #include "components/autofill/core/browser/autofill_data_model.h" |
| 22 #include "components/autofill/core/browser/autofill_type.h" |
| 23 #include "components/autofill/core/browser/credit_card.h" |
| 24 #include "components/autofill/core/browser/payments/payments_request.h" |
| 25 #include "components/autofill/core/browser/payments/payments_service_url.h" |
| 26 #include "components/data_use_measurement/core/data_use_user_data.h" |
| 27 #include "google_apis/gaia/identity_provider.h" |
| 28 #include "net/base/escape.h" |
| 29 #include "net/base/load_flags.h" |
| 30 #include "net/http/http_status_code.h" |
| 31 #include "net/traffic_annotation/network_traffic_annotation.h" |
| 32 #include "net/url_request/url_fetcher.h" |
| 33 #include "net/url_request/url_request_context_getter.h" |
| 34 |
| 35 namespace autofill { |
| 36 namespace payments { |
| 37 |
| 38 namespace { |
| 39 |
| 40 const char kUnmaskCardRequestPath[] = |
| 41 "payments/apis-secure/creditcardservice/getrealpan?s7e_suffix=chromewallet"; |
| 42 const char kUnmaskCardRequestFormat[] = |
| 43 "requestContentType=application/json; charset=utf-8&request=%s" |
| 44 "&s7e_13_cvc=%s"; |
| 45 |
| 46 const char kGetUploadDetailsRequestPath[] = |
| 47 "payments/apis/chromepaymentsservice/getdetailsforsavecard"; |
| 48 |
| 49 const char kUploadCardRequestPath[] = |
| 50 "payments/apis-secure/chromepaymentsservice/savecard" |
| 51 "?s7e_suffix=chromewallet"; |
| 52 const char kUploadCardRequestFormat[] = |
| 53 "requestContentType=application/json; charset=utf-8&request=%s" |
| 54 "&s7e_1_pan=%s&s7e_13_cvc=%s"; |
| 55 |
| 56 const char kTokenServiceConsumerId[] = "wallet_client"; |
| 57 const char kPaymentsOAuth2Scope[] = |
| 58 "https://www.googleapis.com/auth/wallet.chrome"; |
| 59 |
| 60 GURL GetRequestUrl(const std::string& path) { |
| 61 if (base::CommandLine::ForCurrentProcess()->HasSwitch("sync-url")) { |
| 62 if (IsPaymentsProductionEnabled()) { |
| 63 LOG(ERROR) << "You are using production Payments but you specified a " |
| 64 "--sync-url. You likely want to disable the sync sandbox " |
| 65 "or switch to sandbox Payments. Both are controlled in " |
| 66 "about:flags."; |
| 67 } |
| 68 } else if (!IsPaymentsProductionEnabled()) { |
| 69 LOG(ERROR) << "You are using sandbox Payments but you didn't specify a " |
| 70 "--sync-url. You likely want to enable the sync sandbox " |
| 71 "or switch to production Payments. Both are controlled in " |
| 72 "about:flags."; |
| 73 } |
| 74 |
| 75 return GetBaseSecureUrl().Resolve(path); |
| 76 } |
| 77 |
| 78 std::unique_ptr<base::DictionaryValue> BuildRiskDictionary( |
| 79 const std::string& encoded_risk_data) { |
| 80 std::unique_ptr<base::DictionaryValue> risk_data(new base::DictionaryValue()); |
| 81 #if defined(OS_IOS) |
| 82 // Browser fingerprinting is not available on iOS. Instead, we generate |
| 83 // RiskAdvisoryData. |
| 84 risk_data->SetString("message_type", "RISK_ADVISORY_DATA"); |
| 85 risk_data->SetString("encoding_type", "BASE_64_URL"); |
| 86 #else |
| 87 risk_data->SetString("message_type", "BROWSER_NATIVE_FINGERPRINTING"); |
| 88 risk_data->SetString("encoding_type", "BASE_64"); |
| 89 #endif |
| 90 |
| 91 risk_data->SetString("value", encoded_risk_data); |
| 92 |
| 93 return risk_data; |
| 94 } |
| 95 |
| 96 void SetStringIfNotEmpty(const AutofillDataModel& profile, |
| 97 const ServerFieldType& type, |
| 98 const std::string& app_locale, |
| 99 const std::string& path, |
| 100 base::DictionaryValue* dictionary) { |
| 101 const base::string16 value = profile.GetInfo(AutofillType(type), app_locale); |
| 102 if (!value.empty()) |
| 103 dictionary->SetString(path, value); |
| 104 } |
| 105 |
| 106 void AppendStringIfNotEmpty(const AutofillProfile& profile, |
| 107 const ServerFieldType& type, |
| 108 const std::string& app_locale, |
| 109 base::ListValue* list) { |
| 110 const base::string16 value = profile.GetInfo(AutofillType(type), app_locale); |
| 111 if (!value.empty()) |
| 112 list->AppendString(value); |
| 113 } |
| 114 |
| 115 // Returns a dictionary with the structure expected by Payments RPCs, containing |
| 116 // each of the fields in |profile|, formatted according to |app_locale|. If |
| 117 // |include_non_location_data| is false, the name and phone number in |profile| |
| 118 // are not included. |
| 119 std::unique_ptr<base::DictionaryValue> BuildAddressDictionary( |
| 120 const AutofillProfile& profile, |
| 121 const std::string& app_locale, |
| 122 bool include_non_location_data) { |
| 123 std::unique_ptr<base::DictionaryValue> postal_address( |
| 124 new base::DictionaryValue()); |
| 125 |
| 126 if (include_non_location_data) { |
| 127 SetStringIfNotEmpty(profile, NAME_FULL, app_locale, |
| 128 PaymentsClient::kRecipientName, postal_address.get()); |
| 129 } |
| 130 |
| 131 std::unique_ptr<base::ListValue> address_lines(new base::ListValue()); |
| 132 AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE1, app_locale, |
| 133 address_lines.get()); |
| 134 AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE2, app_locale, |
| 135 address_lines.get()); |
| 136 AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE3, app_locale, |
| 137 address_lines.get()); |
| 138 if (!address_lines->empty()) |
| 139 postal_address->Set("address_line", std::move(address_lines)); |
| 140 |
| 141 SetStringIfNotEmpty(profile, ADDRESS_HOME_CITY, app_locale, "locality_name", |
| 142 postal_address.get()); |
| 143 SetStringIfNotEmpty(profile, ADDRESS_HOME_STATE, app_locale, |
| 144 "administrative_area_name", postal_address.get()); |
| 145 SetStringIfNotEmpty(profile, ADDRESS_HOME_ZIP, app_locale, |
| 146 "postal_code_number", postal_address.get()); |
| 147 |
| 148 // Use GetRawInfo to get a country code instead of the country name: |
| 149 const base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY); |
| 150 if (!country_code.empty()) |
| 151 postal_address->SetString("country_name_code", country_code); |
| 152 |
| 153 std::unique_ptr<base::DictionaryValue> address(new base::DictionaryValue()); |
| 154 address->Set("postal_address", std::move(postal_address)); |
| 155 |
| 156 if (include_non_location_data) { |
| 157 SetStringIfNotEmpty(profile, PHONE_HOME_WHOLE_NUMBER, app_locale, |
| 158 PaymentsClient::kPhoneNumber, address.get()); |
| 159 } |
| 160 |
| 161 return address; |
| 162 } |
| 163 |
| 164 class UnmaskCardRequest : public PaymentsRequest { |
| 165 public: |
| 166 UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details) |
| 167 : request_details_(request_details) { |
| 168 DCHECK(CreditCard::MASKED_SERVER_CARD == |
| 169 request_details.card.record_type() || |
| 170 CreditCard::FULL_SERVER_CARD == request_details.card.record_type()); |
| 171 } |
| 172 ~UnmaskCardRequest() override {} |
| 173 |
| 174 std::string GetRequestUrlPath() override { return kUnmaskCardRequestPath; } |
| 175 |
| 176 std::string GetRequestContentType() override { |
| 177 return "application/x-www-form-urlencoded"; |
| 178 } |
| 179 |
| 180 std::string GetRequestContent() override { |
| 181 base::DictionaryValue request_dict; |
| 182 request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc"); |
| 183 request_dict.SetString("credit_card_id", request_details_.card.server_id()); |
| 184 request_dict.Set("risk_data_encoded", |
| 185 BuildRiskDictionary(request_details_.risk_data)); |
| 186 request_dict.Set("context", base::MakeUnique<base::DictionaryValue>()); |
| 187 |
| 188 int value = 0; |
| 189 if (base::StringToInt(request_details_.user_response.exp_month, &value)) |
| 190 request_dict.SetInteger("expiration_month", value); |
| 191 if (base::StringToInt(request_details_.user_response.exp_year, &value)) |
| 192 request_dict.SetInteger("expiration_year", value); |
| 193 |
| 194 std::string json_request; |
| 195 base::JSONWriter::Write(request_dict, &json_request); |
| 196 std::string request_content = base::StringPrintf( |
| 197 kUnmaskCardRequestFormat, |
| 198 net::EscapeUrlEncodedData(json_request, true).c_str(), |
| 199 net::EscapeUrlEncodedData( |
| 200 base::UTF16ToASCII(request_details_.user_response.cvc), true) |
| 201 .c_str()); |
| 202 VLOG(3) << "getrealpan request body: " << request_content; |
| 203 return request_content; |
| 204 } |
| 205 |
| 206 void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override { |
| 207 response->GetString("pan", &real_pan_); |
| 208 } |
| 209 |
| 210 bool IsResponseComplete() override { return !real_pan_.empty(); } |
| 211 |
| 212 void RespondToDelegate(PaymentsClientDelegate* delegate, |
| 213 AutofillClient::PaymentsRpcResult result) override { |
| 214 delegate->OnDidGetRealPan(result, real_pan_); |
| 215 } |
| 216 |
| 217 private: |
| 218 PaymentsClient::UnmaskRequestDetails request_details_; |
| 219 std::string real_pan_; |
| 220 }; |
| 221 |
| 222 class GetUploadDetailsRequest : public PaymentsRequest { |
| 223 public: |
| 224 GetUploadDetailsRequest(const std::vector<AutofillProfile>& addresses, |
| 225 const std::string& app_locale) |
| 226 : addresses_(addresses), app_locale_(app_locale) {} |
| 227 ~GetUploadDetailsRequest() override {} |
| 228 |
| 229 std::string GetRequestUrlPath() override { |
| 230 return kGetUploadDetailsRequestPath; |
| 231 } |
| 232 |
| 233 std::string GetRequestContentType() override { return "application/json"; } |
| 234 |
| 235 std::string GetRequestContent() override { |
| 236 base::DictionaryValue request_dict; |
| 237 std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue()); |
| 238 context->SetString("language_code", app_locale_); |
| 239 request_dict.Set("context", std::move(context)); |
| 240 |
| 241 std::unique_ptr<base::ListValue> addresses(new base::ListValue()); |
| 242 for (const AutofillProfile& profile : addresses_) { |
| 243 // These addresses are used by Payments to (1) accurately determine the |
| 244 // user's country in order to show the correct legal documents and (2) to |
| 245 // verify that the addresses are valid for their purposes so that we don't |
| 246 // offer save in a case where it would definitely fail (e.g. P.O. boxes). |
| 247 // The final parameter directs BuildAddressDictionary to omit names and |
| 248 // phone numbers, which aren't useful for these purposes. |
| 249 addresses->Append(BuildAddressDictionary(profile, app_locale_, false)); |
| 250 } |
| 251 request_dict.Set("address", std::move(addresses)); |
| 252 |
| 253 std::string request_content; |
| 254 base::JSONWriter::Write(request_dict, &request_content); |
| 255 VLOG(3) << "getdetailsforsavecard request body: " << request_content; |
| 256 return request_content; |
| 257 } |
| 258 |
| 259 void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override { |
| 260 response->GetString("context_token", &context_token_); |
| 261 base::DictionaryValue* unowned_legal_message; |
| 262 if (response->GetDictionary("legal_message", &unowned_legal_message)) |
| 263 legal_message_ = unowned_legal_message->CreateDeepCopy(); |
| 264 } |
| 265 |
| 266 bool IsResponseComplete() override { |
| 267 return !context_token_.empty() && legal_message_; |
| 268 } |
| 269 |
| 270 void RespondToDelegate(PaymentsClientDelegate* delegate, |
| 271 AutofillClient::PaymentsRpcResult result) override { |
| 272 delegate->OnDidGetUploadDetails(result, context_token_, |
| 273 std::move(legal_message_)); |
| 274 } |
| 275 |
| 276 private: |
| 277 std::vector<AutofillProfile> addresses_; |
| 278 std::string app_locale_; |
| 279 base::string16 context_token_; |
| 280 std::unique_ptr<base::DictionaryValue> legal_message_; |
| 281 }; |
| 282 |
| 283 class UploadCardRequest : public PaymentsRequest { |
| 284 public: |
| 285 UploadCardRequest(const PaymentsClient::UploadRequestDetails& request_details) |
| 286 : request_details_(request_details) {} |
| 287 ~UploadCardRequest() override {} |
| 288 |
| 289 std::string GetRequestUrlPath() override { return kUploadCardRequestPath; } |
| 290 |
| 291 std::string GetRequestContentType() override { |
| 292 return "application/x-www-form-urlencoded"; |
| 293 } |
| 294 |
| 295 std::string GetRequestContent() override { |
| 296 base::DictionaryValue request_dict; |
| 297 request_dict.SetString("encrypted_pan", "__param:s7e_1_pan"); |
| 298 request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc"); |
| 299 request_dict.Set("risk_data_encoded", |
| 300 BuildRiskDictionary(request_details_.risk_data)); |
| 301 |
| 302 const std::string& app_locale = request_details_.app_locale; |
| 303 std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue()); |
| 304 context->SetString("language_code", app_locale); |
| 305 request_dict.Set("context", std::move(context)); |
| 306 |
| 307 SetStringIfNotEmpty(request_details_.card, CREDIT_CARD_NAME_FULL, |
| 308 app_locale, "cardholder_name", &request_dict); |
| 309 |
| 310 std::unique_ptr<base::ListValue> addresses(new base::ListValue()); |
| 311 for (const AutofillProfile& profile : request_details_.profiles) { |
| 312 addresses->Append(BuildAddressDictionary(profile, app_locale, true)); |
| 313 } |
| 314 request_dict.Set("address", std::move(addresses)); |
| 315 |
| 316 request_dict.SetString("context_token", request_details_.context_token); |
| 317 |
| 318 int value = 0; |
| 319 const base::string16 exp_month = request_details_.card.GetInfo( |
| 320 AutofillType(CREDIT_CARD_EXP_MONTH), app_locale); |
| 321 const base::string16 exp_year = request_details_.card.GetInfo( |
| 322 AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale); |
| 323 if (base::StringToInt(exp_month, &value)) |
| 324 request_dict.SetInteger("expiration_month", value); |
| 325 if (base::StringToInt(exp_year, &value)) |
| 326 request_dict.SetInteger("expiration_year", value); |
| 327 |
| 328 const base::string16 pan = request_details_.card.GetInfo( |
| 329 AutofillType(CREDIT_CARD_NUMBER), app_locale); |
| 330 std::string json_request; |
| 331 base::JSONWriter::Write(request_dict, &json_request); |
| 332 std::string request_content = base::StringPrintf( |
| 333 kUploadCardRequestFormat, |
| 334 net::EscapeUrlEncodedData(json_request, true).c_str(), |
| 335 net::EscapeUrlEncodedData(base::UTF16ToASCII(pan), true).c_str(), |
| 336 net::EscapeUrlEncodedData(base::UTF16ToASCII(request_details_.cvc), |
| 337 true) |
| 338 .c_str()); |
| 339 VLOG(3) << "savecard request body: " << request_content; |
| 340 return request_content; |
| 341 } |
| 342 |
| 343 void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override { |
| 344 } |
| 345 |
| 346 bool IsResponseComplete() override { return true; } |
| 347 |
| 348 void RespondToDelegate(PaymentsClientDelegate* delegate, |
| 349 AutofillClient::PaymentsRpcResult result) override { |
| 350 delegate->OnDidUploadCard(result); |
| 351 } |
| 352 |
| 353 private: |
| 354 PaymentsClient::UploadRequestDetails request_details_; |
| 355 }; |
| 356 |
| 357 } // namespace |
| 358 |
| 359 const char PaymentsClient::kRecipientName[] = "recipient_name"; |
| 360 const char PaymentsClient::kPhoneNumber[] = "phone_number"; |
| 361 |
| 362 PaymentsClient::UnmaskRequestDetails::UnmaskRequestDetails() {} |
| 363 PaymentsClient::UnmaskRequestDetails::~UnmaskRequestDetails() {} |
| 364 |
| 365 PaymentsClient::UploadRequestDetails::UploadRequestDetails() {} |
| 366 PaymentsClient::UploadRequestDetails::UploadRequestDetails( |
| 367 const UploadRequestDetails& other) = default; |
| 368 PaymentsClient::UploadRequestDetails::~UploadRequestDetails() {} |
| 369 |
| 370 PaymentsClient::PaymentsClient(net::URLRequestContextGetter* context_getter, |
| 371 PaymentsClientDelegate* delegate) |
| 372 : OAuth2TokenService::Consumer(kTokenServiceConsumerId), |
| 373 context_getter_(context_getter), |
| 374 delegate_(delegate), |
| 375 has_retried_authorization_(false), |
| 376 weak_ptr_factory_(this) { |
| 377 DCHECK(delegate); |
| 378 } |
| 379 |
| 380 PaymentsClient::~PaymentsClient() {} |
| 381 |
| 382 void PaymentsClient::Prepare() { |
| 383 if (access_token_.empty()) |
| 384 StartTokenFetch(false); |
| 385 } |
| 386 |
| 387 void PaymentsClient::UnmaskCard( |
| 388 const PaymentsClient::UnmaskRequestDetails& request_details) { |
| 389 IssueRequest(base::MakeUnique<UnmaskCardRequest>(request_details), true); |
| 390 } |
| 391 |
| 392 void PaymentsClient::GetUploadDetails( |
| 393 const std::vector<AutofillProfile>& addresses, |
| 394 const std::string& app_locale) { |
| 395 IssueRequest(base::MakeUnique<GetUploadDetailsRequest>(addresses, app_locale), |
| 396 false); |
| 397 } |
| 398 |
| 399 void PaymentsClient::UploadCard( |
| 400 const PaymentsClient::UploadRequestDetails& request_details) { |
| 401 IssueRequest(base::MakeUnique<UploadCardRequest>(request_details), true); |
| 402 } |
| 403 |
| 404 void PaymentsClient::IssueRequest(std::unique_ptr<PaymentsRequest> request, |
| 405 bool authenticate) { |
| 406 request_ = std::move(request); |
| 407 has_retried_authorization_ = false; |
| 408 InitializeUrlFetcher(); |
| 409 |
| 410 if (!authenticate) |
| 411 url_fetcher_->Start(); |
| 412 else if (access_token_.empty()) |
| 413 StartTokenFetch(false); |
| 414 else |
| 415 SetOAuth2TokenAndStartRequest(); |
| 416 } |
| 417 |
| 418 void PaymentsClient::InitializeUrlFetcher() { |
| 419 net::NetworkTrafficAnnotationTag traffic_annotation = |
| 420 net::DefineNetworkTrafficAnnotation("payments_sync_cards", R"( |
| 421 semantics { |
| 422 sender: "Payments" |
| 423 description: |
| 424 "This service communicates with Google Payments servers to upload " |
| 425 "(save) or receive the user's credit card info." |
| 426 trigger: |
| 427 "Requests are triggered by a user action, such as selecting a " |
| 428 "masked server card from Chromium's credit card autofill dropdown, " |
| 429 "submitting a form which has credit card information, or accepting " |
| 430 "the prompt to save a credit card to Payments servers." |
| 431 data: |
| 432 "In case of save, a protocol buffer containing relevant address " |
| 433 "and credit card information which should be saved in Google " |
| 434 "Payments servers, along with user credentials. In case of load, a " |
| 435 "protocol buffer containing the id of the credit card to unmask, " |
| 436 "an encrypted cvc value, an optional updated card expiration date, " |
| 437 "and user credentials." |
| 438 destination: GOOGLE_OWNED_SERVICE |
| 439 } |
| 440 policy { |
| 441 cookies_allowed: false |
| 442 setting: |
| 443 "Users can enable or disable this feature in Chromium settings by " |
| 444 "toggling 'Credit cards and addresses using Google Payments', " |
| 445 "under 'Advanced sync settings...'. This feature is enabled by " |
| 446 "default." |
| 447 chrome_policy { |
| 448 AutoFillEnabled { |
| 449 policy_options {mode: MANDATORY} |
| 450 AutoFillEnabled: false |
| 451 } |
| 452 } |
| 453 })"); |
| 454 url_fetcher_ = |
| 455 net::URLFetcher::Create(0, GetRequestUrl(request_->GetRequestUrlPath()), |
| 456 net::URLFetcher::POST, this, traffic_annotation); |
| 457 |
| 458 data_use_measurement::DataUseUserData::AttachToFetcher( |
| 459 url_fetcher_.get(), data_use_measurement::DataUseUserData::AUTOFILL); |
| 460 url_fetcher_->SetRequestContext(context_getter_.get()); |
| 461 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | |
| 462 net::LOAD_DO_NOT_SEND_COOKIES | |
| 463 net::LOAD_DISABLE_CACHE); |
| 464 |
| 465 url_fetcher_->SetUploadData(request_->GetRequestContentType(), |
| 466 request_->GetRequestContent()); |
| 467 } |
| 468 |
| 469 void PaymentsClient::CancelRequest() { |
| 470 request_.reset(); |
| 471 url_fetcher_.reset(); |
| 472 access_token_request_.reset(); |
| 473 access_token_.clear(); |
| 474 has_retried_authorization_ = false; |
| 475 } |
| 476 |
| 477 void PaymentsClient::OnURLFetchComplete(const net::URLFetcher* source) { |
| 478 DCHECK_EQ(source, url_fetcher_.get()); |
| 479 |
| 480 // |url_fetcher_|, which is aliased to |source|, might continue to be used in |
| 481 // this method, but should be freed once control leaves the method. |
| 482 std::unique_ptr<net::URLFetcher> scoped_url_fetcher(std::move(url_fetcher_)); |
| 483 std::unique_ptr<base::DictionaryValue> response_dict; |
| 484 int response_code = source->GetResponseCode(); |
| 485 std::string data; |
| 486 source->GetResponseAsString(&data); |
| 487 VLOG(2) << "Got data: " << data; |
| 488 |
| 489 AutofillClient::PaymentsRpcResult result = AutofillClient::SUCCESS; |
| 490 |
| 491 switch (response_code) { |
| 492 // Valid response. |
| 493 case net::HTTP_OK: { |
| 494 std::string error_code; |
| 495 std::unique_ptr<base::Value> message_value = base::JSONReader::Read(data); |
| 496 if (message_value.get() && |
| 497 message_value->IsType(base::Value::Type::DICTIONARY)) { |
| 498 response_dict.reset( |
| 499 static_cast<base::DictionaryValue*>(message_value.release())); |
| 500 response_dict->GetString("error.code", &error_code); |
| 501 request_->ParseResponse(std::move(response_dict)); |
| 502 } |
| 503 |
| 504 if (base::LowerCaseEqualsASCII(error_code, "internal")) |
| 505 result = AutofillClient::TRY_AGAIN_FAILURE; |
| 506 else if (!error_code.empty() || !request_->IsResponseComplete()) |
| 507 result = AutofillClient::PERMANENT_FAILURE; |
| 508 |
| 509 break; |
| 510 } |
| 511 |
| 512 case net::HTTP_UNAUTHORIZED: { |
| 513 if (has_retried_authorization_) { |
| 514 result = AutofillClient::PERMANENT_FAILURE; |
| 515 break; |
| 516 } |
| 517 has_retried_authorization_ = true; |
| 518 |
| 519 InitializeUrlFetcher(); |
| 520 StartTokenFetch(true); |
| 521 return; |
| 522 } |
| 523 |
| 524 // TODO(estade): is this actually how network connectivity issues are |
| 525 // reported? |
| 526 case net::HTTP_REQUEST_TIMEOUT: { |
| 527 result = AutofillClient::NETWORK_ERROR; |
| 528 break; |
| 529 } |
| 530 |
| 531 // Handle anything else as a generic (permanent) failure. |
| 532 default: { |
| 533 result = AutofillClient::PERMANENT_FAILURE; |
| 534 break; |
| 535 } |
| 536 } |
| 537 |
| 538 if (result != AutofillClient::SUCCESS) { |
| 539 VLOG(1) << "Payments returned error: " << response_code |
| 540 << " with data: " << data; |
| 541 } |
| 542 |
| 543 request_->RespondToDelegate(delegate_, result); |
| 544 } |
| 545 |
| 546 void PaymentsClient::OnGetTokenSuccess( |
| 547 const OAuth2TokenService::Request* request, |
| 548 const std::string& access_token, |
| 549 const base::Time& expiration_time) { |
| 550 DCHECK_EQ(request, access_token_request_.get()); |
| 551 access_token_ = access_token; |
| 552 if (url_fetcher_) |
| 553 SetOAuth2TokenAndStartRequest(); |
| 554 |
| 555 access_token_request_.reset(); |
| 556 } |
| 557 |
| 558 void PaymentsClient::OnGetTokenFailure( |
| 559 const OAuth2TokenService::Request* request, |
| 560 const GoogleServiceAuthError& error) { |
| 561 DCHECK_EQ(request, access_token_request_.get()); |
| 562 VLOG(1) << "Unhandled OAuth2 error: " << error.ToString(); |
| 563 if (url_fetcher_) { |
| 564 url_fetcher_.reset(); |
| 565 request_->RespondToDelegate(delegate_, AutofillClient::PERMANENT_FAILURE); |
| 566 } |
| 567 access_token_request_.reset(); |
| 568 } |
| 569 |
| 570 void PaymentsClient::StartTokenFetch(bool invalidate_old) { |
| 571 // We're still waiting for the last request to come back. |
| 572 if (!invalidate_old && access_token_request_) |
| 573 return; |
| 574 |
| 575 OAuth2TokenService::ScopeSet payments_scopes; |
| 576 payments_scopes.insert(kPaymentsOAuth2Scope); |
| 577 IdentityProvider* identity = delegate_->GetIdentityProvider(); |
| 578 if (invalidate_old) { |
| 579 DCHECK(!access_token_.empty()); |
| 580 identity->GetTokenService()->InvalidateAccessToken( |
| 581 identity->GetActiveAccountId(), payments_scopes, access_token_); |
| 582 } |
| 583 access_token_.clear(); |
| 584 access_token_request_ = identity->GetTokenService()->StartRequest( |
| 585 identity->GetActiveAccountId(), payments_scopes, this); |
| 586 } |
| 587 |
| 588 void PaymentsClient::SetOAuth2TokenAndStartRequest() { |
| 589 url_fetcher_->AddExtraRequestHeader(net::HttpRequestHeaders::kAuthorization + |
| 590 std::string(": Bearer ") + access_token_); |
| 591 |
| 592 url_fetcher_->Start(); |
| 593 } |
| 594 |
| 595 } // namespace payments |
| 596 } // namespace autofill |
OLD | NEW |