blob: 8ac4d3411e699b57d1b13baf284866701898e454 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/url_loader_factory_params_helper.h"
#include <optional>
#include <string_view>
#include "base/command_line.h"
#include "content/browser/devtools/network_service_devtools_observer.h"
#include "content/browser/renderer_host/frame_tree_node.h"
#include "content/browser/renderer_host/navigation_request.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/storage_partition_impl.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/runtime_feature_state/runtime_feature_state_document_data.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/url_constants.h"
#include "ipc/ipc_message.h"
#include "net/base/isolation_info.h"
#include "net/cookies/cookie_setting_override.h"
#include "services/network/public/cpp/is_potentially_trustworthy.h"
#include "services/network/public/mojom/cross_origin_embedder_policy.mojom.h"
#include "services/network/public/mojom/device_bound_sessions.mojom.h"
#include "services/network/public/mojom/early_hints.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/shared_dictionary_access_observer.mojom.h"
#include "services/network/public/mojom/url_loader.mojom-shared.h"
#include "third_party/blink/public/common/tokens/tokens.h"
#include "third_party/blink/public/common/web_preferences/web_preferences.h"
namespace content {
namespace {
// Whether loading state updates to the
// network::mojom::URLLoaderNetworkServiceObserver are inhibited for URLLoaders
// created via URLLoaderFactoryParamsHelper.
//
// network::mojom::URLLoaderNetworkServiceObserver::OnLoadingStateUpdate is
// among the most frequent Mojo messages in traces from the field
// (go/mojos-in-field-traces-2022). Inhibiting the messages has been tested all
// the way to stable with no ill effect and performance gains.
//
// Remove when evaluation of combined performance gains is complete
// crbug.com/1487544.
BASE_FEATURE(kInhibitLoadingStateUpdate,
"InhibitLoadingStateUpdate",
base::FEATURE_ENABLED_BY_DEFAULT);
// Helper used by the public URLLoaderFactoryParamsHelper::Create... methods.
//
// |origin| is the origin that will use the URLLoaderFactory.
// |origin| is typically the same as the origin in
// network::ResourceRequest::request_initiator, except when
// |is_for_isolated_world|. See also the doc comment for
// extensions::URLLoaderFactoryManager::CreateFactory.
network::mojom::URLLoaderFactoryParamsPtr CreateParams(
RenderProcessHost* process,
const url::Origin& origin,
const url::Origin& request_initiator_origin_lock,
bool is_trusted,
const std::optional<blink::LocalFrameToken>& top_frame_token,
const net::IsolationInfo& isolation_info,
network::mojom::ClientSecurityStatePtr client_security_state,
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
coep_reporter,
bool allow_universal_access_from_file_urls,
bool is_for_isolated_world,
mojo::PendingRemote<network::mojom::CookieAccessObserver> cookie_observer,
mojo::PendingRemote<network::mojom::TrustTokenAccessObserver>
trust_token_observer,
mojo::PendingRemote<network::mojom::SharedDictionaryAccessObserver>
shared_dictionary_observer,
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
url_loader_network_observer,
mojo::PendingRemote<network::mojom::DevToolsObserver> devtools_observer,
mojo::PendingRemote<network::mojom::DeviceBoundSessionAccessObserver>
device_bound_session_observer,
network::mojom::TrustTokenOperationPolicyVerdict
trust_token_issuance_policy,
network::mojom::TrustTokenOperationPolicyVerdict
trust_token_redemption_policy,
net::CookieSettingOverrides cookie_setting_overrides,
std::string_view debug_tag,
bool require_cross_site_request_for_cookies) {
DCHECK(process);
network::mojom::URLLoaderFactoryParamsPtr params =
network::mojom::URLLoaderFactoryParams::New();
params->process_id = process->GetDeprecatedID();
params->request_initiator_origin_lock = request_initiator_origin_lock;
params->is_trusted = is_trusted;
if (top_frame_token)
params->top_frame_id = top_frame_token.value().value();
params->isolation_info = isolation_info;
params->disable_web_security =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebSecurity);
params->client_security_state = std::move(client_security_state);
params->coep_reporter = std::move(coep_reporter);
if (params->disable_web_security) {
// --disable-web-security also disables Opaque Response Blocking (ORB).
params->is_orb_enabled = false;
} else if (allow_universal_access_from_file_urls &&
origin.scheme() == url::kFileScheme) {
// allow_universal_access_from_file_urls disables ORB (via
// `is_orb_enabled`) and CORS (via `disable_web_security`) for requests
// made from a file: |origin|.
params->is_orb_enabled = false;
params->disable_web_security = true;
} else {
params->is_orb_enabled = true;
}
params->trust_token_issuance_policy = trust_token_issuance_policy;
params->trust_token_redemption_policy = trust_token_redemption_policy;
// If we have a URLLoaderNetworkObserver, request loading state updates.
if (url_loader_network_observer &&
!base::FeatureList::IsEnabled(kInhibitLoadingStateUpdate)) {
params->provide_loading_state_updates = true;
}
GetContentClient()->browser()->OverrideURLLoaderFactoryParams(
process->GetBrowserContext(), origin, is_for_isolated_world,
params.get());
params->cookie_observer = std::move(cookie_observer);
params->trust_token_observer = std::move(trust_token_observer);
params->shared_dictionary_observer = std::move(shared_dictionary_observer);
params->url_loader_network_observer = std::move(url_loader_network_observer);
params->devtools_observer = std::move(devtools_observer);
params->device_bound_session_observer =
std::move(device_bound_session_observer);
params->cookie_setting_overrides = cookie_setting_overrides;
params->debug_tag = std::string(debug_tag);
params->require_cross_site_request_for_cookies =
require_cross_site_request_for_cookies;
return params;
}
} // namespace
// static
network::mojom::URLLoaderFactoryParamsPtr
URLLoaderFactoryParamsHelper::CreateForFrame(
RenderFrameHostImpl* frame,
const url::Origin& frame_origin,
const net::IsolationInfo& isolation_info,
network::mojom::ClientSecurityStatePtr client_security_state,
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
coep_reporter,
RenderProcessHost* process,
network::mojom::TrustTokenOperationPolicyVerdict
trust_token_issuance_policy,
network::mojom::TrustTokenOperationPolicyVerdict
trust_token_redemption_policy,
net::CookieSettingOverrides cookie_setting_overrides,
std::string_view debug_tag) {
return CreateParams(
process,
frame_origin, // origin
frame_origin, // request_initiator_origin_lock
false, // is_trusted
frame->GetTopFrameToken(), isolation_info,
std::move(client_security_state), std::move(coep_reporter),
frame->GetOrCreateWebPreferences().allow_universal_access_from_file_urls,
false, // is_for_isolated_world
frame->CreateCookieAccessObserver(),
frame->CreateTrustTokenAccessObserver(),
frame->CreateSharedDictionaryAccessObserver(),
frame->CreateURLLoaderNetworkObserver(),
NetworkServiceDevToolsObserver::MakeSelfOwned(frame->frame_tree_node()),
frame->CreateDeviceBoundSessionObserver(), trust_token_issuance_policy,
trust_token_redemption_policy, cookie_setting_overrides, debug_tag,
/*require_cross_site_request_for_cookies=*/false);
}
// static
network::mojom::URLLoaderFactoryParamsPtr
URLLoaderFactoryParamsHelper::CreateForIsolatedWorld(
RenderFrameHostImpl* frame,
const url::Origin& isolated_world_origin,
const url::Origin& main_world_origin,
const net::IsolationInfo& isolation_info,
network::mojom::ClientSecurityStatePtr client_security_state,
network::mojom::TrustTokenOperationPolicyVerdict
trust_token_issuance_policy,
network::mojom::TrustTokenOperationPolicyVerdict
trust_token_redemption_policy,
net::CookieSettingOverrides cookie_setting_overrides) {
return CreateParams(
frame->GetProcess(),
isolated_world_origin, // origin
main_world_origin, // request_initiator_origin_lock
false, // is_trusted
frame->GetTopFrameToken(), isolation_info,
std::move(client_security_state),
mojo::NullRemote(), // coep_reporter
frame->GetOrCreateWebPreferences().allow_universal_access_from_file_urls,
true, // is_for_isolated_world
frame->CreateCookieAccessObserver(),
frame->CreateTrustTokenAccessObserver(),
frame->CreateSharedDictionaryAccessObserver(),
frame->CreateURLLoaderNetworkObserver(),
NetworkServiceDevToolsObserver::MakeSelfOwned(frame->frame_tree_node()),
frame->CreateDeviceBoundSessionObserver(), trust_token_issuance_policy,
trust_token_redemption_policy, cookie_setting_overrides,
"ParamHelper::CreateForIsolatedWorld",
/*require_cross_site_request_for_cookies=*/false);
}
network::mojom::URLLoaderFactoryParamsPtr
URLLoaderFactoryParamsHelper::CreateForPrefetch(
RenderFrameHostImpl* frame,
network::mojom::ClientSecurityStatePtr client_security_state,
net::CookieSettingOverrides cookie_setting_overrides) {
// The factory client |is_trusted| to control the |network_isolation_key| in
// each separate request (rather than forcing the client to use the key
// specified in URLLoaderFactoryParams).
const url::Origin& frame_origin = frame->GetLastCommittedOrigin();
return CreateParams(
frame->GetProcess(),
frame_origin, // origin
frame_origin, // request_initiator_origin_lock
true, // is_trusted
frame->GetTopFrameToken(),
net::IsolationInfo(), // isolation_info
std::move(client_security_state),
mojo::NullRemote(), // coep_reporter
frame->GetOrCreateWebPreferences().allow_universal_access_from_file_urls,
false, // is_for_isolated_world
frame->CreateCookieAccessObserver(),
frame->CreateTrustTokenAccessObserver(),
frame->CreateSharedDictionaryAccessObserver(),
frame->CreateURLLoaderNetworkObserver(),
NetworkServiceDevToolsObserver::MakeSelfOwned(frame->frame_tree_node()),
frame->CreateDeviceBoundSessionObserver(),
network::mojom::TrustTokenOperationPolicyVerdict::kForbid,
network::mojom::TrustTokenOperationPolicyVerdict::kForbid,
cookie_setting_overrides, "ParamHelper::CreateForPrefetch",
/*require_cross_site_request_for_cookies=*/false);
}
// static
// TODO(crbug.com/40190528): make sure client_security_state is no longer
// nullptr anywhere.
// TODO(crbug.com/40247160): Investigate whether to support cookie setting
// overrides (hardcoded empty set used for now).
network::mojom::URLLoaderFactoryParamsPtr
URLLoaderFactoryParamsHelper::CreateForWorker(
RenderProcessHost* process,
const url::Origin& request_initiator,
const net::IsolationInfo& isolation_info,
mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
coep_reporter,
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
url_loader_network_observer,
mojo::PendingRemote<network::mojom::DevToolsObserver> devtools_observer,
network::mojom::ClientSecurityStatePtr client_security_state,
std::string_view debug_tag,
bool require_cross_site_request_for_cookies) {
return CreateParams(
process,
request_initiator, // origin
request_initiator, // request_initiator_origin_lock
false, // is_trusted
std::nullopt, // top_frame_token
isolation_info, std::move(client_security_state),
std::move(coep_reporter),
false, // allow_universal_access_from_file_urls
false, // is_for_isolated_world
static_cast<StoragePartitionImpl*>(process->GetStoragePartition())
->CreateCookieAccessObserverForServiceWorker(),
static_cast<StoragePartitionImpl*>(process->GetStoragePartition())
->CreateTrustTokenAccessObserverForServiceWorker(),
static_cast<StoragePartitionImpl*>(process->GetStoragePartition())
->CreateSharedDictionaryAccessObserverForServiceWorker(),
std::move(url_loader_network_observer), std::move(devtools_observer),
static_cast<StoragePartitionImpl*>(process->GetStoragePartition())
->CreateDeviceBoundSessionObserverForServiceWorker(),
// Trust Token redemption and signing operations require the Permissions
// Policy. It seems Permissions Policy in worker contexts
// is currently an open issue (as of 06/21/2022):
// https://github.com/w3c/webappsec-permissions-policy/issues/207.
network::mojom::TrustTokenOperationPolicyVerdict::kPotentiallyPermit,
network::mojom::TrustTokenOperationPolicyVerdict::kPotentiallyPermit,
net::CookieSettingOverrides(), debug_tag,
require_cross_site_request_for_cookies);
}
// static
// TODO(crbug.com/40247160): Investigate whether to support cookie setting
// overrides (hardcoded empty set used for now).
network::mojom::URLLoaderFactoryParamsPtr
URLLoaderFactoryParamsHelper::CreateForEarlyHintsPreload(
RenderProcessHost* process,
const url::Origin& tentative_origin,
NavigationRequest& navigation_request,
const network::mojom::EarlyHints& early_hints,
mojo::PendingRemote<network::mojom::CookieAccessObserver> cookie_observer,
mojo::PendingRemote<network::mojom::TrustTokenAccessObserver>
trust_token_observer,
mojo::PendingRemote<network::mojom::SharedDictionaryAccessObserver>
shared_dictionary_observer,
mojo::PendingRemote<network::mojom::DeviceBoundSessionAccessObserver>
device_bound_session_observer) {
// TODO(crbug.com/40188470): Consider not using the speculative
// RenderFrameHostImpl to create URLLoaderNetworkServiceObserver.
// In general we should avoid using speculative RenderFrameHostImpl
// to fill URLLoaderFactoryParams because some parameters can be calculated
// only after the RenderFrameHostImpl is committed.
// See also the design doc linked from the bug entry. It describes options
// to create the observer without RenderFrameHostImpl.
mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
url_loader_network_observer = navigation_request.frame_tree_node()
->current_frame_host()
->CreateURLLoaderNetworkObserver();
auto isolation_info = net::IsolationInfo::Create(
net::IsolationInfo::RequestType::kOther,
/*top_frame_origin=*/tentative_origin, /*frame_origin=*/tentative_origin,
net::SiteForCookies::FromOrigin(tentative_origin));
// TODO(https://issues.chromium.org/issues/336754077):
// Support Document-Isolation-Policy in early hints headers instead of passing
// a default DocumentIsolationPolicy.
network::mojom::ClientSecurityStatePtr client_security_state =
network::mojom::ClientSecurityState::New(
early_hints.headers->cross_origin_embedder_policy,
network::IsOriginPotentiallyTrustworthy(tentative_origin),
early_hints.ip_address_space,
network::mojom::PrivateNetworkRequestPolicy::kBlock,
network::DocumentIsolationPolicy());
return CreateParams(
process, /*origin=*/tentative_origin,
/*request_initiator_origin_lock=*/tentative_origin,
/*is_trusted=*/false, /*top_frame_token=*/std::nullopt, isolation_info,
std::move(client_security_state),
/*coep_reporter=*/mojo::NullRemote(),
/*allow_universal_access_from_file_urls=*/false,
/*is_for_isolated_world=*/false, std::move(cookie_observer),
std::move(trust_token_observer), std::move(shared_dictionary_observer),
std::move(url_loader_network_observer),
/*devtools_observer=*/mojo::NullRemote(),
std::move(device_bound_session_observer),
network::mojom::TrustTokenOperationPolicyVerdict::kForbid,
network::mojom::TrustTokenOperationPolicyVerdict::kForbid,
net::CookieSettingOverrides(), "ParamHelper::CreateForEarlyHintsPreload",
/*require_cross_site_request_for_cookies=*/false);
}
} // namespace content