blob: 9ab3776f7d1fceae1749e7e6e06a3848ee57ca90 [file]
// 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.
#ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_HTTP_SERVICE_HANDLER_H_
#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_HTTP_SERVICE_HANDLER_H_
#include <compare>
#include <map>
#include "base/containers/flat_set.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/unguessable_token.h"
#include "chrome/browser/devtools/devtools_dispatch_http_request_params.h"
#include "components/signin/public/identity_manager/access_token_fetcher.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
class GURL;
class Profile;
namespace signin {
class AccessTokenFetcher;
struct AccessTokenInfo;
} // namespace signin
class DevToolsHttpServiceHandler {
public:
struct Result {
enum class Error {
kNone, // Success
kServiceNotFound, // The service is not registered.
kAccessDenied, // The path/method is not in the allow-list.
kValidationFailed, // Service-specific validation failed.
kTokenFetchFailed, // Could not get an OAuth token.
kNetworkError, // A network-level error occurred (e.g., DNS failure).
kHttpError, // Server returned a non-2xx HTTP status.
};
Result();
~Result();
Result(Result&&);
Result& operator=(Result&&);
Error error = Error::kNone;
int net_error = 0;
int http_status = -1;
std::optional<std::string> response_body;
std::string error_detail;
};
using Callback = base::OnceCallback<void(std::unique_ptr<Result> result)>;
DevToolsHttpServiceHandler();
virtual ~DevToolsHttpServiceHandler();
using StreamWriter = base::RepeatingCallback<void(std::string_view)>;
virtual void Request(Profile* profile,
const DevToolsDispatchHttpRequestParams& params,
std::optional<StreamWriter> stream_writer,
Callback callback);
protected:
// Performs service-specific pre-request validation. Can be asynchronous.
virtual void CanMakeRequest(Profile* profile,
base::OnceCallback<void(bool success)> callback);
private:
// Returns the base URL for the service's API.
virtual GURL BaseURL() const = 0;
// Returns the OAuth consumer id required for authenticating with the service.
virtual signin::OAuthConsumerId OAuthConsumerId() const = 0;
// Returns the traffic annotation for the request.
virtual net::NetworkTrafficAnnotationTag NetworkTrafficAnnotationTag()
const = 0;
void OnValidationDone(Callback callback,
Profile* profile,
std::optional<StreamWriter> stream_writer,
const DevToolsDispatchHttpRequestParams& params,
bool validation_success);
void OnTokenFetched(Callback callback,
Profile* profile,
std::optional<StreamWriter> stream_writer,
const DevToolsDispatchHttpRequestParams& params,
base::UnguessableToken fetcher_id,
GoogleServiceAuthError error,
signin::AccessTokenInfo access_token_info);
void OnRequestComplete(
Callback callback,
std::unique_ptr<network::SimpleURLLoader> simple_url_loader,
std::optional<std::string> response_body);
class DevToolsStreamConsumer;
// The ActiveStreamRequest owns the DevToolsStreamConsumer (via unique_ptr).
// The DevToolsStreamConsumer needs to destroy the ActiveStreamRequest when
// the stream is complete or cancelled (to free the SimpleURLLoader and
// itself).
//
// ┌──────────────────────────────────────┐
// │ DevToolsHttpServiceHandler │◄─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
// └──────────────────┬───────────────────┘ │
// │ │
// │ owns (std::map) │
// ▼ │
// ┌──────────────────────────────────────┐ │
// │ ActiveStreamRequest │ │
// └───────┬──────────────────────┬───────┘ │
// │ │ │
// │ unique_ptr │ unique_ptr │
// │ │ │
// ▼ ▼ │
// ┌───────────────┐ ┌──────────────────────────────┐ │
// │SimpleURLLoader│ │ DevToolsStreamConsumer │ │
// └───────┬───────┘ └──────────────┬───────────────┘ │
// │ │ │
// │ streams data to │ cleanup_ callback │
// │ (via interface) │ (holds WeakPtr + ID) │
// │ │ │
// ▼ ▼ │
// (Interface) (Calls active_streams_.erase(id)) ─ ─ ┘
//
// This cycle is resolved when the Consumer runs the cleanup callback (in
// OnComplete), which removes the Request from the map, destroying the
// Request, the Consumer, and the callback itself.
struct ActiveStreamRequest {
ActiveStreamRequest();
~ActiveStreamRequest();
ActiveStreamRequest(ActiveStreamRequest&&);
ActiveStreamRequest& operator=(ActiveStreamRequest&&);
std::unique_ptr<network::SimpleURLLoader> loader;
std::unique_ptr<DevToolsStreamConsumer> consumer;
};
std::map<base::UnguessableToken, ActiveStreamRequest> active_streams_;
std::map<base::UnguessableToken, std::unique_ptr<signin::AccessTokenFetcher>>
access_token_fetchers_;
base::WeakPtrFactory<DevToolsHttpServiceHandler> weak_factory_{this};
};
#endif // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_HTTP_SERVICE_HANDLER_H_