Commit 2e756665 authored by rajendrant's avatar rajendrant Committed by Chromium LUCI CQ

SubresourceRedirect: Record breakdown metrics for JS-created, CSP, CORS

This CL records the ineligibility for Blink disabling images for
subresource redirect.

Bug: 1167025
Change-Id: I615fba6989b9fa2bb2d7391e45bd89348992c731
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2633097
Commit-Queue: rajendrant <rajendrant@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarTarun Bansal <tbansal@chromium.org>
Reviewed-by: default avatarMichael Crouse <mcrouse@chromium.org>
Auto-Submit: rajendrant <rajendrant@chromium.org>
Cr-Commit-Position: refs/heads/master@{#846245}
parent 4ecda944
...@@ -972,6 +972,8 @@ IN_PROC_BROWSER_TEST_F(SubresourceRedirectBrowserTest, ...@@ -972,6 +972,8 @@ IN_PROC_BROWSER_TEST_F(SubresourceRedirectBrowserTest,
VerifyIneligibleImageHintsUnavailableUkm(0); VerifyIneligibleImageHintsUnavailableUkm(0);
VerifyIneligibleMissingInImageHintsUkm(0); VerifyIneligibleMissingInImageHintsUkm(0);
VerifyImageCompressionPageInfoState(true); VerifyImageCompressionPageInfoState(true);
histogram_tester()->ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 1);
} }
// This test verifies images restricted via CSP img-src directive will not be // This test verifies images restricted via CSP img-src directive will not be
...@@ -992,6 +994,8 @@ IN_PROC_BROWSER_TEST_F(SubresourceRedirectBrowserTest, ...@@ -992,6 +994,8 @@ IN_PROC_BROWSER_TEST_F(SubresourceRedirectBrowserTest,
"SubresourceRedirect.CompressionAttempt.ResponseCode", 0); "SubresourceRedirect.CompressionAttempt.ResponseCode", 0);
EXPECT_TRUE(RunScriptExtractBool("checkImage()")); EXPECT_TRUE(RunScriptExtractBool("checkImage()"));
content::FetchHistogramsFromChildProcesses();
metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
EXPECT_EQ(GURL(RunScriptExtractString("imageSrc()")).port(), EXPECT_EQ(GURL(RunScriptExtractString("imageSrc()")).port(),
https_url().port()); https_url().port());
...@@ -1001,10 +1005,12 @@ IN_PROC_BROWSER_TEST_F(SubresourceRedirectBrowserTest, ...@@ -1001,10 +1005,12 @@ IN_PROC_BROWSER_TEST_F(SubresourceRedirectBrowserTest,
VerifyIneligibleImageHintsUnavailableUkm(0); VerifyIneligibleImageHintsUnavailableUkm(0);
VerifyIneligibleMissingInImageHintsUkm(0); VerifyIneligibleMissingInImageHintsUkm(0);
VerifyImageCompressionPageInfoState(true); VerifyImageCompressionPageInfoState(true);
histogram_tester()->ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 2);
} }
// This test verifies images restricted via CSP img-src directive will not be // This test verifies images restricted via CSP default-src directive will not
// redirected. // be redirected.
IN_PROC_BROWSER_TEST_F( IN_PROC_BROWSER_TEST_F(
SubresourceRedirectBrowserTest, SubresourceRedirectBrowserTest,
DISABLE_ON_WIN_MAC_CHROMEOS( DISABLE_ON_WIN_MAC_CHROMEOS(
...@@ -1022,6 +1028,8 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1022,6 +1028,8 @@ IN_PROC_BROWSER_TEST_F(
"SubresourceRedirect.CompressionAttempt.ResponseCode", 0); "SubresourceRedirect.CompressionAttempt.ResponseCode", 0);
EXPECT_TRUE(RunScriptExtractBool("checkImage()")); EXPECT_TRUE(RunScriptExtractBool("checkImage()"));
content::FetchHistogramsFromChildProcesses();
metrics::SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
EXPECT_EQ(GURL(RunScriptExtractString("imageSrc()")).port(), EXPECT_EQ(GURL(RunScriptExtractString("imageSrc()")).port(),
https_url().port()); https_url().port());
...@@ -1031,6 +1039,8 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1031,6 +1039,8 @@ IN_PROC_BROWSER_TEST_F(
VerifyIneligibleImageHintsUnavailableUkm(0); VerifyIneligibleImageHintsUnavailableUkm(0);
VerifyIneligibleMissingInImageHintsUkm(0); VerifyIneligibleMissingInImageHintsUkm(0);
VerifyImageCompressionPageInfoState(true); VerifyImageCompressionPageInfoState(true);
histogram_tester()->ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 2);
} }
IN_PROC_BROWSER_TEST_F( IN_PROC_BROWSER_TEST_F(
...@@ -1062,6 +1072,8 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1062,6 +1072,8 @@ IN_PROC_BROWSER_TEST_F(
VerifyIneligibleMissingInImageHintsUkm(0); VerifyIneligibleMissingInImageHintsUkm(0);
VerifyIneligibleOtherImageUkm(0); VerifyIneligibleOtherImageUkm(0);
VerifyImageCompressionPageInfoState(true); VerifyImageCompressionPageInfoState(true);
histogram_tester()->ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 0);
} }
IN_PROC_BROWSER_TEST_F( IN_PROC_BROWSER_TEST_F(
...@@ -1085,11 +1097,14 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1085,11 +1097,14 @@ IN_PROC_BROWSER_TEST_F(
EXPECT_EQ(GURL(RunScriptExtractString("imageSrc()")).port(), EXPECT_EQ(GURL(RunScriptExtractString("imageSrc()")).port(),
https_url().port()); https_url().port());
// 3 images are not compressible, 1 image is compressible.
VerifyCompressibleImageUkm(1); VerifyCompressibleImageUkm(1);
VerifyIneligibleImageHintsUnavailableUkm(0); VerifyIneligibleImageHintsUnavailableUkm(0);
VerifyIneligibleMissingInImageHintsUkm(0); VerifyIneligibleMissingInImageHintsUkm(0);
VerifyIneligibleOtherImageUkm(3); VerifyIneligibleOtherImageUkm(3);
VerifyImageCompressionPageInfoState(true); VerifyImageCompressionPageInfoState(true);
histogram_tester()->ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 6);
} }
// This test verifies that no image redirect happens when empty hints is sent. // This test verifies that no image redirect happens when empty hints is sent.
......
...@@ -4,11 +4,13 @@ ...@@ -4,11 +4,13 @@
#include <tuple> #include <tuple>
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/loader/subresource_redirect_util.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/style/computed_style.h" #include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/style_image.h" #include "third_party/blink/renderer/core/style/style_image.h"
...@@ -57,17 +59,52 @@ class SubresourceRedirectSimTest ...@@ -57,17 +59,52 @@ class SubresourceRedirectSimTest
GetDocument().UpdateStyleAndLayoutTree(); GetDocument().UpdateStyleAndLayoutTree();
} }
// Loads the main page resource and then loads the given image in the page.
void LoadMainResourceAndImage(const String& html_body,
const String& img_url) {
SimRequest image_resource(img_url, "image/png");
LoadMainResource(html_body);
if (!is_lazyload_image_enabled())
image_resource.Complete(ReadTestImage());
Compositor().BeginFrame();
test::RunPendingTasks();
if (is_lazyload_image_enabled()) {
// Scroll down until the image is visible.
GetDocument().View()->LayoutViewport()->SetScrollOffset(
ScrollOffset(0, 10000), mojom::blink::ScrollType::kProgrammatic);
Compositor().BeginFrame();
test::RunPendingTasks();
image_resource.Complete(ReadTestImage());
}
}
// Verifies previews state for the fetched request URL.
void VerifySubresourceRedirectPreviewsState(
const String& url,
bool is_subresource_redirect_allowed) {
PreviewsState previews_state = GetDocument()
.Fetcher()
->CachedResource(KURL(url))
->GetResourceRequest()
.GetPreviewsState();
EXPECT_EQ(is_subresource_redirect_allowed,
(previews_state & PreviewsTypes::kSubresourceRedirectOn) != 0);
}
ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test_; ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test_;
ScopedAutomaticLazyImageLoadingForTest ScopedAutomaticLazyImageLoadingForTest
scoped_automatic_lazy_image_loading_for_test_; scoped_automatic_lazy_image_loading_for_test_;
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
base::HistogramTester histogram_tester_;
}; };
// This test verifies subresource redirect previews state based on different // This test verifies subresource redirect previews state based on different
// states of SaveData, LazyLoad, SubresourceRedirect features. // states of SaveData, LazyLoad, SubresourceRedirect features.
TEST_P(SubresourceRedirectSimTest, CSSBackgroundImage) { TEST_P(SubresourceRedirectSimTest, CSSBackgroundImage) {
SimRequest image_resource("https://example.com/img.png", "image/png"); LoadMainResourceAndImage(R"HTML(
LoadMainResource(R"HTML(
<style> <style>
#deferred_image { #deferred_image {
height:200px; height:200px;
...@@ -76,33 +113,159 @@ TEST_P(SubresourceRedirectSimTest, CSSBackgroundImage) { ...@@ -76,33 +113,159 @@ TEST_P(SubresourceRedirectSimTest, CSSBackgroundImage) {
</style> </style>
<div style='height:10000px;'></div> <div style='height:10000px;'></div>
<div id="deferred_image"></div> <div id="deferred_image"></div>
)HTML"); )HTML",
"https://example.com/img.png");
if (!is_lazyload_image_enabled()) // Subresource redirect previews bit should be set only if SaveData and
image_resource.Complete(ReadTestImage()); // SubresourceRedirect feature are enabled.
VerifySubresourceRedirectPreviewsState(
Compositor().BeginFrame(); "https://example.com/img.png",
test::RunPendingTasks(); is_save_data_enabled() && is_subresource_redirect_enabled());
}
if (is_lazyload_image_enabled()) { TEST_P(SubresourceRedirectSimTest, ImgElement) {
// Scroll down until the background image is visible. LoadMainResourceAndImage(R"HTML(
GetDocument().View()->LayoutViewport()->SetScrollOffset( <body>
ScrollOffset(0, 10000), mojom::blink::ScrollType::kProgrammatic); <img src='https://example.com/img.png' loading='lazy'/>
Compositor().BeginFrame(); </body>
test::RunPendingTasks(); )HTML",
image_resource.Complete(ReadTestImage()); "https://example.com/img.png");
}
PreviewsState previews_state =
GetDocument()
.Fetcher()
->CachedResource(KURL("https://example.com/img.png"))
->GetResourceRequest()
.GetPreviewsState();
// Subresource redirect previews bit should be set only if SaveData and // Subresource redirect previews bit should be set only if SaveData and
// SubresourceRedirect feature are enabled. // SubresourceRedirect feature are enabled.
EXPECT_EQ(is_save_data_enabled() && is_subresource_redirect_enabled(), VerifySubresourceRedirectPreviewsState(
(previews_state & PreviewsTypes::kSubresourceRedirectOn) != 0); "https://example.com/img.png",
is_save_data_enabled() && is_subresource_redirect_enabled());
histogram_tester_.ExpectTotalCount("SubresourceRedirect.Blink.Ineligibility",
0);
}
TEST_P(SubresourceRedirectSimTest, JavascriptCreatedSameOriginImage) {
LoadMainResourceAndImage(R"HTML(
<body>
<div></div>
<script>
var img = document.createElement("img");
img.loading = 'lazy';
img.src = 'https://example.com/img.png';
document.getElementsByTagName('div')[0].appendChild(img);
</script>
</body>
)HTML",
"https://example.com/img.png");
VerifySubresourceRedirectPreviewsState("https://example.com/img.png", false);
if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
histogram_tester_.ExpectUniqueSample(
"SubresourceRedirect.Blink.Ineligibility",
BlinkSubresourceRedirectIneligibility::kJavascriptCreatedSameOrigin,
is_lazyload_image_enabled() ? 2 : 1);
} else {
histogram_tester_.ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 0);
}
}
TEST_P(SubresourceRedirectSimTest, JavascriptCreatedCrossOriginImage) {
LoadMainResourceAndImage(R"HTML(
<body>
<div></div>
<script>
var img = document.createElement("img");
img.loading = 'lazy';
img.src = 'https://differentorigin.com/img.png';
document.getElementsByTagName('div')[0].appendChild(img);
</script>
</body>
)HTML",
"https://differentorigin.com/img.png");
VerifySubresourceRedirectPreviewsState("https://differentorigin.com/img.png",
false);
if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
histogram_tester_.ExpectUniqueSample(
"SubresourceRedirect.Blink.Ineligibility",
BlinkSubresourceRedirectIneligibility::kJavascriptCreatedCrossOrigin,
is_lazyload_image_enabled() ? 2 : 1);
} else {
histogram_tester_.ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 0);
}
}
TEST_P(SubresourceRedirectSimTest, ImgElementWithCrossOriginAttribute) {
LoadMainResourceAndImage(R"HTML(
<body>
<img src='https://example.com/img.png' loading='lazy' crossorigin='anonymous'/>
</body>
)HTML",
"https://example.com/img.png");
VerifySubresourceRedirectPreviewsState("https://example.com/img.png", false);
if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
histogram_tester_.ExpectUniqueSample(
"SubresourceRedirect.Blink.Ineligibility",
BlinkSubresourceRedirectIneligibility::kCrossOriginAttributeSet,
is_lazyload_image_enabled() ? 2 : 1);
} else {
histogram_tester_.ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 0);
}
}
TEST_P(SubresourceRedirectSimTest,
RestrictedByContentSecurityPolicyDefaultSrc) {
LoadMainResourceAndImage(R"HTML(
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
</head>
<body>
<img src='https://example.com/img.png' loading='lazy'/>
</body>
)HTML",
"https://example.com/img.png");
VerifySubresourceRedirectPreviewsState("https://example.com/img.png", false);
if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
histogram_tester_.ExpectUniqueSample(
"SubresourceRedirect.Blink.Ineligibility",
BlinkSubresourceRedirectIneligibility::
kContentSecurityPolicyDefaultSrcRestricted,
is_lazyload_image_enabled() ? 2 : 1);
} else {
histogram_tester_.ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 0);
}
}
TEST_P(SubresourceRedirectSimTest, RestrictedByContentSecurityPolicyImgSrc) {
LoadMainResourceAndImage(R"HTML(
<head>
<meta http-equiv="Content-Security-Policy" content="img-src 'self'">
</head>
<body>
<img src='https://example.com/img.png' loading='lazy'/>
</body>
)HTML",
"https://example.com/img.png");
VerifySubresourceRedirectPreviewsState("https://example.com/img.png", false);
if (is_save_data_enabled() && is_subresource_redirect_enabled()) {
histogram_tester_.ExpectUniqueSample(
"SubresourceRedirect.Blink.Ineligibility",
BlinkSubresourceRedirectIneligibility::
kContentSecurityPolicyImgSrcRestricted,
is_lazyload_image_enabled() ? 2 : 1);
} else {
histogram_tester_.ExpectTotalCount(
"SubresourceRedirect.Blink.Ineligibility", 0);
}
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
......
...@@ -50,6 +50,8 @@ blink_core_sources_loader = [ ...@@ -50,6 +50,8 @@ blink_core_sources_loader = [
"http_refresh_scheduler.h", "http_refresh_scheduler.h",
"idleness_detector.cc", "idleness_detector.cc",
"idleness_detector.h", "idleness_detector.h",
"subresource_redirect_util.cc",
"subresource_redirect_util.h",
"image_loader.cc", "image_loader.cc",
"image_loader.h", "image_loader.h",
"importance_attribute.cc", "importance_attribute.cc",
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h" #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_client_hints_type.h" #include "third_party/blink/public/platform/web_client_hints_type.h"
#include "third_party/blink/public/platform/web_url_request.h" #include "third_party/blink/public/platform/web_url_request.h"
...@@ -38,7 +37,6 @@ ...@@ -38,7 +37,6 @@
#include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/increment_load_event_delay_count.h" #include "third_party/blink/renderer/core/dom/increment_load_event_delay_count.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/frame_owner.h" #include "third_party/blink/renderer/core/frame/frame_owner.h"
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h" #include "third_party/blink/renderer/core/frame/local_frame_client.h"
...@@ -53,6 +51,7 @@ ...@@ -53,6 +51,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h" #include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h"
#include "third_party/blink/renderer/core/loader/importance_attribute.h" #include "third_party/blink/renderer/core/loader/importance_attribute.h"
#include "third_party/blink/renderer/core/loader/lazy_image_helper.h" #include "third_party/blink/renderer/core/loader/lazy_image_helper.h"
#include "third_party/blink/renderer/core/loader/subresource_redirect_util.h"
#include "third_party/blink/renderer/core/probe/async_task_id.h" #include "third_party/blink/renderer/core/probe/async_task_id.h"
#include "third_party/blink/renderer/core/probe/core_probes.h" #include "third_party/blink/renderer/core/probe/core_probes.h"
#include "third_party/blink/renderer/core/svg/graphics/svg_image.h" #include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
...@@ -66,7 +65,6 @@ ...@@ -66,7 +65,6 @@
#include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h" #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_loading_log.h"
#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h" #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
...@@ -115,42 +113,6 @@ bool CanReuseFromListOfAvailableImages( ...@@ -115,42 +113,6 @@ bool CanReuseFromListOfAvailableImages(
return true; return true;
} }
// Returns whether subresource redirect can be attempted for the image fetch.
// Redirect to other origins could be disabled due to CSP or CORS restrictions.
bool ShouldEnableSubresourceRedirect(HTMLImageElement* image_element,
const KURL& url) {
// Allow redirection only when DataSaver is enabled and subresource redirect
// feature is enabled which allows redirecting to better optimized versions.
if (!base::FeatureList::IsEnabled(blink::features::kSubresourceRedirect) ||
!GetNetworkStateNotifier().SaveDataEnabled()) {
return false;
}
// Enable subresource redirect only for <img> elements created by parser.
// Images created from javascript, fetched via XHR/Fetch API should not be
// subresource redirected due to the additional CORB/CORS handling needed for
// them.
if (!image_element || !image_element->ElementCreatedByParser()) {
return false;
}
// Create a cross origin URL by appending a string to the original host. This
// is used to find whether CSP is restricting image fetches from other
// origins.
KURL cross_origin_url = url;
cross_origin_url.SetHost(url.Host() + "crossorigin.com");
auto* content_security_policy =
image_element->GetExecutionContext()->GetContentSecurityPolicy();
if (content_security_policy &&
!content_security_policy->AllowImageFromSource(
cross_origin_url, cross_origin_url, RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting)) {
return false;
}
// Allow subresource redirect only when cross-origin attribute is not set,
// which indicates CORS validation is not triggered for the image.
return (GetCrossOriginAttributeValue(image_element->FastGetAttribute(
html_names::kCrossoriginAttr)) == kCrossOriginAttributeNotSet);
}
} // namespace } // namespace
class ImageLoader::Task { class ImageLoader::Task {
......
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/core/loader/subresource_redirect_util.h"
#include "base/metrics/histogram_functions.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/html/cross_origin_attribute.h"
#include "third_party/blink/renderer/platform/network/network_state_notifier.h"
#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
namespace blink {
namespace {
// Records the ineligibility metrics.
void RecordSubresourceRedirectIneligibility(
BlinkSubresourceRedirectIneligibility reason) {
base::UmaHistogramEnumeration("SubresourceRedirect.Blink.Ineligibility",
reason);
}
// Returns whether the URL scheme is http or https.
bool IsSchemeHttpOrHttps(const KURL& url) {
return url.Protocol() == url::kHttpsScheme ||
url.Protocol() == url::kHttpScheme;
}
} // namespace
bool ShouldEnableSubresourceRedirect(HTMLImageElement* image_element,
const KURL& url) {
if (!image_element)
return false;
// Allow redirection only when DataSaver is enabled and subresource redirect
// feature is enabled which allows redirecting to better optimized versions.
if (!base::FeatureList::IsEnabled(blink::features::kSubresourceRedirect) ||
!GetNetworkStateNotifier().SaveDataEnabled()) {
return false;
}
// Allow redirection only for http(s) subresources on http(s) documents.
if (!IsSchemeHttpOrHttps(url) ||
!IsSchemeHttpOrHttps(image_element->GetDocument().Url())) {
return false;
}
// Enable subresource redirect only for <img> elements created by parser.
// Images created from javascript, fetched via XHR/Fetch API should not be
// subresource redirected due to the additional CORB/CORS handling needed for
// them.
if (!image_element->ElementCreatedByParser()) {
RecordSubresourceRedirectIneligibility(
SecurityOrigin::AreSameOrigin(url, image_element->GetDocument().Url())
? BlinkSubresourceRedirectIneligibility::
kJavascriptCreatedSameOrigin
: BlinkSubresourceRedirectIneligibility::
kJavascriptCreatedCrossOrigin);
return false;
}
// Create a cross origin URL by appending a string to the original host. This
// is used to find whether CSP is restricting image fetches from other
// origins.
KURL cross_origin_url = url;
cross_origin_url.SetHost(url.Host() + "crossorigin.com");
auto* content_security_policy =
image_element->GetExecutionContext()->GetContentSecurityPolicy();
if (content_security_policy &&
!content_security_policy->AllowImageFromSource(
cross_origin_url, cross_origin_url, RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting)) {
// Check if an object is allowed by CSP as a proxy to determine whether the
// image resource was disallowed by default-src or img-src directives. When
// an object is allowed it means default-src did not disallow the image.
RecordSubresourceRedirectIneligibility(
content_security_policy->AllowRequest(
mojom::blink::RequestContextType::OBJECT,
network::mojom::RequestDestination::kObject, cross_origin_url,
String() /* nonce */, IntegrityMetadataSet(),
ParserDisposition::kParserInserted, cross_origin_url,
RedirectStatus::kNoRedirect,
ReportingDisposition::kSuppressReporting,
ContentSecurityPolicy::CheckHeaderType::kCheckEnforce)
? BlinkSubresourceRedirectIneligibility::
kContentSecurityPolicyImgSrcRestricted
: BlinkSubresourceRedirectIneligibility::
kContentSecurityPolicyDefaultSrcRestricted);
return false;
}
// Allow subresource redirect only when cross-origin attribute is not set,
// which indicates CORS validation is not triggered for the image.
if (GetCrossOriginAttributeValue(image_element->FastGetAttribute(
html_names::kCrossoriginAttr)) != kCrossOriginAttributeNotSet) {
RecordSubresourceRedirectIneligibility(
BlinkSubresourceRedirectIneligibility::kCrossOriginAttributeSet);
return false;
}
return true;
}
} // namespace blink
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_SUBRESOURCE_REDIRECT_UTIL_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_SUBRESOURCE_REDIRECT_UTIL_H_
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
namespace blink {
// Enumerates the different ineligibility reasons for why a subresource
// redirection was disabled in blink. This is recorded in metrics and should not
// be reordered or removed. Should be in sync with the same name in enums.xml
enum class BlinkSubresourceRedirectIneligibility {
// Created by javascript and is same-origin with the document.
kJavascriptCreatedSameOrigin = 0,
// Created by javascript and is cross-origin with the document.
kJavascriptCreatedCrossOrigin = 1,
// Restricted by Content-Security-Policy default-src directive.
kContentSecurityPolicyDefaultSrcRestricted = 2,
// Restricted by Content-Security-Policy img-src directive.
kContentSecurityPolicyImgSrcRestricted = 3,
// Crossorigin attribute was set which indicates CORS validation will happen
// for the subresource.
kCrossOriginAttributeSet = 4,
// New enum entries should be added here.
kMaxValue = kCrossOriginAttributeSet
};
// Returns whether subresource redirect can be attempted for fetching the image
// with |url|. Redirect to other origins could be disabled due to CSP or CORS
// restrictions.
bool ShouldEnableSubresourceRedirect(HTMLImageElement* image_element,
const KURL& url);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LOADER_SUBRESOURCE_REDIRECT_UTIL_H_
...@@ -6943,6 +6943,16 @@ Called by update_bad_message_reasons.py.--> ...@@ -6943,6 +6943,16 @@ Called by update_bad_message_reasons.py.-->
<int value="5" label="Blacklist disabled."/> <int value="5" label="Blacklist disabled."/>
</enum> </enum>
<enum name="BlinkSubresourceRedirectIneligibility">
<int value="0" label="Javascript created, same-origin resource"/>
<int value="1" label="Javascript created, cross-origin resource"/>
<int value="2"
label="Restricted by Content-Security-Policy default-src directive"/>
<int value="3"
label="Restricted by Content-Security-Policy img-src directive"/>
<int value="4" label="Crossorigin attribute was set"/>
</enum>
<enum name="BloatedRendererHandlingInBrowser"> <enum name="BloatedRendererHandlingInBrowser">
<int value="0" label="Reloaded the bloated tab"/> <int value="0" label="Reloaded the bloated tab"/>
<int value="1" label="Cannot reload the bloated tab"/> <int value="1" label="Cannot reload the bloated tab"/>
...@@ -646,6 +646,16 @@ reviews. Googlers can read more about this at go/gwsq-gerrit. ...@@ -646,6 +646,16 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary> </summary>
</histogram> </histogram>
<histogram name="SubresourceRedirect.Blink.Ineligibility"
enum="BlinkSubresourceRedirectIneligibility" expires_after="M92">
<owner>rajendrant@chromium.org</owner>
<owner>mcrouse@chromium.org</owner>
<summary>
Records the different reasons subresource redirect was disabled by Blink.
Recorded for each subresource that was disabled by Blink.
</summary>
</histogram>
<histogram name="SubresourceRedirect.BypassDuration" units="ms" <histogram name="SubresourceRedirect.BypassDuration" units="ms"
expires_after="M92"> expires_after="M92">
<owner>rajendrant@chromium.org</owner> <owner>rajendrant@chromium.org</owner>
...@@ -812,7 +822,7 @@ reviews. Googlers can read more about this at go/gwsq-gerrit. ...@@ -812,7 +822,7 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</histogram> </histogram>
<histogram name="SubresourceRedirect.RobotsRulesFetcher.ResponseCode" <histogram name="SubresourceRedirect.RobotsRulesFetcher.ResponseCode"
units="ms" expires_after="M92"> units="HttpResponseCode" expires_after="M92">
<owner>rajendrant@chromium.org</owner> <owner>rajendrant@chromium.org</owner>
<owner>mcrouse@chromium.org</owner> <owner>mcrouse@chromium.org</owner>
<summary> <summary>
......
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