blob: a00adc4eeda536613ab500b564576c85d48df9bf [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.
#ifndef SERVICES_NETWORK_ACCEPT_CH_FRAME_INTERCEPTOR_H_
#define SERVICES_NETWORK_ACCEPT_CH_FRAME_INTERCEPTOR_H_
#include <memory>
#include "base/component_export.h"
#include "base/types/pass_key.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/base/completion_once_callback.h"
#include "net/base/net_errors.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/accept_ch_frame_observer.mojom.h"
namespace net {
class HttpRequestHeaders;
} // namespace net
namespace network {
// Handles the logic associated with processing the HTTP/2 or HTTP/3
// `ACCEPT_CH` frame received during connection establishment.
//
// This class parses the client hints advertised in the frame, compares them
// against hints already included in the initial request headers, and interacts
// with a browser-provided `AcceptCHFrameObserver` to potentially restart the
// request if additional client hints should be included.
class COMPONENT_EXPORT(NETWORK_SERVICE) AcceptCHFrameInterceptor {
public:
// Conditionally creates an instance of AcceptCHFrameInterceptor.
// Returns nullptr if the `accept_ch_frame_observer` is invalid or if the
// kAcceptCHFrame feature flag is disabled. Otherwise, returns a unique_ptr
// to a new instance.
// `enabled_client_hints` represents the client hints enabled when the
// resource request was created.
static std::unique_ptr<AcceptCHFrameInterceptor> MaybeCreate(
mojo::PendingRemote<mojom::AcceptCHFrameObserver>
accept_ch_frame_observer,
std::optional<ResourceRequest::TrustedParams::EnabledClientHints>
enabled_client_hints);
static std::unique_ptr<AcceptCHFrameInterceptor> CreateForTesting(
mojo::PendingRemote<mojom::AcceptCHFrameObserver>
accept_ch_frame_observer,
std::optional<ResourceRequest::TrustedParams::EnabledClientHints>
enabled_client_hints);
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// LINT.IfChange(NeedsObserverCheckReason)
enum class NeedsObserverCheckReason {
kNotNeeded = 0, // The case where it returns false.
kNoEnabledClientHints = 1,
kMainFrameOriginMismatch = 2,
kSubframeFeatureDisabled = 3,
kHintNotEnabled = 4,
kMaxValue = kHintNotEnabled,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:NeedsObserverCheckReason)
AcceptCHFrameInterceptor(const AcceptCHFrameInterceptor&) = delete;
AcceptCHFrameInterceptor& operator=(const AcceptCHFrameInterceptor&) = delete;
~AcceptCHFrameInterceptor();
// Called when connection establishment details are available, including any
// information potentially derived from an HTTP/2 or HTTP/3 `ACCEPT_CH` frame.
// It takes the request's `url`, a string representation (`accept_ch_frame`)
// of the hints advertised in such a frame, and the initial outgoing request
// `headers`. It compares these advertised hints against the `headers`. If any
// hints needed for the request (based on the frame) were not already
// included, this method notifies the `accept_ch_frame_observer_`.
//
// Returns `net::OK` if no observer notification is needed. If `net::OK` is
// returned, the request can proceed immediately, `callback` will not be
// called.
// Returns `net::ERR_IO_PENDING` if the observer is notified. If
// `net::ERR_IO_PENDING` is returned, the `callback` will be invoked
// asynchronously by this class once the observer responds via Mojo
// (the response usually indicates `net::OK` to proceed or an error).
net::Error OnConnected(const GURL& url,
const std::string& accept_ch_frame,
const net::HttpRequestHeaders& headers,
net::CompletionOnceCallback callback);
NeedsObserverCheckReason NeedsObserverCheckForTesting(
const url::Origin& origin,
const std::vector<mojom::WebClientHintsType>& hints);
private:
// Constructor is private to enforce creation via MaybeCreate or
// CreateForTesting.
AcceptCHFrameInterceptor(
mojo::PendingRemote<mojom::AcceptCHFrameObserver>
accept_ch_frame_observer,
std::optional<ResourceRequest::TrustedParams::EnabledClientHints>
enabled_client_hints,
base::PassKey<AcceptCHFrameInterceptor>);
// Returns true if `hints` need to be checked by the
// `accept_ch_frame_observer_`.
// If hints requested by the ACCEPT_CH frame is not in the resource request,
// the IPC is sent to the browser process via `accept_ch_frame_observer_` to
// verify if it is enabled.
// `hints` represents the difference between ACCEPT_CH frame and the resource
// request. This function verifies if `hints` are enabled at the request
// creation time (which is stored in `enabled_client_hints_`) to avoid sending
// the IPCs if possible. The enabled hints may change after the request
// creation, and the IPC is still needed for them.
NeedsObserverCheckReason NeedsObserverCheck(
const url::Origin& origin,
const std::vector<mojom::WebClientHintsType>& hints);
mojo::Remote<mojom::AcceptCHFrameObserver> accept_ch_frame_observer_;
// `enabled_client_hints_` is the client hints enabled when the
// resource request was created. If ACCEPT_CH frame has client hints
// which does not show up in a request header during `OnConnected()`,
// `accept_ch_observer_` should be called to ensure the hints are enabled.
// `enabled_client_hints_` is used beforehand to avoid an unnecessary observer
// call.
const std::optional<ResourceRequest::TrustedParams::EnabledClientHints>
enabled_client_hints_;
};
} // namespace network
#endif // SERVICES_NETWORK_ACCEPT_CH_FRAME_INTERCEPTOR_H_