| // 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_ |