| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/quick_pair/repository/oauth_http_fetcher.h" |
| |
| #include "ash/quick_pair/common/fast_pair/fast_pair_http_result.h" |
| #include "ash/quick_pair/common/quick_pair_browser_delegate.h" |
| #include "components/cross_device/logging/logging.h" |
| #include "components/signin/public/base/consent_level.h" |
| #include "components/signin/public/identity_manager/access_token_info.h" |
| #include "components/signin/public/identity_manager/identity_manager.h" |
| #include "components/signin/public/identity_manager/primary_account_access_token_fetcher.h" |
| #include "google_apis/gaia/gaia_constants.h" |
| #include "net/base/net_errors.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "services/network/public/cpp/simple_url_loader.h" |
| #include "services/network/public/mojom/url_response_head.mojom.h" |
| |
| namespace ash { |
| namespace quick_pair { |
| |
| OAuthHttpFetcher::OAuthHttpFetcher( |
| const net::PartialNetworkTrafficAnnotationTag& traffic_annotation, |
| signin::OAuthConsumerId oauth_consumer_id) |
| : traffic_annotation_(traffic_annotation), |
| oauth_consumer_id_(oauth_consumer_id) {} |
| |
| OAuthHttpFetcher::~OAuthHttpFetcher() = default; |
| |
| void OAuthHttpFetcher::ExecuteGetRequest(const GURL& url, |
| FetchCompleteCallback callback) { |
| request_type_ = RequestType::GET; |
| StartRequest(url, std::move(callback)); |
| } |
| |
| void OAuthHttpFetcher::ExecutePostRequest(const GURL& url, |
| const std::string& body, |
| FetchCompleteCallback callback) { |
| request_type_ = RequestType::POST; |
| body_ = body; |
| StartRequest(url, std::move(callback)); |
| } |
| |
| void OAuthHttpFetcher::ExecuteDeleteRequest(const GURL& url, |
| FetchCompleteCallback callback) { |
| request_type_ = RequestType::DELETE; |
| StartRequest(url, std::move(callback)); |
| } |
| |
| void OAuthHttpFetcher::StartRequest(const GURL& url, |
| FetchCompleteCallback callback) { |
| CD_LOG(VERBOSE, Feature::FP) << __func__ << ": executing request to: " << url; |
| |
| CHECK(!has_call_started_) |
| << __func__ |
| << ": Attempted to make an API call, but there is already a " |
| "request in progress."; |
| |
| signin::IdentityManager* const identity_manager = |
| QuickPairBrowserDelegate::Get()->GetIdentityManager(); |
| CHECK(identity_manager) << __func__ << ": IdentityManager is not available."; |
| |
| has_call_started_ = true; |
| url_ = url; |
| callback_ = std::move(callback); |
| access_token_fetcher_ = |
| std::make_unique<signin::PrimaryAccountAccessTokenFetcher>( |
| oauth_consumer_id_, identity_manager, |
| base::BindOnce(&OAuthHttpFetcher::OnAccessTokenFetched, |
| weak_ptr_factory_.GetWeakPtr()), |
| signin::PrimaryAccountAccessTokenFetcher::Mode::kImmediate, |
| signin::ConsentLevel::kSignin); |
| } |
| |
| void OAuthHttpFetcher::OnAccessTokenFetched( |
| GoogleServiceAuthError error, |
| signin::AccessTokenInfo access_token_info) { |
| access_token_fetcher_.reset(); |
| if (error.state() != GoogleServiceAuthError::NONE) { |
| CD_LOG(WARNING, Feature::FP) |
| << __func__ << ": Failed to retrieve access token. " |
| << error.ToString(); |
| std::move(callback_).Run(std::nullopt, nullptr); |
| return; |
| } |
| |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory = |
| QuickPairBrowserDelegate::Get()->GetURLLoaderFactory(); |
| if (!url_loader_factory) { |
| CD_LOG(WARNING, Feature::FP) |
| << __func__ << ": URLLoaderFactory is not available."; |
| std::move(callback_).Run(std::nullopt, nullptr); |
| return; |
| } |
| |
| CD_LOG(VERBOSE, Feature::FP) << "Access token fetched successfully."; |
| |
| OAuth2ApiCallFlow::Start(std::move(url_loader_factory), |
| access_token_info.token); |
| } |
| |
| GURL OAuthHttpFetcher::CreateApiCallUrl() { |
| return url_; |
| } |
| |
| std::string OAuthHttpFetcher::CreateApiCallBody() { |
| switch (request_type_) { |
| case RequestType::GET: |
| case RequestType::DELETE: |
| return std::string(); |
| |
| case RequestType::POST: |
| return body_; |
| } |
| } |
| |
| std::string OAuthHttpFetcher::CreateApiCallBodyContentType() { |
| switch (request_type_) { |
| case RequestType::GET: |
| case RequestType::DELETE: |
| return std::string(); |
| |
| case RequestType::POST: |
| return "application/x-protobuf"; |
| } |
| } |
| |
| std::string OAuthHttpFetcher::GetRequestTypeForBody(std::string_view body) { |
| switch (request_type_) { |
| case RequestType::GET: |
| return "GET"; |
| |
| case RequestType::POST: |
| return "POST"; |
| |
| case RequestType::DELETE: |
| return "DELETE"; |
| } |
| } |
| |
| void OAuthHttpFetcher::ProcessApiCallSuccess( |
| const network::mojom::URLResponseHead* head, |
| std::optional<std::string> body) { |
| CD_LOG(INFO, Feature::FP) << __func__; |
| |
| std::move(callback_).Run( |
| std::move(body), |
| std::make_unique<FastPairHttpResult>(/*net_error=*/net::OK, |
| /*head=*/head)); |
| } |
| |
| void OAuthHttpFetcher::ProcessApiCallFailure( |
| int net_error, |
| const network::mojom::URLResponseHead* head, |
| std::optional<std::string> body) { |
| CD_LOG(WARNING, Feature::FP) << __func__ << ": net_err=" << net_error; |
| |
| std::move(callback_).Run(std::nullopt, std::make_unique<FastPairHttpResult>( |
| /*net_error=*/net_error, |
| /*head=*/head)); |
| } |
| |
| net::PartialNetworkTrafficAnnotationTag |
| OAuthHttpFetcher::GetNetworkTrafficAnnotationTag() { |
| return traffic_annotation_; |
| } |
| |
| } // namespace quick_pair |
| } // namespace ash |