| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/devtools/devtools_http_service_handler.h" |
| |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "components/signin/public/identity_manager/access_token_info.h" |
| #include "components/signin/public/identity_manager/identity_manager.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "net/base/net_errors.h" |
| #include "net/base/url_util.h" |
| #include "net/http/http_status_code.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/cpp/simple_url_loader.h" |
| #include "services/network/public/mojom/url_response_head.mojom.h" |
| |
| DevToolsHttpServiceHandler::Result::Result() = default; |
| DevToolsHttpServiceHandler::Result::~Result() = default; |
| DevToolsHttpServiceHandler::Result::Result(Result&&) = default; |
| DevToolsHttpServiceHandler::Result& |
| DevToolsHttpServiceHandler::Result::operator=(Result&&) = default; |
| |
| DevToolsHttpServiceHandler::~DevToolsHttpServiceHandler() = default; |
| DevToolsHttpServiceHandler::DevToolsHttpServiceHandler() = default; |
| |
| void DevToolsHttpServiceHandler::Request( |
| Profile* profile, |
| const DevToolsDispatchHttpRequestParams& params, |
| Callback callback) { |
| CanMakeRequest(profile, |
| base::BindOnce(&DevToolsHttpServiceHandler::OnValidationDone, |
| weak_factory_.GetWeakPtr(), std::move(callback), |
| profile, params)); |
| } |
| |
| void DevToolsHttpServiceHandler::OnValidationDone( |
| Callback callback, |
| Profile* profile, |
| const DevToolsDispatchHttpRequestParams& params, |
| bool validation_success) { |
| if (!validation_success) { |
| auto result = std::make_unique<Result>(); |
| result->error = Result::Error::kValidationFailed; |
| std::move(callback).Run(std::move(result)); |
| return; |
| } |
| |
| auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); |
| |
| auto fetcher_id = base::UnguessableToken::Create(); |
| auto access_token_fetcher = |
| identity_manager->CreateAccessTokenFetcherForAccount( |
| identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin), |
| "DevTools_dispatchHttpRequest", OAuthScopes(), |
| base::BindOnce(&DevToolsHttpServiceHandler::OnTokenFetched, |
| weak_factory_.GetWeakPtr(), std::move(callback), |
| profile, params, fetcher_id), |
| signin::AccessTokenFetcher::Mode::kImmediate); |
| access_token_fetchers_.insert({ |
| fetcher_id, |
| std::move(access_token_fetcher), |
| }); |
| } |
| |
| void DevToolsHttpServiceHandler::OnTokenFetched( |
| Callback callback, |
| Profile* profile, |
| const DevToolsDispatchHttpRequestParams& params, |
| base::UnguessableToken fetcher_id, |
| GoogleServiceAuthError error, |
| signin::AccessTokenInfo access_token_info) { |
| access_token_fetchers_.erase(fetcher_id); |
| if (error.state() != GoogleServiceAuthError::NONE) { |
| auto result = std::make_unique<Result>(); |
| result->error = Result::Error::kTokenFetchFailed; |
| result->error_detail = error.ToString(); |
| std::move(callback).Run(std::move(result)); |
| return; |
| } |
| |
| auto resource_request = std::make_unique<network::ResourceRequest>(); |
| GURL url = BaseURL().Resolve(params.path); |
| for (const auto& pair : params.query_params) { |
| const std::string& key = pair.first; |
| for (const std::string& value : pair.second) { |
| url = net::AppendQueryParameter(url, key, value); |
| } |
| } |
| resource_request->url = url; |
| resource_request->method = params.method; |
| resource_request->headers.SetHeader(net::HttpRequestHeaders::kAuthorization, |
| "Bearer " + access_token_info.token); |
| |
| auto simple_url_loader = network::SimpleURLLoader::Create( |
| std::move(resource_request), NetworkTrafficAnnotationTag()); |
| simple_url_loader->SetAllowHttpErrorResults(true); |
| |
| if (params.body.has_value()) { |
| simple_url_loader->AttachStringForUpload(params.body.value(), |
| "application/json"); |
| } |
| |
| network::SimpleURLLoader* loader_ptr = simple_url_loader.get(); |
| loader_ptr->DownloadToString( |
| profile->GetDefaultStoragePartition() |
| ->GetURLLoaderFactoryForBrowserProcess() |
| .get(), |
| base::BindOnce(&DevToolsHttpServiceHandler::OnRequestComplete, |
| weak_factory_.GetWeakPtr(), std::move(callback), |
| std::move(simple_url_loader)), |
| network::SimpleURLLoader::kMaxBoundedStringDownloadSize); |
| } |
| |
| void DevToolsHttpServiceHandler::OnRequestComplete( |
| Callback callback, |
| std::unique_ptr<network::SimpleURLLoader> simple_url_loader, |
| std::optional<std::string> response_body) { |
| auto result = std::make_unique<Result>(); |
| result->net_error = simple_url_loader->NetError(); |
| result->response_body = std::move(response_body); |
| if (simple_url_loader->ResponseInfo() && |
| simple_url_loader->ResponseInfo()->headers) { |
| result->http_status = |
| simple_url_loader->ResponseInfo()->headers->response_code(); |
| } |
| |
| if (result->net_error != net::OK) { |
| result->error = Result::Error::kNetworkError; |
| } else if (result->http_status < net::HTTP_OK || |
| result->http_status >= net::HTTP_MULTIPLE_CHOICES) { |
| result->error = Result::Error::kHttpError; |
| } |
| |
| std::move(callback).Run(std::move(result)); |
| } |