910e62b5创建于 1月15日历史提交
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_LOADER_URL_LOADER_FACTORY_UTILS_H_
#define CONTENT_BROWSER_LOADER_URL_LOADER_FACTORY_UTILS_H_

#include <variant>

#include "base/memory/stack_allocated.h"
#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/common/content_export.h"
#include "content/public/browser/content_browser_client.h"
#include "services/network/public/cpp/url_loader_factory_builder.h"

namespace net {
class IsolationInfo;
}

namespace content {

class StoragePartitionImpl;

namespace url_loader_factory {

using Interceptor = base::RepeatingCallback<
    void(int process_id, network::URLLoaderFactoryBuilder& factory_builder)>;

// This method must be called on the UI thread.
CONTENT_EXPORT const Interceptor& GetTestingInterceptor();

// Allows intercepting the URLLoaderFactory creation.
// For every `SetInterceptorForTesting(non-null interceptor)`,
// `SetInterceptorForTesting({})` must be called to ensure restoring the default
// behavior.
// This method must be called either on the UI thread or before threads start.
// This callback is run on the UI thread.
// TODO(crbug.com/40947547): Document when the interception occurs.
CONTENT_EXPORT void SetInterceptorForTesting(const Interceptor& interceptor);

// Only accessed on the IO thread.
// Basically the same as `!!GetTestingInterceptor()`, and introduced to avoid
// possible race conditions between UI/IO threads.
CONTENT_EXPORT bool HasInterceptorOnIOThreadForTesting();
CONTENT_EXPORT void SetHasInterceptorOnIOThreadForTesting(bool has_interceptor);

// A parameter object for `ContentBrowserClient::WillCreateURLLoaderFactory()`.
class CONTENT_EXPORT ContentClientParams final {
  STACK_ALLOCATED();

 public:
  ContentClientParams(BrowserContext* browser_context,
                      RenderFrameHost* frame,
                      int render_process_id,
                      const url::Origin& request_initiator,
                      const net::IsolationInfo& isolation_info,
                      ukm::SourceIdObj ukm_source_id,
                      bool* bypass_redirect_checks = nullptr,
                      std::optional<int64_t> navigation_id = std::nullopt,
                      scoped_refptr<base::SequencedTaskRunner>
                          navigation_response_task_runner = nullptr);

  ContentClientParams(const ContentClientParams&) = delete;
  ContentClientParams& operator=(const ContentClientParams&) = delete;
  ContentClientParams(ContentClientParams&&);
  ContentClientParams& operator=(ContentClientParams&&);
  ~ContentClientParams();

  // Invokes `ContentBrowserClient::WillCreateURLLoaderFactory()` with the
  // parameters given to this method and the constructor.
  void Run(network::URLLoaderFactoryBuilder& factory_builder,
           ContentBrowserClient::URLLoaderFactoryType type,
           mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
               header_client,
           bool* disable_secure_dns,
           network::mojom::URLLoaderFactoryOverridePtr* factory_override);

 private:
  raw_ptr<BrowserContext> browser_context_;
  raw_ptr<RenderFrameHost> frame_;
  int render_process_id_;
  raw_ref<const url::Origin> request_initiator_;
  raw_ref<const net::IsolationInfo> isolation_info_;
  ukm::SourceIdObj ukm_source_id_;
  raw_ptr<bool> bypass_redirect_checks_;
  std::optional<int64_t> navigation_id_;
  scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner_;
};

// When `kAllow` is used, non-null `header_client`, `disable_secure_dns` and
// `factory_override` (respectively) are passed to
// `ContentBrowserClient::WillCreateURLLoaderFactory()` and
// `devtools_instrumentation`.
// Otherwise (`kDisallow`), nullptr are passed.
enum class HeaderClientOption { kAllow, kDisallow };
enum class DisableSecureDnsOption { kAllow, kDisallow };
enum class FactoryOverrideOption { kAllow, kDisallow };

// Specifies the final destination of the URLLoaderFactory in `Create()`.
class CONTENT_EXPORT TerminalParams final {
  STACK_ALLOCATED();

 public:
  // Connects to the URLLoaderFactory from
  // `NetworkContext::CreateURLLoaderFactory(factory_params)`.
  // Any options listed in the arguments can be specified.
  static TerminalParams ForNetworkContext(
      network::mojom::NetworkContext* network_context,
      network::mojom::URLLoaderFactoryParamsPtr factory_params,
      HeaderClientOption header_client_option = HeaderClientOption::kDisallow,
      FactoryOverrideOption factory_override_option =
          FactoryOverrideOption::kDisallow,
      DisableSecureDnsOption disable_secure_dns_option =
          DisableSecureDnsOption::kDisallow);

  // Connects to `storage_partition->GetURLLoaderFactoryForBrowserProcess()`
  // if possible, or otherwise fallback to
  // `storage_partition->GetNetworkContext()->CreateURLLoaderFactory(
  //      storage_partition->CreateURLLoaderFactoryParams())`.
  //
  // This is equivalent to
  // `TerminalParams::ForNetworkContext(
  //      storage_partition->GetNetworkContext(),
  //      storage_partition->CreateURLLoaderFactoryParams(), ...)`
  // except that for `ForBrowserProcess()`
  // -  `GetURLLoaderFactoryForBrowserProcess()` can be used if possible, while
  // - `FactoryOverrideOption`/`DisableSecureDnsOption` must be `kDisallow`.
  static TerminalParams ForBrowserProcess(
      StoragePartitionImpl* storage_partition,
      HeaderClientOption header_client_option = HeaderClientOption::kDisallow);

  // Connects to the given URLLoaderFactory(-ish) object.
  // This should be used only for requests not served by the network service,
  // e.g. requests with non-network schemes and requests served by prefetch
  // caches. For requests served by the network service, use
  // `ForNetworkContext()` or `ForBrowserProcess()` as they should have
  // corresponding `NetworkContext`s.
  //
  // See the `process_id_` comment below for `process_id`.
  using URLLoaderFactoryTypes =
      std::variant<mojo::PendingRemote<network::mojom::URLLoaderFactory>,
                   scoped_refptr<network::SharedURLLoaderFactory>>;
  static TerminalParams ForNonNetwork(URLLoaderFactoryTypes url_loader_factory,
                                      int process_id);

  TerminalParams(TerminalParams&&);
  TerminalParams& operator=(TerminalParams&&);
  ~TerminalParams();

  network::mojom::NetworkContext* network_context() const;
  HeaderClientOption header_client_option() const;
  FactoryOverrideOption factory_override_option() const;
  DisableSecureDnsOption disable_secure_dns_option() const;
  StoragePartitionImpl* storage_partition() const;
  int process_id() const;
  network::mojom::URLLoaderFactoryParamsPtr TakeFactoryParams();
  std::optional<URLLoaderFactoryTypes> TakeURLLoaderFactory();

 private:
  TerminalParams(network::mojom::NetworkContext* network_context,
                 network::mojom::URLLoaderFactoryParamsPtr factory_params,
                 HeaderClientOption header_client_option,
                 FactoryOverrideOption factory_override_option,
                 DisableSecureDnsOption disable_secure_dns_option,
                 StoragePartitionImpl* storage_partition,
                 std::optional<URLLoaderFactoryTypes> url_loader_factory,
                 int process_id);

  raw_ptr<network::mojom::NetworkContext> network_context_;
  network::mojom::URLLoaderFactoryParamsPtr factory_params_;
  HeaderClientOption header_client_option_;
  FactoryOverrideOption factory_override_option_;
  DisableSecureDnsOption disable_secure_dns_option_;
  raw_ptr<StoragePartitionImpl> storage_partition_;
  std::optional<URLLoaderFactoryTypes> url_loader_factory_;

  // The process ID plumbed to URLLoaderInterceptor. This can be
  // - a renderer process, or
  // - `network::mojom::kBrowserProcessId` for browser process.
  // TODO(crbug.com/324458368): This is different from
  // `ContentClientParams::render_process_id_`. Clarify the meaning of
  // `process_id_` here if needed.
  int process_id_;
};

// Creates a URLLoaderFactory, intercepted by:
// 1. `ContentBrowserClient::WillCreateURLLoaderFactory()`
//    (if `content_client_params` is non-nullopt),
// 2. `devtools_instrumentation` (if `devtools_params` is non-nullopt)
// 3. `GetInterceptor()`
//    (see the comments in the .cc file for detailed conditions)
// and then finally routed as specified by `TerminalParams`.
//
// The created URLLoaderFactory is
// - Returned as `scoped_refptr<network::SharedURLLoaderFactory>`,
// - Returned as `mojo::PendingRemote<network::mojom::URLLoaderFactory>`, or
// - Connected to `receiver_to_connect`,
// respectively for the variants below.
//
// Note that the created URLLoaderFactory might NOT support auto-reconnect after
// a crash of Network Service.
[[nodiscard]] CONTENT_EXPORT scoped_refptr<network::SharedURLLoaderFactory>
Create(ContentBrowserClient::URLLoaderFactoryType type,
       TerminalParams terminal_params,
       std::optional<ContentClientParams> content_client_params = std::nullopt,
       std::optional<devtools_instrumentation::WillCreateURLLoaderFactoryParams>
           devtools_params = std::nullopt);

[[nodiscard]] CONTENT_EXPORT mojo::PendingRemote<
    network::mojom::URLLoaderFactory>
CreatePendingRemote(
    ContentBrowserClient::URLLoaderFactoryType type,
    TerminalParams terminal_params,
    std::optional<ContentClientParams> content_client_params = std::nullopt,
    std::optional<devtools_instrumentation::WillCreateURLLoaderFactoryParams>
        devtools_params = std::nullopt);

CONTENT_EXPORT void CreateAndConnectToPendingReceiver(
    mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver_to_connect,
    ContentBrowserClient::URLLoaderFactoryType type,
    TerminalParams terminal_params,
    std::optional<ContentClientParams> content_client_params = std::nullopt,
    std::optional<devtools_instrumentation::WillCreateURLLoaderFactoryParams>
        devtools_params = std::nullopt);

}  // namespace url_loader_factory
}  // namespace content

#endif  // CONTENT_BROWSER_LOADER_URL_LOADER_FACTORY_UTILS_H_