blob: 2d72a7cc8679b239f18ad35040567f6e9aedfe5f [file] [log] [blame]
// 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));
}