Commit 579690af authored by Matt Falkenhagen's avatar Matt Falkenhagen Committed by Commit Bot

Add use counter kUndeferrableThirdPartySubresourceRequestWithCookie.

The intent is to measure the page loads that do a blocking (i.e.,
non-deferrable) subresource request with cookies to a third-party from
a first-party frame. This is meant in the context of prererendering:
deferrable means the request can be delayed until navigation, without
blocking progress by the prerendered page.

Currently this is only measuring synchronous classic (non-module)
<script> elements with cookies (not other credentials), but this may
expand later.

Bug: 1131317
Change-Id: I34eea95c67501406928875ce3fe3c3c14e6f372e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2423757
Commit-Queue: Matt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarHiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810192}
parent 818c147f
......@@ -957,6 +957,7 @@ void WebURLLoaderImpl::PopulateURLResponse(
response->SetIsSignedExchangeInnerResponse(
head.is_signed_exchange_inner_response);
response->SetWasInPrefetchCache(head.was_in_prefetch_cache);
response->SetWasCookieInRequest(head.was_cookie_in_request);
response->SetRecursivePrefetchToken(head.recursive_prefetch_token);
SetSecurityStyleAndDetails(url, head, response, report_security_info);
......
......@@ -177,6 +177,9 @@ struct URLResponseHead {
// True if this resource is served from the prefetch cache.
bool was_in_prefetch_cache = false;
// True if the request included a cookie.
bool was_cookie_in_request = false;
// True if the response was intercepted by a plugin.
bool intercepted_by_plugin = false;
......
......@@ -111,6 +111,15 @@ void PopulateResourceResponse(net::URLRequest* request,
!(request->load_flags() & net::LOAD_PREFETCH) &&
response_info.unused_since_prefetch;
response->was_cookie_in_request = false;
for (const auto& cookie_with_access_result : request->maybe_sent_cookies()) {
if (cookie_with_access_result.access_result.status.IsInclude()) {
// IsInclude() true means the cookie was sent.
response->was_cookie_in_request = true;
break;
}
}
if (is_load_timing_enabled)
request->GetLoadTimingInfo(&response->load_timing);
......
......@@ -3009,6 +3009,7 @@ enum WebFeature {
kIdentifiabilityStudyReserved3679 = 3679,
kIdentifiabilityStudyReserved3680 = 3680,
kIdentifiabilityStudyReserved3681 = 3681,
kUndeferrableThirdPartySubresourceRequestWithCookie = 3682,
// Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots.
......
......@@ -318,6 +318,7 @@ class WebURLResponse {
BLINK_PLATFORM_EXPORT void SetIsSignedExchangeInnerResponse(bool);
BLINK_PLATFORM_EXPORT void SetWasInPrefetchCache(bool);
BLINK_PLATFORM_EXPORT void SetWasCookieInRequest(bool);
BLINK_PLATFORM_EXPORT void SetRecursivePrefetchToken(
const base::Optional<base::UnguessableToken>&);
......
......@@ -192,6 +192,50 @@ void RecordNotStreamingReasonHistogram(
} // namespace
void ClassicPendingScript::RecordThirdPartyRequestWithCookieIfNeeded(
const ResourceResponse& response) const {
// Can be null in some cases where loading failed.
if (response.IsNull())
return;
scoped_refptr<SecurityOrigin> script_origin =
SecurityOrigin::Create(response.ResponseUrl());
const SecurityOrigin* doc_origin =
GetElement()->GetExecutionContext()->GetSecurityOrigin();
scoped_refptr<const SecurityOrigin> top_frame_origin =
GetElement()->GetDocument().TopFrameOrigin();
// The use counter is meant to gather data for prerendering: how often do
// pages make credentialed requests to third parties from first-party frames,
// that cannot be delayed during prerendering until the page is navigated to.
// Therefore...
// Ignore third-party frames.
if (!top_frame_origin || top_frame_origin->RegistrableDomain() !=
doc_origin->RegistrableDomain()) {
return;
}
// Ignore first-party requests.
if (doc_origin->RegistrableDomain() == script_origin->RegistrableDomain())
return;
// Ignore cookie-less requests.
if (!response.WasCookieInRequest())
return;
// Ignore scripts that can be delayed. This is only async scripts currently.
// kDefer and kForceDefer don't count as delayable since delaying them
// artificially further while prerendering would prevent the page from making
// progress.
if (GetSchedulingType() == ScriptSchedulingType::kAsync)
return;
GetElement()->GetExecutionContext()->CountUse(
mojom::blink::WebFeature::
kUndeferrableThirdPartySubresourceRequestWithCookie);
}
void ClassicPendingScript::RecordStreamingHistogram(
ScriptSchedulingType type,
bool can_use_streamer,
......@@ -342,6 +386,7 @@ ClassicScript* ClassicPendingScript::GetSource(const KURL& document_url) const {
DCHECK(GetResource()->IsLoaded());
ScriptResource* resource = ToScriptResource(GetResource());
RecordThirdPartyRequestWithCookieIfNeeded(resource->GetResponse());
auto* fetcher = GetElement()->GetExecutionContext()->Fetcher();
// If the MIME check fails, which is considered as load failure.
......
......@@ -101,6 +101,7 @@ class CORE_EXPORT ClassicPendingScript final : public PendingScript,
ScriptSchedulingType type,
bool can_use_streamer,
ScriptStreamer::NotStreamingReason reason);
void RecordThirdPartyRequestWithCookieIfNeeded(const ResourceResponse&) const;
// MemoryPressureListener
void OnPurgeMemory() override;
......
......@@ -152,6 +152,8 @@ class CORE_EXPORT PendingScript : public GarbageCollected<PendingScript>,
base::TimeTicks parser_blocking_load_start_time,
bool is_controlled_by_script_runner);
void RecordThirdPartyRequestWithCookieIfNeeded();
// |m_element| must points to the corresponding ScriptLoader's
// ScriptElementBase and thus must be non-null before dispose() is called
// (except for unit tests).
......
......@@ -450,6 +450,10 @@ void WebURLResponse::SetWasInPrefetchCache(bool was_in_prefetch_cache) {
resource_response_->SetWasInPrefetchCache(was_in_prefetch_cache);
}
void WebURLResponse::SetWasCookieInRequest(bool was_cookie_in_request) {
resource_response_->SetWasCookieInRequest(was_cookie_in_request);
}
void WebURLResponse::SetRecursivePrefetchToken(
const base::Optional<base::UnguessableToken>& token) {
resource_response_->SetRecursivePrefetchToken(token);
......
......@@ -482,6 +482,12 @@ class PLATFORM_EXPORT ResourceResponse final {
was_in_prefetch_cache_ = was_in_prefetch_cache;
}
bool WasCookieInRequest() const { return was_cookie_in_request_; }
void SetWasCookieInRequest(bool was_cookie_in_request) {
was_cookie_in_request_ = was_cookie_in_request;
}
network::mojom::CrossOriginEmbedderPolicyValue GetCrossOriginEmbedderPolicy()
const;
......@@ -565,6 +571,9 @@ class PLATFORM_EXPORT ResourceResponse final {
// True if this resource is served from the prefetch cache.
bool was_in_prefetch_cache_ = false;
// True if a cookie was sent in the request for this resource.
bool was_cookie_in_request_ = false;
// True if this resource was loaded from the network.
bool network_accessed_ = false;
......
......@@ -29457,6 +29457,7 @@ Called by update_use_counter_feature_enum.py.-->
<int value="3679" label="IdentifiabilityStudyReserved3679"/>
<int value="3680" label="IdentifiabilityStudyReserved3680"/>
<int value="3681" label="IdentifiabilityStudyReserved3681"/>
<int value="3682" label="UndeferrableThirdPartySubresourceRequestWithCookie"/>
</enum>
<enum name="FeaturePolicyAllowlistType">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment