Extend PrefetchContainer::referring_origin_ for general browser-initiated prefetch
This CL is based on wbjacksonjr@'s proposal. Currently, all prefetch triggers have a concept of referring document/origin. Specifically, potential value of PrefetchContainer::referring_origin_ is - If CCT (prefetch from App A that has verified associated origin): referring_origin == A’s origin - If CCT (otherwise): referring_origin == opaque origin [1] so that we can treat this request as a cross-site prefetch. Also, if nullopt is passed to PrefetchContainer's public ctor for browser- initiated prefetch, it is automatically converted to opaque origin [2] - If Speculation rules prefetch in document A: referring_origin == A’s origin In order to introduce WebView prefetch, which has no concepts that corresponds to referring document/origin and thus has no restriction related to it, this CL changes the type of PrefetchContainer::referring_origin_ to std::optional so that general browser-initiated prefetch can use this. Practically this case can be handled like same-site prefetch, in the same manner as normal browser-initiated prerender behaves like same-site prerender. [1] https://source.chromium.org/chromium/chromium/src/+/main:chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java;l=663;drc=8f3124aee72eb5cc75bec53fd9e7999592767e9a [2] https://source.chromium.org/chromium/chromium/src/+/main:content/browser/preloading/prefetch/prefetch_container.cc;l=426;drc=4d3dad034f8aefd3a1c6043eecbd901568546936 Bug: 40946257, 363946909 Co-authored-by: Wayne Jackson Jr. <wbjacksonjr@chromium.org> Change-Id: Ic0d1bf1e3350c719020a6a9b8232a50acc170ab4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5942243 Reviewed-by: Wayne Jackson Jr. <wbjacksonjr@chromium.org> Reviewed-by: Kouhei Ueno <kouhei@chromium.org> Commit-Queue: Kouhei Ueno <kouhei@chromium.org> Cr-Commit-Position: refs/heads/main@{#1373194}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
d71d00babd
commit
9dfeb633bc
@ -336,7 +336,7 @@ bool CalculateIsLikelyAheadOfPrerender(PreloadingAttempt* attempt) {
|
||||
class PrefetchContainer::SinglePrefetch {
|
||||
public:
|
||||
explicit SinglePrefetch(const GURL& url,
|
||||
const url::Origin& referring_origin,
|
||||
bool is_isolated_network_context_required,
|
||||
bool is_reusable);
|
||||
~SinglePrefetch();
|
||||
|
||||
@ -423,7 +423,7 @@ PrefetchContainer::PrefetchContainer(
|
||||
std::optional<PreloadingHoldbackStatus> holdback_status_override)
|
||||
: PrefetchContainer(
|
||||
GlobalRenderFrameHostId(),
|
||||
referring_origin.value_or(url::Origin()),
|
||||
referring_origin,
|
||||
/*referring_url_hash=*/std::nullopt,
|
||||
PrefetchContainer::Key(
|
||||
std::optional<blink::DocumentToken>(std::nullopt),
|
||||
@ -456,7 +456,7 @@ PrefetchContainer::PrefetchContainer(
|
||||
base::WeakPtr<PreloadingAttempt> attempt,
|
||||
std::optional<PrefetchStartCallback> prefetch_start_callback)
|
||||
: PrefetchContainer(GlobalRenderFrameHostId(),
|
||||
referring_origin.value_or(url::Origin()),
|
||||
referring_origin,
|
||||
/*referring_url_hash=*/std::nullopt,
|
||||
PrefetchContainer::Key(
|
||||
std::optional<blink::DocumentToken>(std::nullopt),
|
||||
@ -479,7 +479,7 @@ PrefetchContainer::PrefetchContainer(
|
||||
|
||||
PrefetchContainer::PrefetchContainer(
|
||||
const GlobalRenderFrameHostId& referring_render_frame_host_id,
|
||||
const url::Origin& referring_origin,
|
||||
const std::optional<url::Origin>& referring_origin,
|
||||
const std::optional<size_t>& referring_url_hash,
|
||||
const PrefetchContainer::Key& key,
|
||||
const PrefetchType& prefetch_type,
|
||||
@ -551,7 +551,8 @@ PrefetchContainer::PrefetchContainer(
|
||||
return false;
|
||||
}();
|
||||
redirect_chain_.push_back(std::make_unique<SinglePrefetch>(
|
||||
GetURL(), referring_origin_, is_reusable));
|
||||
GetURL(), IsCrossSiteRequest(url::Origin::Create(GetURL())),
|
||||
is_reusable));
|
||||
}
|
||||
|
||||
PrefetchContainer::~PrefetchContainer() {
|
||||
@ -1010,12 +1011,24 @@ void PrefetchContainer::AddRedirectHop(const net::RedirectInfo& redirect_info) {
|
||||
AddXClientDataHeader(*resource_request_.get());
|
||||
|
||||
redirect_chain_.push_back(std::make_unique<SinglePrefetch>(
|
||||
redirect_info.new_url, referring_origin_,
|
||||
redirect_info.new_url,
|
||||
IsCrossSiteRequest(url::Origin::Create(redirect_info.new_url)),
|
||||
// If `PrefetchResponseReader` of the initial navigation is reusable,
|
||||
// inherit the property.
|
||||
redirect_chain_[0]->response_reader_->is_reusable()));
|
||||
}
|
||||
|
||||
bool PrefetchContainer::IsCrossSiteRequest(const url::Origin& origin) const {
|
||||
return referring_origin_.has_value() &&
|
||||
net::SchemefulSite(referring_origin_.value()) !=
|
||||
net::SchemefulSite(origin);
|
||||
}
|
||||
|
||||
bool PrefetchContainer::IsCrossOriginRequest(const url::Origin& origin) const {
|
||||
return referring_origin_.has_value() &&
|
||||
!referring_origin_.value().IsSameOriginWith(origin);
|
||||
}
|
||||
|
||||
void PrefetchContainer::MarkCrossSiteContaminated() {
|
||||
is_cross_site_contaminated_ = true;
|
||||
}
|
||||
@ -1728,7 +1741,7 @@ PrefetchStatus PrefetchContainer::Reader::GetPrefetchStatus() const {
|
||||
}
|
||||
|
||||
bool PrefetchContainer::IsProxyRequiredForURL(const GURL& url) const {
|
||||
return !referring_origin_.IsSameOriginWith(url) &&
|
||||
return IsCrossOriginRequest(url::Origin::Create(url)) &&
|
||||
prefetch_type_.IsProxyRequiredWhenCrossOrigin();
|
||||
}
|
||||
|
||||
@ -1856,11 +1869,10 @@ void PrefetchContainer::AddClientHintsHeaders(
|
||||
// prefetch, and potentially a cross-site only. (This logic might need to be
|
||||
// revisited if we ever supported prefetching in another site's partition,
|
||||
// such as in a subframe.)
|
||||
const bool is_same_site =
|
||||
net::SchemefulSite(referring_origin_) == net::SchemefulSite(origin);
|
||||
const bool is_cross_site = IsCrossSiteRequest(origin);
|
||||
const auto cross_site_behavior =
|
||||
features::kPrefetchClientHintsCrossSiteBehavior.Get();
|
||||
if (is_same_site ||
|
||||
if (!is_cross_site ||
|
||||
cross_site_behavior ==
|
||||
features::PrefetchClientHintsCrossSiteBehavior::kAll) {
|
||||
request_headers->MergeFrom(client_hints_headers);
|
||||
@ -1933,11 +1945,11 @@ CONTENT_EXPORT std::ostream& operator<<(
|
||||
|
||||
PrefetchContainer::SinglePrefetch::SinglePrefetch(
|
||||
const GURL& url,
|
||||
const url::Origin& referring_origin,
|
||||
bool is_isolated_network_context_required,
|
||||
bool is_reusable)
|
||||
: url_(url),
|
||||
is_isolated_network_context_required_(
|
||||
net::SchemefulSite(referring_origin) != net::SchemefulSite(url_)),
|
||||
is_isolated_network_context_required),
|
||||
response_reader_(
|
||||
base::MakeRefCounted<PrefetchResponseReader>(is_reusable)) {}
|
||||
|
||||
|
@ -111,8 +111,7 @@ class CONTENT_EXPORT PrefetchContainer {
|
||||
|
||||
// Ctor used for browser-initiated prefetch.
|
||||
// We can pass the referring origin of prefetches via `referring_origin` if
|
||||
// necessary. When `std::nullopt` is passed, the referring origin will be
|
||||
// opaque.
|
||||
// necessary.
|
||||
PrefetchContainer(
|
||||
WebContents& referring_web_contents,
|
||||
const GURL& url,
|
||||
@ -126,8 +125,7 @@ class CONTENT_EXPORT PrefetchContainer {
|
||||
|
||||
// Ctor used for browser-initiated prefetch that doesn't depend on web
|
||||
// contents. We can pass the referring origin of prefetches via
|
||||
// `referrer_origin` if necessary. When `std::nullopt` is passed, the
|
||||
// referring origin will be opaque.
|
||||
// `referrer_origin` if necessary.
|
||||
PrefetchContainer(
|
||||
BrowserContext* browser_context,
|
||||
const GURL& url,
|
||||
@ -268,7 +266,9 @@ class CONTENT_EXPORT PrefetchContainer {
|
||||
bool IsRendererInitiated() const;
|
||||
|
||||
// The origin and that initiates the prefetch request.
|
||||
const url::Origin& GetReferringOrigin() const { return referring_origin_; }
|
||||
const std::optional<url::Origin> GetReferringOrigin() const {
|
||||
return referring_origin_;
|
||||
}
|
||||
|
||||
// Whether or not an isolated network context is required to the next
|
||||
// prefetch.
|
||||
@ -384,6 +384,10 @@ class CONTENT_EXPORT PrefetchContainer {
|
||||
void SetIsDecoy(bool is_decoy) { is_decoy_ = is_decoy; }
|
||||
bool IsDecoy() const { return is_decoy_; }
|
||||
|
||||
// Whether the prefetch request is cross-site/cross-origin for given origin.
|
||||
bool IsCrossSiteRequest(const url::Origin& origin) const;
|
||||
bool IsCrossOriginRequest(const url::Origin& origin) const;
|
||||
|
||||
// Whether this prefetch is potentially contaminated by cross-site state.
|
||||
// If so, it may need special handling for privacy.
|
||||
// See https://crbug.com/1439246.
|
||||
@ -769,7 +773,7 @@ class CONTENT_EXPORT PrefetchContainer {
|
||||
private:
|
||||
PrefetchContainer(
|
||||
const GlobalRenderFrameHostId& referring_render_frame_host_id,
|
||||
const url::Origin& referring_origin,
|
||||
const std::optional<url::Origin>& referring_origin,
|
||||
const std::optional<size_t>& referring_url_hash,
|
||||
const PrefetchContainer::Key& key,
|
||||
const PrefetchType& prefetch_type,
|
||||
@ -837,8 +841,8 @@ class CONTENT_EXPORT PrefetchContainer {
|
||||
// The origin and URL that initiates the prefetch request.
|
||||
// For renderer-initiated prefetch, this is calculated by referring
|
||||
// RenderFrameHost's LastCommittedOrigin. For browser-initiated prefetch, this
|
||||
// is sometimes explicitly passed via ctor, otherwise opaque origin.
|
||||
const url::Origin referring_origin_;
|
||||
// is sometimes explicitly passed via ctor.
|
||||
const std::optional<url::Origin> referring_origin_;
|
||||
// Used by metrics for equality checks, only works for renderer-initiated
|
||||
// triggers.
|
||||
const std::optional<size_t> referring_url_hash_;
|
||||
|
@ -312,7 +312,7 @@ TEST_P(PrefetchContainerTest, CreatePrefetchContainer_Embedder) {
|
||||
PrefetchContainer prefetch_container(
|
||||
*web_contents(), GURL("https://test.com"),
|
||||
PrefetchType(PreloadingTriggerType::kEmbedder,
|
||||
/*use_prefetch_proxy=*/true),
|
||||
/*use_prefetch_proxy=*/false),
|
||||
blink::mojom::Referrer(), /*referring_origin=*/std::nullopt,
|
||||
/*no_vary_search_expected=*/std::nullopt, /*attempt=*/nullptr);
|
||||
|
||||
@ -321,8 +321,8 @@ TEST_P(PrefetchContainerTest, CreatePrefetchContainer_Embedder) {
|
||||
EXPECT_EQ(prefetch_container.GetURL(), GURL("https://test.com"));
|
||||
EXPECT_EQ(prefetch_container.GetPrefetchType(),
|
||||
PrefetchType(PreloadingTriggerType::kEmbedder,
|
||||
/*use_prefetch_proxy=*/true));
|
||||
EXPECT_TRUE(
|
||||
/*use_prefetch_proxy=*/false));
|
||||
EXPECT_FALSE(
|
||||
prefetch_container.IsIsolatedNetworkContextRequiredForCurrentPrefetch());
|
||||
|
||||
EXPECT_EQ(prefetch_container.key(),
|
||||
@ -1064,8 +1064,8 @@ TEST_P(PrefetchContainerTest, IsIsolatedNetworkRequired_Embedder) {
|
||||
auto prefetch_container_default = CreateEmbedderPrefetchContainer(
|
||||
GURL("https://test.com/prefetch"), std::nullopt);
|
||||
prefetch_container_default->MakeResourceRequest({});
|
||||
EXPECT_TRUE(prefetch_container_default
|
||||
->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
|
||||
EXPECT_FALSE(prefetch_container_default
|
||||
->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
|
||||
|
||||
auto prefetch_container_same_origin = CreateEmbedderPrefetchContainer(
|
||||
GURL("https://test.com/prefetch"),
|
||||
|
@ -36,7 +36,7 @@ PrefetchNetworkContext::PrefetchNetworkContext(
|
||||
bool use_isolated_network_context,
|
||||
const PrefetchType& prefetch_type,
|
||||
const GlobalRenderFrameHostId& referring_render_frame_host_id,
|
||||
const url::Origin& referring_origin)
|
||||
const std::optional<url::Origin>& referring_origin)
|
||||
: use_isolated_network_context_(use_isolated_network_context),
|
||||
prefetch_type_(prefetch_type),
|
||||
referring_render_frame_host_id_(referring_render_frame_host_id),
|
||||
@ -209,7 +209,8 @@ PrefetchNetworkContext::CreateNewURLLoaderFactory(
|
||||
url_loader_factory::HeaderClientOption::kAllow),
|
||||
url_loader_factory::ContentClientParams(
|
||||
browser_context, referring_render_frame_host,
|
||||
referring_render_process_id, referring_origin_, net::IsolationInfo(),
|
||||
referring_render_process_id,
|
||||
referring_origin_.value_or(url::Origin()), net::IsolationInfo(),
|
||||
ukm_source_id, &bypass_redirect_checks));
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ class CONTENT_EXPORT PrefetchNetworkContext {
|
||||
bool use_isolated_network_context,
|
||||
const PrefetchType& prefetch_type,
|
||||
const GlobalRenderFrameHostId& referring_render_frame_host_id,
|
||||
const url::Origin& referring_origin);
|
||||
const std::optional<url::Origin>& referring_origin);
|
||||
~PrefetchNetworkContext();
|
||||
|
||||
PrefetchNetworkContext(const PrefetchNetworkContext&) = delete;
|
||||
@ -78,7 +78,7 @@ class CONTENT_EXPORT PrefetchNetworkContext {
|
||||
// proxy |url_loader_factory_| by calling WillCreateURLLoaderFactory.
|
||||
// For renderer-initiated prefetch, this is calculated by referring
|
||||
// RenderFrameHost's LastCommittedOrigin.
|
||||
const url::Origin referring_origin_;
|
||||
const std::optional<url::Origin> referring_origin_;
|
||||
|
||||
// The network context and URL loader factory to use when making prefetches.
|
||||
mojo::Remote<network::mojom::NetworkContext> network_context_;
|
||||
|
@ -523,8 +523,9 @@ void PrefetchService::PrefetchUrl(
|
||||
(PrefetchAllowAllDomainsForExtendedPreloading() &&
|
||||
delegate_->IsExtendedPreloadingEnabled());
|
||||
if (!allow_all_domains &&
|
||||
prefetch_container->GetReferringOrigin().has_value() &&
|
||||
!delegate_->IsDomainInPrefetchAllowList(
|
||||
prefetch_container->GetReferringOrigin().GetURL())) {
|
||||
prefetch_container->GetReferringOrigin().value().GetURL())) {
|
||||
DVLOG(1) << *prefetch_container
|
||||
<< ": not prefetched (not in allow list)";
|
||||
return;
|
||||
|
@ -1370,13 +1370,13 @@ TEST_P(PrefetchServiceTest, SuccessCase_Embedder) {
|
||||
|
||||
MakePrefetchFromEmbedder(GURL("https://example.com"),
|
||||
PrefetchType(PreloadingTriggerType::kEmbedder,
|
||||
/*use_prefetch_proxy=*/true));
|
||||
/*use_prefetch_proxy=*/false));
|
||||
task_environment()->RunUntilIdle();
|
||||
|
||||
VerifyCommonRequestState(GURL("https://example.com"),
|
||||
{.use_prefetch_proxy = true});
|
||||
{.use_prefetch_proxy = false});
|
||||
MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType,
|
||||
/*use_prefetch_proxy=*/true,
|
||||
/*use_prefetch_proxy=*/false,
|
||||
{{"X-Testing", "Hello World"}}, kHTMLBody);
|
||||
|
||||
// Verify that the prefetch request was successful.
|
||||
@ -1416,13 +1416,13 @@ TEST_P(PrefetchServiceTest,
|
||||
|
||||
MakePrefetchFromEmbedder(GURL("https://example.com"),
|
||||
PrefetchType(PreloadingTriggerType::kEmbedder,
|
||||
/*use_prefetch_proxy=*/true));
|
||||
/*use_prefetch_proxy=*/false));
|
||||
task_environment()->RunUntilIdle();
|
||||
|
||||
VerifyCommonRequestState(GURL("https://example.com"),
|
||||
{.use_prefetch_proxy = true});
|
||||
{.use_prefetch_proxy = false});
|
||||
MakeResponseAndWait(net::HTTP_OK, net::OK, kHTMLMimeType,
|
||||
/*use_prefetch_proxy=*/true,
|
||||
/*use_prefetch_proxy=*/false,
|
||||
{{"X-Testing", "Hello World"}}, kHTMLBody);
|
||||
|
||||
// Verify that the prefetch request was successful.
|
||||
|
Reference in New Issue
Block a user