blob: 4ac238cd4abe60df211aa2a21c62db6e7ec876af [file] [log] [blame]
// 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_