910e62b5创建于 1月15日历史提交
// 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_