Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Unified Diff: tools/clang/traffic_annotation_extractor/tests/inputs/payments_client.cc

Issue 2448133006: Tool added to extract network traffic annotations. (Closed)
Patch Set: nits Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tools/clang/traffic_annotation_extractor/tests/inputs/payments_client.cc
diff --git a/tools/clang/traffic_annotation_extractor/tests/inputs/payments_client.cc b/tools/clang/traffic_annotation_extractor/tests/inputs/payments_client.cc
new file mode 100644
index 0000000000000000000000000000000000000000..44e85c2e8d9f5e4ce4a160c3ae32666d3836af3a
--- /dev/null
+++ b/tools/clang/traffic_annotation_extractor/tests/inputs/payments_client.cc
@@ -0,0 +1,596 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
battre 2017/04/07 08:42:27 Same here. I think that we want unittests, not int
Ramin Halavati 2017/04/07 11:33:32 Ditto.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/payments/payments_client.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_data_model.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/payments/payments_request.h"
+#include "components/autofill/core/browser/payments/payments_service_url.h"
+#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "google_apis/gaia/identity_provider.h"
+#include "net/base/escape.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace autofill {
+namespace payments {
+
+namespace {
+
+const char kUnmaskCardRequestPath[] =
+ "payments/apis-secure/creditcardservice/getrealpan?s7e_suffix=chromewallet";
+const char kUnmaskCardRequestFormat[] =
+ "requestContentType=application/json; charset=utf-8&request=%s"
+ "&s7e_13_cvc=%s";
+
+const char kGetUploadDetailsRequestPath[] =
+ "payments/apis/chromepaymentsservice/getdetailsforsavecard";
+
+const char kUploadCardRequestPath[] =
+ "payments/apis-secure/chromepaymentsservice/savecard"
+ "?s7e_suffix=chromewallet";
+const char kUploadCardRequestFormat[] =
+ "requestContentType=application/json; charset=utf-8&request=%s"
+ "&s7e_1_pan=%s&s7e_13_cvc=%s";
+
+const char kTokenServiceConsumerId[] = "wallet_client";
+const char kPaymentsOAuth2Scope[] =
+ "https://www.googleapis.com/auth/wallet.chrome";
+
+GURL GetRequestUrl(const std::string& path) {
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch("sync-url")) {
+ if (IsPaymentsProductionEnabled()) {
+ LOG(ERROR) << "You are using production Payments but you specified a "
+ "--sync-url. You likely want to disable the sync sandbox "
+ "or switch to sandbox Payments. Both are controlled in "
+ "about:flags.";
+ }
+ } else if (!IsPaymentsProductionEnabled()) {
+ LOG(ERROR) << "You are using sandbox Payments but you didn't specify a "
+ "--sync-url. You likely want to enable the sync sandbox "
+ "or switch to production Payments. Both are controlled in "
+ "about:flags.";
+ }
+
+ return GetBaseSecureUrl().Resolve(path);
+}
+
+std::unique_ptr<base::DictionaryValue> BuildRiskDictionary(
+ const std::string& encoded_risk_data) {
+ std::unique_ptr<base::DictionaryValue> risk_data(new base::DictionaryValue());
+#if defined(OS_IOS)
+ // Browser fingerprinting is not available on iOS. Instead, we generate
+ // RiskAdvisoryData.
+ risk_data->SetString("message_type", "RISK_ADVISORY_DATA");
+ risk_data->SetString("encoding_type", "BASE_64_URL");
+#else
+ risk_data->SetString("message_type", "BROWSER_NATIVE_FINGERPRINTING");
+ risk_data->SetString("encoding_type", "BASE_64");
+#endif
+
+ risk_data->SetString("value", encoded_risk_data);
+
+ return risk_data;
+}
+
+void SetStringIfNotEmpty(const AutofillDataModel& profile,
+ const ServerFieldType& type,
+ const std::string& app_locale,
+ const std::string& path,
+ base::DictionaryValue* dictionary) {
+ const base::string16 value = profile.GetInfo(AutofillType(type), app_locale);
+ if (!value.empty())
+ dictionary->SetString(path, value);
+}
+
+void AppendStringIfNotEmpty(const AutofillProfile& profile,
+ const ServerFieldType& type,
+ const std::string& app_locale,
+ base::ListValue* list) {
+ const base::string16 value = profile.GetInfo(AutofillType(type), app_locale);
+ if (!value.empty())
+ list->AppendString(value);
+}
+
+// Returns a dictionary with the structure expected by Payments RPCs, containing
+// each of the fields in |profile|, formatted according to |app_locale|. If
+// |include_non_location_data| is false, the name and phone number in |profile|
+// are not included.
+std::unique_ptr<base::DictionaryValue> BuildAddressDictionary(
+ const AutofillProfile& profile,
+ const std::string& app_locale,
+ bool include_non_location_data) {
+ std::unique_ptr<base::DictionaryValue> postal_address(
+ new base::DictionaryValue());
+
+ if (include_non_location_data) {
+ SetStringIfNotEmpty(profile, NAME_FULL, app_locale,
+ PaymentsClient::kRecipientName, postal_address.get());
+ }
+
+ std::unique_ptr<base::ListValue> address_lines(new base::ListValue());
+ AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE1, app_locale,
+ address_lines.get());
+ AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE2, app_locale,
+ address_lines.get());
+ AppendStringIfNotEmpty(profile, ADDRESS_HOME_LINE3, app_locale,
+ address_lines.get());
+ if (!address_lines->empty())
+ postal_address->Set("address_line", std::move(address_lines));
+
+ SetStringIfNotEmpty(profile, ADDRESS_HOME_CITY, app_locale, "locality_name",
+ postal_address.get());
+ SetStringIfNotEmpty(profile, ADDRESS_HOME_STATE, app_locale,
+ "administrative_area_name", postal_address.get());
+ SetStringIfNotEmpty(profile, ADDRESS_HOME_ZIP, app_locale,
+ "postal_code_number", postal_address.get());
+
+ // Use GetRawInfo to get a country code instead of the country name:
+ const base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY);
+ if (!country_code.empty())
+ postal_address->SetString("country_name_code", country_code);
+
+ std::unique_ptr<base::DictionaryValue> address(new base::DictionaryValue());
+ address->Set("postal_address", std::move(postal_address));
+
+ if (include_non_location_data) {
+ SetStringIfNotEmpty(profile, PHONE_HOME_WHOLE_NUMBER, app_locale,
+ PaymentsClient::kPhoneNumber, address.get());
+ }
+
+ return address;
+}
+
+class UnmaskCardRequest : public PaymentsRequest {
+ public:
+ UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details)
+ : request_details_(request_details) {
+ DCHECK(
+ CreditCard::MASKED_SERVER_CARD == request_details.card.record_type() ||
+ CreditCard::FULL_SERVER_CARD == request_details.card.record_type());
+ }
+ ~UnmaskCardRequest() override {}
+
+ std::string GetRequestUrlPath() override { return kUnmaskCardRequestPath; }
+
+ std::string GetRequestContentType() override {
+ return "application/x-www-form-urlencoded";
+ }
+
+ std::string GetRequestContent() override {
+ base::DictionaryValue request_dict;
+ request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc");
+ request_dict.SetString("credit_card_id", request_details_.card.server_id());
+ request_dict.Set("risk_data_encoded",
+ BuildRiskDictionary(request_details_.risk_data));
+ request_dict.Set("context", base::MakeUnique<base::DictionaryValue>());
+
+ int value = 0;
+ if (base::StringToInt(request_details_.user_response.exp_month, &value))
+ request_dict.SetInteger("expiration_month", value);
+ if (base::StringToInt(request_details_.user_response.exp_year, &value))
+ request_dict.SetInteger("expiration_year", value);
+
+ std::string json_request;
+ base::JSONWriter::Write(request_dict, &json_request);
+ std::string request_content = base::StringPrintf(
+ kUnmaskCardRequestFormat,
+ net::EscapeUrlEncodedData(json_request, true).c_str(),
+ net::EscapeUrlEncodedData(
+ base::UTF16ToASCII(request_details_.user_response.cvc), true)
+ .c_str());
+ VLOG(3) << "getrealpan request body: " << request_content;
+ return request_content;
+ }
+
+ void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override {
+ response->GetString("pan", &real_pan_);
+ }
+
+ bool IsResponseComplete() override { return !real_pan_.empty(); }
+
+ void RespondToDelegate(PaymentsClientDelegate* delegate,
+ AutofillClient::PaymentsRpcResult result) override {
+ delegate->OnDidGetRealPan(result, real_pan_);
+ }
+
+ private:
+ PaymentsClient::UnmaskRequestDetails request_details_;
+ std::string real_pan_;
+};
+
+class GetUploadDetailsRequest : public PaymentsRequest {
+ public:
+ GetUploadDetailsRequest(const std::vector<AutofillProfile>& addresses,
+ const std::string& app_locale)
+ : addresses_(addresses), app_locale_(app_locale) {}
+ ~GetUploadDetailsRequest() override {}
+
+ std::string GetRequestUrlPath() override {
+ return kGetUploadDetailsRequestPath;
+ }
+
+ std::string GetRequestContentType() override { return "application/json"; }
+
+ std::string GetRequestContent() override {
+ base::DictionaryValue request_dict;
+ std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue());
+ context->SetString("language_code", app_locale_);
+ request_dict.Set("context", std::move(context));
+
+ std::unique_ptr<base::ListValue> addresses(new base::ListValue());
+ for (const AutofillProfile& profile : addresses_) {
+ // These addresses are used by Payments to (1) accurately determine the
+ // user's country in order to show the correct legal documents and (2) to
+ // verify that the addresses are valid for their purposes so that we don't
+ // offer save in a case where it would definitely fail (e.g. P.O. boxes).
+ // The final parameter directs BuildAddressDictionary to omit names and
+ // phone numbers, which aren't useful for these purposes.
+ addresses->Append(BuildAddressDictionary(profile, app_locale_, false));
+ }
+ request_dict.Set("address", std::move(addresses));
+
+ std::string request_content;
+ base::JSONWriter::Write(request_dict, &request_content);
+ VLOG(3) << "getdetailsforsavecard request body: " << request_content;
+ return request_content;
+ }
+
+ void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override {
+ response->GetString("context_token", &context_token_);
+ base::DictionaryValue* unowned_legal_message;
+ if (response->GetDictionary("legal_message", &unowned_legal_message))
+ legal_message_ = unowned_legal_message->CreateDeepCopy();
+ }
+
+ bool IsResponseComplete() override {
+ return !context_token_.empty() && legal_message_;
+ }
+
+ void RespondToDelegate(PaymentsClientDelegate* delegate,
+ AutofillClient::PaymentsRpcResult result) override {
+ delegate->OnDidGetUploadDetails(result, context_token_,
+ std::move(legal_message_));
+ }
+
+ private:
+ std::vector<AutofillProfile> addresses_;
+ std::string app_locale_;
+ base::string16 context_token_;
+ std::unique_ptr<base::DictionaryValue> legal_message_;
+};
+
+class UploadCardRequest : public PaymentsRequest {
+ public:
+ UploadCardRequest(const PaymentsClient::UploadRequestDetails& request_details)
+ : request_details_(request_details) {}
+ ~UploadCardRequest() override {}
+
+ std::string GetRequestUrlPath() override { return kUploadCardRequestPath; }
+
+ std::string GetRequestContentType() override {
+ return "application/x-www-form-urlencoded";
+ }
+
+ std::string GetRequestContent() override {
+ base::DictionaryValue request_dict;
+ request_dict.SetString("encrypted_pan", "__param:s7e_1_pan");
+ request_dict.SetString("encrypted_cvc", "__param:s7e_13_cvc");
+ request_dict.Set("risk_data_encoded",
+ BuildRiskDictionary(request_details_.risk_data));
+
+ const std::string& app_locale = request_details_.app_locale;
+ std::unique_ptr<base::DictionaryValue> context(new base::DictionaryValue());
+ context->SetString("language_code", app_locale);
+ request_dict.Set("context", std::move(context));
+
+ SetStringIfNotEmpty(request_details_.card, CREDIT_CARD_NAME_FULL,
+ app_locale, "cardholder_name", &request_dict);
+
+ std::unique_ptr<base::ListValue> addresses(new base::ListValue());
+ for (const AutofillProfile& profile : request_details_.profiles) {
+ addresses->Append(BuildAddressDictionary(profile, app_locale, true));
+ }
+ request_dict.Set("address", std::move(addresses));
+
+ request_dict.SetString("context_token", request_details_.context_token);
+
+ int value = 0;
+ const base::string16 exp_month = request_details_.card.GetInfo(
+ AutofillType(CREDIT_CARD_EXP_MONTH), app_locale);
+ const base::string16 exp_year = request_details_.card.GetInfo(
+ AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale);
+ if (base::StringToInt(exp_month, &value))
+ request_dict.SetInteger("expiration_month", value);
+ if (base::StringToInt(exp_year, &value))
+ request_dict.SetInteger("expiration_year", value);
+
+ const base::string16 pan = request_details_.card.GetInfo(
+ AutofillType(CREDIT_CARD_NUMBER), app_locale);
+ std::string json_request;
+ base::JSONWriter::Write(request_dict, &json_request);
+ std::string request_content = base::StringPrintf(
+ kUploadCardRequestFormat,
+ net::EscapeUrlEncodedData(json_request, true).c_str(),
+ net::EscapeUrlEncodedData(base::UTF16ToASCII(pan), true).c_str(),
+ net::EscapeUrlEncodedData(base::UTF16ToASCII(request_details_.cvc),
+ true)
+ .c_str());
+ VLOG(3) << "savecard request body: " << request_content;
+ return request_content;
+ }
+
+ void ParseResponse(std::unique_ptr<base::DictionaryValue> response) override {
+ }
+
+ bool IsResponseComplete() override { return true; }
+
+ void RespondToDelegate(PaymentsClientDelegate* delegate,
+ AutofillClient::PaymentsRpcResult result) override {
+ delegate->OnDidUploadCard(result);
+ }
+
+ private:
+ PaymentsClient::UploadRequestDetails request_details_;
+};
+
+} // namespace
+
+const char PaymentsClient::kRecipientName[] = "recipient_name";
+const char PaymentsClient::kPhoneNumber[] = "phone_number";
+
+PaymentsClient::UnmaskRequestDetails::UnmaskRequestDetails() {}
+PaymentsClient::UnmaskRequestDetails::~UnmaskRequestDetails() {}
+
+PaymentsClient::UploadRequestDetails::UploadRequestDetails() {}
+PaymentsClient::UploadRequestDetails::UploadRequestDetails(
+ const UploadRequestDetails& other) = default;
+PaymentsClient::UploadRequestDetails::~UploadRequestDetails() {}
+
+PaymentsClient::PaymentsClient(net::URLRequestContextGetter* context_getter,
+ PaymentsClientDelegate* delegate)
+ : OAuth2TokenService::Consumer(kTokenServiceConsumerId),
+ context_getter_(context_getter),
+ delegate_(delegate),
+ has_retried_authorization_(false),
+ weak_ptr_factory_(this) {
+ DCHECK(delegate);
+}
+
+PaymentsClient::~PaymentsClient() {}
+
+void PaymentsClient::Prepare() {
+ if (access_token_.empty())
+ StartTokenFetch(false);
+}
+
+void PaymentsClient::UnmaskCard(
+ const PaymentsClient::UnmaskRequestDetails& request_details) {
+ IssueRequest(base::MakeUnique<UnmaskCardRequest>(request_details), true);
+}
+
+void PaymentsClient::GetUploadDetails(
+ const std::vector<AutofillProfile>& addresses,
+ const std::string& app_locale) {
+ IssueRequest(base::MakeUnique<GetUploadDetailsRequest>(addresses, app_locale),
+ false);
+}
+
+void PaymentsClient::UploadCard(
+ const PaymentsClient::UploadRequestDetails& request_details) {
+ IssueRequest(base::MakeUnique<UploadCardRequest>(request_details), true);
+}
+
+void PaymentsClient::IssueRequest(std::unique_ptr<PaymentsRequest> request,
+ bool authenticate) {
+ request_ = std::move(request);
+ has_retried_authorization_ = false;
+ InitializeUrlFetcher();
+
+ if (!authenticate)
+ url_fetcher_->Start();
+ else if (access_token_.empty())
+ StartTokenFetch(false);
+ else
+ SetOAuth2TokenAndStartRequest();
+}
+
+void PaymentsClient::InitializeUrlFetcher() {
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("payments_sync_cards", R"(
+ semantics {
+ sender: "Payments"
+ description:
+ "This service communicates with Google Payments servers to upload "
+ "(save) or receive the user's credit card info."
+ trigger:
+ "Requests are triggered by a user action, such as selecting a "
+ "masked server card from Chromium's credit card autofill dropdown, "
+ "submitting a form which has credit card information, or accepting "
+ "the prompt to save a credit card to Payments servers."
+ data:
+ "In case of save, a protocol buffer containing relevant address "
+ "and credit card information which should be saved in Google "
+ "Payments servers, along with user credentials. In case of load, a "
+ "protocol buffer containing the id of the credit card to unmask, "
+ "an encrypted cvc value, an optional updated card expiration date, "
+ "and user credentials."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: false
+ setting:
+ "Users can enable or disable this feature in Chromium settings by "
+ "toggling 'Credit cards and addresses using Google Payments', "
+ "under 'Advanced sync settings...'. This feature is enabled by "
+ "default."
+ chrome_policy {
+ AutoFillEnabled {
+ policy_options {mode: MANDATORY}
+ AutoFillEnabled: false
+ }
+ }
+ })");
+ url_fetcher_ =
+ net::URLFetcher::Create(0, GetRequestUrl(request_->GetRequestUrlPath()),
+ net::URLFetcher::POST, this, traffic_annotation);
+
+ data_use_measurement::DataUseUserData::AttachToFetcher(
+ url_fetcher_.get(), data_use_measurement::DataUseUserData::AUTOFILL);
+ url_fetcher_->SetRequestContext(context_getter_.get());
+ url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
+ net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DISABLE_CACHE);
+
+ url_fetcher_->SetUploadData(request_->GetRequestContentType(),
+ request_->GetRequestContent());
+}
+
+void PaymentsClient::CancelRequest() {
+ request_.reset();
+ url_fetcher_.reset();
+ access_token_request_.reset();
+ access_token_.clear();
+ has_retried_authorization_ = false;
+}
+
+void PaymentsClient::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK_EQ(source, url_fetcher_.get());
+
+ // |url_fetcher_|, which is aliased to |source|, might continue to be used in
+ // this method, but should be freed once control leaves the method.
+ std::unique_ptr<net::URLFetcher> scoped_url_fetcher(std::move(url_fetcher_));
+ std::unique_ptr<base::DictionaryValue> response_dict;
+ int response_code = source->GetResponseCode();
+ std::string data;
+ source->GetResponseAsString(&data);
+ VLOG(2) << "Got data: " << data;
+
+ AutofillClient::PaymentsRpcResult result = AutofillClient::SUCCESS;
+
+ switch (response_code) {
+ // Valid response.
+ case net::HTTP_OK: {
+ std::string error_code;
+ std::unique_ptr<base::Value> message_value = base::JSONReader::Read(data);
+ if (message_value.get() &&
+ message_value->IsType(base::Value::Type::DICTIONARY)) {
+ response_dict.reset(
+ static_cast<base::DictionaryValue*>(message_value.release()));
+ response_dict->GetString("error.code", &error_code);
+ request_->ParseResponse(std::move(response_dict));
+ }
+
+ if (base::LowerCaseEqualsASCII(error_code, "internal"))
+ result = AutofillClient::TRY_AGAIN_FAILURE;
+ else if (!error_code.empty() || !request_->IsResponseComplete())
+ result = AutofillClient::PERMANENT_FAILURE;
+
+ break;
+ }
+
+ case net::HTTP_UNAUTHORIZED: {
+ if (has_retried_authorization_) {
+ result = AutofillClient::PERMANENT_FAILURE;
+ break;
+ }
+ has_retried_authorization_ = true;
+
+ InitializeUrlFetcher();
+ StartTokenFetch(true);
+ return;
+ }
+
+ // TODO(estade): is this actually how network connectivity issues are
+ // reported?
+ case net::HTTP_REQUEST_TIMEOUT: {
+ result = AutofillClient::NETWORK_ERROR;
+ break;
+ }
+
+ // Handle anything else as a generic (permanent) failure.
+ default: {
+ result = AutofillClient::PERMANENT_FAILURE;
+ break;
+ }
+ }
+
+ if (result != AutofillClient::SUCCESS) {
+ VLOG(1) << "Payments returned error: " << response_code
+ << " with data: " << data;
+ }
+
+ request_->RespondToDelegate(delegate_, result);
+}
+
+void PaymentsClient::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& access_token,
+ const base::Time& expiration_time) {
+ DCHECK_EQ(request, access_token_request_.get());
+ access_token_ = access_token;
+ if (url_fetcher_)
+ SetOAuth2TokenAndStartRequest();
+
+ access_token_request_.reset();
+}
+
+void PaymentsClient::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ DCHECK_EQ(request, access_token_request_.get());
+ VLOG(1) << "Unhandled OAuth2 error: " << error.ToString();
+ if (url_fetcher_) {
+ url_fetcher_.reset();
+ request_->RespondToDelegate(delegate_, AutofillClient::PERMANENT_FAILURE);
+ }
+ access_token_request_.reset();
+}
+
+void PaymentsClient::StartTokenFetch(bool invalidate_old) {
+ // We're still waiting for the last request to come back.
+ if (!invalidate_old && access_token_request_)
+ return;
+
+ OAuth2TokenService::ScopeSet payments_scopes;
+ payments_scopes.insert(kPaymentsOAuth2Scope);
+ IdentityProvider* identity = delegate_->GetIdentityProvider();
+ if (invalidate_old) {
+ DCHECK(!access_token_.empty());
+ identity->GetTokenService()->InvalidateAccessToken(
+ identity->GetActiveAccountId(), payments_scopes, access_token_);
+ }
+ access_token_.clear();
+ access_token_request_ = identity->GetTokenService()->StartRequest(
+ identity->GetActiveAccountId(), payments_scopes, this);
+}
+
+void PaymentsClient::SetOAuth2TokenAndStartRequest() {
+ url_fetcher_->AddExtraRequestHeader(net::HttpRequestHeaders::kAuthorization +
+ std::string(": Bearer ") + access_token_);
+
+ url_fetcher_->Start();
+}
+
+} // namespace payments
+} // namespace autofill

Powered by Google App Engine
This is Rietveld 408576698