| // Copyright 2015 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/html/parser/html_preload_scanner.h" |
| |
| #include <memory> |
| #include "base/strings/stringprintf.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/platform/web_client_hints_type.h" |
| #include "third_party/blink/public/platform/web_runtime_features.h" |
| #include "third_party/blink/public/platform/web_url_loader_mock_factory.h" |
| #include "third_party/blink/renderer/core/css/media_values_cached.h" |
| #include "third_party/blink/renderer/core/frame/local_dom_window.h" |
| #include "third_party/blink/renderer/core/frame/settings.h" |
| #include "third_party/blink/renderer/core/html/cross_origin_attribute.h" |
| #include "third_party/blink/renderer/core/html/parser/html_parser_options.h" |
| #include "third_party/blink/renderer/core/html/parser/html_resource_preloader.h" |
| #include "third_party/blink/renderer/core/html/parser/preload_request.h" |
| #include "third_party/blink/renderer/core/media_type_names.h" |
| #include "third_party/blink/renderer/core/testing/page_test_base.h" |
| #include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/client_hints_preferences.h" |
| #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" |
| #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" |
| #include "third_party/blink/renderer/platform/weborigin/security_origin.h" |
| |
| namespace blink { |
| |
| struct PreloadScannerTestCase { |
| const char* base_url; |
| const char* input_html; |
| const char* preloaded_url; // Or nullptr if no preload is expected. |
| const char* output_base_url; |
| ResourceType type; |
| int resource_width; |
| ClientHintsPreferences preferences; |
| }; |
| |
| struct HTMLPreconnectTestCase { |
| const char* base_url; |
| const char* input_html; |
| const char* preconnected_host; |
| CrossOriginAttributeValue cross_origin; |
| }; |
| |
| struct ReferrerPolicyTestCase { |
| const char* base_url; |
| const char* input_html; |
| const char* preloaded_url; // Or nullptr if no preload is expected. |
| const char* output_base_url; |
| ResourceType type; |
| int resource_width; |
| network::mojom::ReferrerPolicy referrer_policy; |
| // Expected referrer header of the preload request, or nullptr if the header |
| // shouldn't be checked (and no network request should be created). |
| const char* expected_referrer; |
| }; |
| |
| struct CorsTestCase { |
| const char* base_url; |
| const char* input_html; |
| network::mojom::RequestMode request_mode; |
| network::mojom::CredentialsMode credentials_mode; |
| }; |
| |
| struct CSPTestCase { |
| const char* base_url; |
| const char* input_html; |
| bool should_see_csp_tag; |
| }; |
| |
| struct NonceTestCase { |
| const char* base_url; |
| const char* input_html; |
| const char* nonce; |
| }; |
| |
| struct ContextTestCase { |
| const char* base_url; |
| const char* input_html; |
| const char* preloaded_url; // Or nullptr if no preload is expected. |
| bool is_image_set; |
| }; |
| |
| struct IntegrityTestCase { |
| size_t number_of_integrity_metadata_found; |
| const char* input_html; |
| }; |
| |
| struct LazyLoadImageTestCase { |
| const char* input_html; |
| bool lazy_load_image_enabled; |
| }; |
| |
| class HTMLMockHTMLResourcePreloader : public ResourcePreloader { |
| public: |
| void PreloadRequestVerification(ResourceType type, |
| const char* url, |
| const char* base_url, |
| int width, |
| const ClientHintsPreferences& preferences) { |
| if (!url) { |
| EXPECT_FALSE(preload_request_) << preload_request_->ResourceURL(); |
| return; |
| } |
| EXPECT_NE(nullptr, preload_request_.get()); |
| if (preload_request_) { |
| EXPECT_FALSE(preload_request_->IsPreconnect()); |
| EXPECT_EQ(type, preload_request_->GetResourceType()); |
| EXPECT_EQ(url, preload_request_->ResourceURL()); |
| EXPECT_EQ(base_url, preload_request_->BaseURL().GetString()); |
| EXPECT_EQ(width, preload_request_->ResourceWidth()); |
| EXPECT_EQ( |
| preferences.ShouldSend(network::mojom::WebClientHintsType::kDpr), |
| preload_request_->Preferences().ShouldSend( |
| network::mojom::WebClientHintsType::kDpr)); |
| EXPECT_EQ(preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth), |
| preload_request_->Preferences().ShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth)); |
| EXPECT_EQ(preferences.ShouldSend( |
| network::mojom::WebClientHintsType::kViewportWidth), |
| preload_request_->Preferences().ShouldSend( |
| network::mojom::WebClientHintsType::kViewportWidth)); |
| } |
| } |
| |
| void PreloadRequestVerification( |
| ResourceType type, |
| const char* url, |
| const char* base_url, |
| int width, |
| network::mojom::ReferrerPolicy referrer_policy) { |
| PreloadRequestVerification(type, url, base_url, width, |
| ClientHintsPreferences()); |
| EXPECT_EQ(referrer_policy, preload_request_->GetReferrerPolicy()); |
| } |
| |
| void PreloadRequestVerification( |
| ResourceType type, |
| const char* url, |
| const char* base_url, |
| int width, |
| network::mojom::ReferrerPolicy referrer_policy, |
| Document* document, |
| const char* expected_referrer) { |
| PreloadRequestVerification(type, url, base_url, width, referrer_policy); |
| Resource* resource = preload_request_->Start(document); |
| ASSERT_TRUE(resource); |
| EXPECT_EQ(expected_referrer, |
| resource->GetResourceRequest().ReferrerString()); |
| } |
| |
| void PreconnectRequestVerification(const String& host, |
| CrossOriginAttributeValue cross_origin) { |
| if (!host.IsNull()) { |
| EXPECT_TRUE(preload_request_->IsPreconnect()); |
| EXPECT_EQ(preload_request_->ResourceURL(), host); |
| EXPECT_EQ(preload_request_->CrossOrigin(), cross_origin); |
| } |
| } |
| |
| void CorsRequestVerification( |
| Document* document, |
| network::mojom::RequestMode request_mode, |
| network::mojom::CredentialsMode credentials_mode) { |
| ASSERT_TRUE(preload_request_.get()); |
| Resource* resource = preload_request_->Start(document); |
| ASSERT_TRUE(resource); |
| EXPECT_EQ(request_mode, resource->GetResourceRequest().GetMode()); |
| EXPECT_EQ(credentials_mode, |
| resource->GetResourceRequest().GetCredentialsMode()); |
| } |
| |
| void NonceRequestVerification(const char* nonce) { |
| ASSERT_TRUE(preload_request_.get()); |
| if (strlen(nonce)) |
| EXPECT_EQ(nonce, preload_request_->Nonce()); |
| else |
| EXPECT_TRUE(preload_request_->Nonce().IsEmpty()); |
| } |
| |
| void ContextVerification(bool is_image_set) { |
| ASSERT_TRUE(preload_request_.get()); |
| EXPECT_EQ(preload_request_->IsImageSetForTestingOnly(), is_image_set); |
| } |
| |
| void CheckNumberOfIntegrityConstraints(size_t expected) { |
| size_t actual = 0; |
| if (preload_request_) { |
| actual = preload_request_->IntegrityMetadataForTestingOnly().size(); |
| EXPECT_EQ(expected, actual); |
| } |
| } |
| |
| void LazyLoadImageEnabledVerification(bool expected_enabled) { |
| if (expected_enabled) { |
| EXPECT_FALSE(preload_request_) << preload_request_->ResourceURL(); |
| } else { |
| ASSERT_TRUE(preload_request_.get()); |
| } |
| } |
| |
| protected: |
| void Preload(std::unique_ptr<PreloadRequest> preload_request) override { |
| preload_request_ = std::move(preload_request); |
| } |
| |
| private: |
| std::unique_ptr<PreloadRequest> preload_request_; |
| }; |
| |
| class HTMLPreloadScannerTest : public PageTestBase { |
| protected: |
| enum ViewportState { |
| kViewportEnabled, |
| kViewportDisabled, |
| }; |
| |
| enum PreloadState { |
| kPreloadEnabled, |
| kPreloadDisabled, |
| }; |
| |
| MediaValuesCached::MediaValuesCachedData CreateMediaValuesData() { |
| MediaValuesCached::MediaValuesCachedData data; |
| data.viewport_width = 500; |
| data.viewport_height = 600; |
| data.device_width = 700; |
| data.device_height = 800; |
| data.device_pixel_ratio = 2.0; |
| data.color_bits_per_component = 24; |
| data.monochrome_bits_per_component = 0; |
| data.primary_pointer_type = mojom::blink::PointerType::kPointerFineType; |
| data.default_font_size = 16; |
| data.three_d_enabled = true; |
| data.media_type = media_type_names::kScreen; |
| data.strict_mode = true; |
| data.display_mode = blink::mojom::DisplayMode::kBrowser; |
| return data; |
| } |
| |
| void RunSetUp(ViewportState viewport_state, |
| PreloadState preload_state = kPreloadEnabled, |
| network::mojom::ReferrerPolicy document_referrer_policy = |
| network::mojom::ReferrerPolicy::kDefault, |
| bool use_secure_document_url = false) { |
| HTMLParserOptions options(&GetDocument()); |
| KURL document_url = KURL("http://whatever.test/"); |
| if (use_secure_document_url) |
| document_url = KURL("https://whatever.test/"); |
| NavigateTo(document_url); |
| GetDocument().GetSettings()->SetViewportEnabled(viewport_state == |
| kViewportEnabled); |
| GetDocument().GetSettings()->SetViewportMetaEnabled(viewport_state == |
| kViewportEnabled); |
| GetDocument().GetSettings()->SetDoHtmlPreloadScanning(preload_state == |
| kPreloadEnabled); |
| GetFrame().DomWindow()->SetReferrerPolicy(document_referrer_policy); |
| scanner_ = std::make_unique<HTMLPreloadScanner>( |
| options, document_url, |
| std::make_unique<CachedDocumentParameters>(&GetDocument()), |
| CreateMediaValuesData(), |
| TokenPreloadScanner::ScannerType::kMainDocument); |
| } |
| |
| void SetUp() override { |
| PageTestBase::SetUp(IntSize()); |
| RunSetUp(kViewportEnabled); |
| } |
| |
| void Test(PreloadScannerTestCase test_case) { |
| SCOPED_TRACE(test_case.input_html); |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url(test_case.base_url); |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| PreloadRequestStream requests = |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| preloader.TakeAndPreload(requests); |
| |
| preloader.PreloadRequestVerification( |
| test_case.type, test_case.preloaded_url, test_case.output_base_url, |
| test_case.resource_width, test_case.preferences); |
| } |
| |
| void Test(HTMLPreconnectTestCase test_case) { |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url(test_case.base_url); |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| PreloadRequestStream requests = |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| preloader.TakeAndPreload(requests); |
| preloader.PreconnectRequestVerification(test_case.preconnected_host, |
| test_case.cross_origin); |
| } |
| |
| void Test(ReferrerPolicyTestCase test_case) { |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url(test_case.base_url); |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| PreloadRequestStream requests = |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| preloader.TakeAndPreload(requests); |
| |
| if (test_case.expected_referrer) { |
| preloader.PreloadRequestVerification( |
| test_case.type, test_case.preloaded_url, test_case.output_base_url, |
| test_case.resource_width, test_case.referrer_policy, &GetDocument(), |
| test_case.expected_referrer); |
| } else { |
| preloader.PreloadRequestVerification( |
| test_case.type, test_case.preloaded_url, test_case.output_base_url, |
| test_case.resource_width, test_case.referrer_policy); |
| } |
| } |
| |
| void Test(CorsTestCase test_case) { |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url(test_case.base_url); |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| PreloadRequestStream requests = |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| preloader.TakeAndPreload(requests); |
| preloader.CorsRequestVerification(&GetDocument(), test_case.request_mode, |
| test_case.credentials_mode); |
| } |
| |
| void Test(CSPTestCase test_case) { |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url(test_case.base_url); |
| seen_csp_meta_tag_ = false; |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| EXPECT_EQ(test_case.should_see_csp_tag, seen_csp_meta_tag_); |
| } |
| |
| void Test(NonceTestCase test_case) { |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url(test_case.base_url); |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| PreloadRequestStream requests = |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| preloader.TakeAndPreload(requests); |
| preloader.NonceRequestVerification(test_case.nonce); |
| } |
| |
| void Test(ContextTestCase test_case) { |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url(test_case.base_url); |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| PreloadRequestStream requests = |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| preloader.TakeAndPreload(requests); |
| |
| preloader.ContextVerification(test_case.is_image_set); |
| } |
| |
| void Test(IntegrityTestCase test_case) { |
| SCOPED_TRACE(test_case.input_html); |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url("http://example.test/"); |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| PreloadRequestStream requests = |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| preloader.TakeAndPreload(requests); |
| |
| preloader.CheckNumberOfIntegrityConstraints( |
| test_case.number_of_integrity_metadata_found); |
| } |
| |
| void Test(LazyLoadImageTestCase test_case) { |
| SCOPED_TRACE(test_case.input_html); |
| HTMLMockHTMLResourcePreloader preloader; |
| KURL base_url("http://example.test/"); |
| scanner_->AppendToEnd(String(test_case.input_html)); |
| PreloadRequestStream requests = |
| scanner_->Scan(base_url, nullptr, seen_csp_meta_tag_); |
| preloader.TakeAndPreload(requests); |
| preloader.LazyLoadImageEnabledVerification( |
| test_case.lazy_load_image_enabled); |
| } |
| |
| private: |
| std::unique_ptr<HTMLPreloadScanner> scanner_; |
| bool seen_csp_meta_tag_ = false; |
| }; |
| |
| TEST_F(HTMLPreloadScannerTest, testImages) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", "<img src='bla.gif'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<img srcset='bla.gif 320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<img sizes='50vw' src='bla.gif'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 1x'>", "bla2.gif", |
| "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 0.5x'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 100w'>", "bla2.gif", |
| "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 100w, bla3.gif 250w'>", |
| "bla3.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 100w, bla3.gif 250w, " |
| "bla4.gif 500w'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img src='bla.gif' srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif " |
| "500w' sizes='50vw'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img src='bla.gif' sizes='50vw' srcset='bla2.gif 100w, bla3.gif 250w, " |
| "bla4.gif 500w'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif 500w' " |
| "src='bla.gif'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif 500w' " |
| "src='bla.gif' sizes='50vw'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif 500w' sizes='50vw' " |
| "src='bla.gif'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img src='bla.gif' srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif " |
| "500w'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 0}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testImagesWithViewport) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<meta name=viewport content='width=160'><img srcset='bla.gif 320w, " |
| "blabla.gif 640w'>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<img src='bla.gif'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<img sizes='50vw' src='bla.gif'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 1x'>", "bla2.gif", |
| "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 0.5x'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 160w'>", "bla2.gif", |
| "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 160w, bla3.gif 250w'>", |
| "bla2.gif", "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 160w, bla3.gif 250w, " |
| "bla4.gif 500w'>", |
| "bla2.gif", "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img src='bla.gif' srcset='bla2.gif 160w, bla3.gif 250w, bla4.gif " |
| "500w' sizes='50vw'>", |
| "bla2.gif", "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img src='bla.gif' sizes='50vw' srcset='bla2.gif 160w, bla3.gif 250w, " |
| "bla4.gif 500w'>", |
| "bla2.gif", "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img sizes='50vw' srcset='bla2.gif 160w, bla3.gif 250w, bla4.gif 500w' " |
| "src='bla.gif'>", |
| "bla2.gif", "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img srcset='bla2.gif 160w, bla3.gif 250w, bla4.gif 500w' " |
| "src='bla.gif' sizes='50vw'>", |
| "bla2.gif", "http://example.test/", ResourceType::kImage, 80}, |
| {"http://example.test", |
| "<img srcset='bla2.gif 160w, bla3.gif 250w, bla4.gif 500w' sizes='50vw' " |
| "src='bla.gif'>", |
| "bla2.gif", "http://example.test/", ResourceType::kImage, 80}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testImagesWithViewportDeviceWidth) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<meta name=viewport content='width=device-width'><img srcset='bla.gif " |
| "320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<img src='bla.gif'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<img sizes='50vw' src='bla.gif'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 1x'>", "bla2.gif", |
| "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 0.5x'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 160w'>", "bla2.gif", |
| "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 160w, bla3.gif 250w'>", |
| "bla3.gif", "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 160w, bla3.gif 250w, " |
| "bla4.gif 500w'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img src='bla.gif' srcset='bla2.gif 160w, bla3.gif 250w, bla4.gif " |
| "500w' sizes='50vw'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img src='bla.gif' sizes='50vw' srcset='bla2.gif 160w, bla3.gif 250w, " |
| "bla4.gif 500w'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img sizes='50vw' srcset='bla2.gif 160w, bla3.gif 250w, bla4.gif 500w' " |
| "src='bla.gif'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img srcset='bla2.gif 160w, bla3.gif 250w, bla4.gif 500w' " |
| "src='bla.gif' sizes='50vw'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 350}, |
| {"http://example.test", |
| "<img srcset='bla2.gif 160w, bla3.gif 250w, bla4.gif 500w' sizes='50vw' " |
| "src='bla.gif'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 350}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testImagesWithViewportDisabled) { |
| RunSetUp(kViewportDisabled); |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<meta name=viewport content='width=160'><img src='bla.gif'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<img srcset='bla.gif 320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<img sizes='50vw' src='bla.gif'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 1x'>", "bla2.gif", |
| "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 0.5x'>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 100w'>", "bla2.gif", |
| "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 100w, bla3.gif 250w'>", |
| "bla3.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' src='bla.gif' srcset='bla2.gif 100w, bla3.gif 250w, " |
| "bla4.gif 500w'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img src='bla.gif' srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif " |
| "500w' sizes='50vw'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img src='bla.gif' sizes='50vw' srcset='bla2.gif 100w, bla3.gif 250w, " |
| "bla4.gif 500w'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img sizes='50vw' srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif 500w' " |
| "src='bla.gif'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif 500w' " |
| "src='bla.gif' sizes='50vw'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<img srcset='bla2.gif 100w, bla3.gif 250w, bla4.gif 500w' sizes='50vw' " |
| "src='bla.gif'>", |
| "bla4.gif", "http://example.test/", ResourceType::kImage, 250}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testViewportNoContent) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<meta name=viewport><img srcset='bla.gif 320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<meta name=viewport content=sdkbsdkjnejjha><img srcset='bla.gif 320w, " |
| "blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testMetaAcceptCH) { |
| ClientHintsPreferences dpr; |
| ClientHintsPreferences resource_width; |
| ClientHintsPreferences all; |
| ClientHintsPreferences viewport_width; |
| dpr.SetShouldSend(network::mojom::WebClientHintsType::kDpr); |
| all.SetShouldSend(network::mojom::WebClientHintsType::kDpr); |
| resource_width.SetShouldSend( |
| network::mojom::WebClientHintsType::kResourceWidth); |
| all.SetShouldSend(network::mojom::WebClientHintsType::kResourceWidth); |
| viewport_width.SetShouldSend( |
| network::mojom::WebClientHintsType::kViewportWidth); |
| all.SetShouldSend(network::mojom::WebClientHintsType::kViewportWidth); |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content='bla'><img srcset='bla.gif 320w, " |
| "blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content='dprw'><img srcset='bla.gif 320w, " |
| "blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch'><img srcset='bla.gif 320w, blabla.gif " |
| "640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content='dpr '><img srcset='bla.gif " |
| "320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0, dpr}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content='bla,dpr '><img srcset='bla.gif " |
| "320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0, dpr}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content=' width '><img sizes='100vw' " |
| "srcset='bla.gif 320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 500, |
| resource_width}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content=' width , wutever'><img " |
| "sizes='300px' srcset='bla.gif 320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 300, |
| resource_width}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content=' viewport-width '><img " |
| "srcset='bla.gif 320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0, |
| viewport_width}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content=' viewport-width , " |
| "wutever'><img srcset='bla.gif 320w, blabla.gif 640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 0, |
| viewport_width}, |
| {"http://example.test", |
| "<meta http-equiv='accept-ch' content=' viewport-width ,width, " |
| "wutever, dpr '><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " |
| "640w'>", |
| "blabla.gif", "http://example.test/", ResourceType::kImage, 450, all}, |
| }; |
| |
| for (const auto& test_case : test_cases) { |
| RunSetUp(kViewportDisabled, kPreloadEnabled, |
| network::mojom::ReferrerPolicy::kDefault, |
| true /* use_secure_document_url */); |
| Test(test_case); |
| } |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testMetaAcceptCHInsecureDocument) { |
| ClientHintsPreferences all; |
| all.SetShouldSend(network::mojom::WebClientHintsType::kDpr); |
| all.SetShouldSend(network::mojom::WebClientHintsType::kResourceWidth); |
| all.SetShouldSend(network::mojom::WebClientHintsType::kViewportWidth); |
| |
| const PreloadScannerTestCase expect_no_client_hint = { |
| "http://example.test", |
| "<meta http-equiv='accept-ch' content=' viewport-width ,width, " |
| "wutever, dpr '><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " |
| "640w'>", |
| "blabla.gif", |
| "http://example.test/", |
| ResourceType::kImage, |
| 450}; |
| |
| const PreloadScannerTestCase expect_client_hint = { |
| "http://example.test", |
| "<meta http-equiv='accept-ch' content=' viewport-width ,width, " |
| "wutever, dpr '><img sizes='90vw' srcset='bla.gif 320w, blabla.gif " |
| "640w'>", |
| "blabla.gif", |
| "http://example.test/", |
| ResourceType::kImage, |
| 450, |
| all}; |
| |
| // For an insecure document, client hint should not be attached. |
| RunSetUp(kViewportDisabled, kPreloadEnabled, |
| network::mojom::ReferrerPolicy::kDefault, |
| false /* use_secure_document_url */); |
| Test(expect_no_client_hint); |
| |
| // For a secure document, client hint should be attached. |
| RunSetUp(kViewportDisabled, kPreloadEnabled, |
| network::mojom::ReferrerPolicy::kDefault, |
| true /* use_secure_document_url */); |
| Test(expect_client_hint); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testPreconnect) { |
| HTMLPreconnectTestCase test_cases[] = { |
| {"http://example.test", "<link rel=preconnect href=http://example2.test>", |
| "http://example2.test", kCrossOriginAttributeNotSet}, |
| {"http://example.test", |
| "<link rel=preconnect href=http://example2.test crossorigin=anonymous>", |
| "http://example2.test", kCrossOriginAttributeAnonymous}, |
| {"http://example.test", |
| "<link rel=preconnect href=http://example2.test " |
| "crossorigin='use-credentials'>", |
| "http://example2.test", kCrossOriginAttributeUseCredentials}, |
| {"http://example.test", |
| "<link rel=preconnected href=http://example2.test " |
| "crossorigin='use-credentials'>", |
| nullptr, kCrossOriginAttributeNotSet}, |
| {"http://example.test", |
| "<link rel=preconnect href=ws://example2.test " |
| "crossorigin='use-credentials'>", |
| nullptr, kCrossOriginAttributeNotSet}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testDisables) { |
| RunSetUp(kViewportEnabled, kPreloadDisabled); |
| |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", "<img src='bla.gif'>"}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testPicture) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<picture><source srcset='srcset_bla.gif'><img src='bla.gif'></picture>", |
| "srcset_bla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<picture><source srcset='srcset_bla.gif' type=''><img " |
| "src='bla.gif'></picture>", |
| "srcset_bla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<picture><source sizes='50vw' srcset='srcset_bla.gif'><img " |
| "src='bla.gif'></picture>", |
| "srcset_bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<picture><source sizes='50vw' srcset='srcset_bla.gif'><img " |
| "sizes='50vw' src='bla.gif'></picture>", |
| "srcset_bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<picture><source srcset='srcset_bla.gif' sizes='50vw'><img " |
| "sizes='50vw' src='bla.gif'></picture>", |
| "srcset_bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<picture><source srcset='srcset_bla.gif'><img sizes='50vw' " |
| "src='bla.gif'></picture>", |
| "srcset_bla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<picture><source media='(max-width: 900px)' " |
| "srcset='srcset_bla.gif'><img sizes='50vw' srcset='bla.gif " |
| "500w'></picture>", |
| "srcset_bla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<picture><source media='(max-width: 400px)' " |
| "srcset='srcset_bla.gif'><img sizes='50vw' srcset='bla.gif " |
| "500w'></picture>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<picture><source type='image/webp' srcset='srcset_bla.gif'><img " |
| "sizes='50vw' srcset='bla.gif 500w'></picture>", |
| "srcset_bla.gif", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<picture><source type='image/jp2' srcset='srcset_bla.gif'><img " |
| "sizes='50vw' srcset='bla.gif 500w'></picture>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<picture><source media='(max-width: 900px)' type='image/jp2' " |
| "srcset='srcset_bla.gif'><img sizes='50vw' srcset='bla.gif " |
| "500w'></picture>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<picture><source type='image/webp' media='(max-width: 400px)' " |
| "srcset='srcset_bla.gif'><img sizes='50vw' srcset='bla.gif " |
| "500w'></picture>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<picture><source type='image/jp2' media='(max-width: 900px)' " |
| "srcset='srcset_bla.gif'><img sizes='50vw' srcset='bla.gif " |
| "500w'></picture>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| {"http://example.test", |
| "<picture><source media='(max-width: 400px)' type='image/webp' " |
| "srcset='srcset_bla.gif'><img sizes='50vw' srcset='bla.gif " |
| "500w'></picture>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 250}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testContext) { |
| ContextTestCase test_cases[] = { |
| {"http://example.test", |
| "<picture><source srcset='srcset_bla.gif'><img src='bla.gif'></picture>", |
| "srcset_bla.gif", true}, |
| {"http://example.test", "<img src='bla.gif'>", "bla.gif", false}, |
| {"http://example.test", "<img srcset='bla.gif'>", "bla.gif", true}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testReferrerPolicy) { |
| ReferrerPolicyTestCase test_cases[] = { |
| {"http://example.test", "<img src='bla.gif'/>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kDefault}, |
| {"http://example.test", "<img referrerpolicy='origin' src='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kOrigin, nullptr}, |
| {"http://example.test", |
| "<meta name='referrer' content='not-a-valid-policy'><img " |
| "src='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kDefault, nullptr}, |
| {"http://example.test", |
| "<img referrerpolicy='origin' referrerpolicy='origin-when-cross-origin' " |
| "src='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kOrigin, nullptr}, |
| {"http://example.test", |
| "<img referrerpolicy='not-a-valid-policy' src='bla.gif'/>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kDefault, nullptr}, |
| {"http://example.test", |
| "<link rel=preload as=image referrerpolicy='origin-when-cross-origin' " |
| "href='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kOriginWhenCrossOrigin, nullptr}, |
| {"http://example.test", |
| "<link rel=preload as=image referrerpolicy='same-origin' " |
| "href='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kSameOrigin, nullptr}, |
| {"http://example.test", |
| "<link rel=preload as=image referrerpolicy='strict-origin' " |
| "href='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kStrictOrigin, nullptr}, |
| {"http://example.test", |
| "<link rel=preload as=image " |
| "referrerpolicy='strict-origin-when-cross-origin' " |
| "href='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kStrictOriginWhenCrossOrigin, nullptr}, |
| {"http://example.test", |
| "<link rel='stylesheet' href='sheet.css' type='text/css'>", "sheet.css", |
| "http://example.test/", ResourceType::kCSSStyleSheet, 0, |
| network::mojom::ReferrerPolicy::kDefault, nullptr}, |
| {"http://example.test", |
| "<link rel=preload as=image referrerpolicy='origin' " |
| "referrerpolicy='origin-when-cross-origin' href='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kOrigin, nullptr}, |
| {"http://example.test", |
| "<meta name='referrer' content='no-referrer'><img " |
| "referrerpolicy='origin' src='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kOrigin, nullptr}, |
| // The scanner's state is not reset between test cases, so all subsequent |
| // test cases have a document referrer policy of no-referrer. |
| {"http://example.test", |
| "<link rel=preload as=image referrerpolicy='not-a-valid-policy' " |
| "href='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kNever, nullptr}, |
| {"http://example.test", |
| "<img referrerpolicy='not-a-valid-policy' src='bla.gif'/>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kNever, nullptr}, |
| {"http://example.test", "<img src='bla.gif'/>", "bla.gif", |
| "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kNever, nullptr}}; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testCors) { |
| CorsTestCase test_cases[] = { |
| {"http://example.test", "<script src='/script'></script>", |
| network::mojom::RequestMode::kNoCors, |
| network::mojom::CredentialsMode::kInclude}, |
| {"http://example.test", "<script crossorigin src='/script'></script>", |
| network::mojom::RequestMode::kCors, |
| network::mojom::CredentialsMode::kSameOrigin}, |
| {"http://example.test", |
| "<script crossorigin=use-credentials src='/script'></script>", |
| network::mojom::RequestMode::kCors, |
| network::mojom::CredentialsMode::kInclude}, |
| {"http://example.test", "<script type='module' src='/script'></script>", |
| network::mojom::RequestMode::kCors, |
| network::mojom::CredentialsMode::kSameOrigin}, |
| {"http://example.test", |
| "<script type='module' crossorigin='anonymous' src='/script'></script>", |
| network::mojom::RequestMode::kCors, |
| network::mojom::CredentialsMode::kSameOrigin}, |
| {"http://example.test", |
| "<script type='module' crossorigin='use-credentials' " |
| "src='/script'></script>", |
| network::mojom::RequestMode::kCors, |
| network::mojom::CredentialsMode::kInclude}, |
| }; |
| |
| for (const auto& test_case : test_cases) { |
| SCOPED_TRACE(test_case.input_html); |
| Test(test_case); |
| } |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testCSP) { |
| CSPTestCase test_cases[] = { |
| {"http://example.test", |
| "<meta http-equiv=\"Content-Security-Policy\" content=\"default-src " |
| "https:\">", |
| true}, |
| {"http://example.test", |
| "<meta name=\"viewport\" content=\"width=device-width\">", false}, |
| {"http://example.test", "<img src=\"example.gif\">", false}}; |
| |
| for (const auto& test_case : test_cases) { |
| SCOPED_TRACE(test_case.input_html); |
| Test(test_case); |
| } |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testNonce) { |
| NonceTestCase test_cases[] = { |
| {"http://example.test", "<script src='/script'></script>", ""}, |
| {"http://example.test", "<script src='/script' nonce=''></script>", ""}, |
| {"http://example.test", "<script src='/script' nonce='abc'></script>", |
| "abc"}, |
| {"http://example.test", "<link rel='import' href='/import'>", ""}, |
| {"http://example.test", "<link rel='import' href='/import' nonce=''>", |
| ""}, |
| {"http://example.test", "<link rel='import' href='/import' nonce='abc'>", |
| "abc"}, |
| {"http://example.test", "<link rel='stylesheet' href='/style'>", ""}, |
| {"http://example.test", "<link rel='stylesheet' href='/style' nonce=''>", |
| ""}, |
| {"http://example.test", |
| "<link rel='stylesheet' href='/style' nonce='abc'>", "abc"}, |
| |
| // <img> doesn't support nonces: |
| {"http://example.test", "<img src='/image'>", ""}, |
| {"http://example.test", "<img src='/image' nonce=''>", ""}, |
| {"http://example.test", "<img src='/image' nonce='abc'>", ""}, |
| }; |
| |
| for (const auto& test_case : test_cases) { |
| SCOPED_TRACE(test_case.input_html); |
| Test(test_case); |
| } |
| } |
| |
| // Tests that a document-level referrer policy (e.g. one set by HTTP header) is |
| // applied for preload requests. |
| TEST_F(HTMLPreloadScannerTest, testReferrerPolicyOnDocument) { |
| RunSetUp(kViewportEnabled, kPreloadEnabled, |
| network::mojom::ReferrerPolicy::kOrigin); |
| ReferrerPolicyTestCase test_cases[] = { |
| {"http://example.test", "<img src='blah.gif'/>", "blah.gif", |
| "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kOrigin, nullptr}, |
| {"http://example.test", "<style>@import url('blah.css');</style>", |
| "blah.css", "http://example.test/", ResourceType::kCSSStyleSheet, 0, |
| network::mojom::ReferrerPolicy::kOrigin, nullptr}, |
| // Tests that a meta-delivered referrer policy with an unrecognized policy |
| // value does not override the document's referrer policy. |
| {"http://example.test", |
| "<meta name='referrer' content='not-a-valid-policy'><img " |
| "src='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kOrigin, nullptr}, |
| // Tests that a meta-delivered referrer policy with a valid policy value |
| // does override the document's referrer policy. |
| {"http://example.test", |
| "<meta name='referrer' content='unsafe-url'><img src='bla.gif'/>", |
| "bla.gif", "http://example.test/", ResourceType::kImage, 0, |
| network::mojom::ReferrerPolicy::kAlways, nullptr}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testLinkRelPreload) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", "<link rel=preload as=fetch href=bla>", "bla", |
| "http://example.test/", ResourceType::kRaw, 0}, |
| {"http://example.test", "<link rel=preload href=bla as=script>", "bla", |
| "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=script type='script/foo'>", "bla", |
| "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", "<link rel=preload href=bla as=style>", "bla", |
| "http://example.test/", ResourceType::kCSSStyleSheet, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=style type='text/css'>", "bla", |
| "http://example.test/", ResourceType::kCSSStyleSheet, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=style type='text/bla'>", nullptr, |
| "http://example.test/", ResourceType::kCSSStyleSheet, 0}, |
| {"http://example.test", "<link rel=preload href=bla as=image>", "bla", |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=image type='image/webp'>", "bla", |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=image type='image/bla'>", nullptr, |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<link rel=preload href=bla as=font>", "bla", |
| "http://example.test/", ResourceType::kFont, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=font type='font/woff2'>", "bla", |
| "http://example.test/", ResourceType::kFont, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=font type='font/bla'>", nullptr, |
| "http://example.test/", ResourceType::kFont, 0}, |
| // Until the preload cache is defined in terms of range requests and media |
| // fetches we can't reliably preload audio/video content and expect it to |
| // be served from the cache correctly. Until |
| // https://github.com/w3c/preload/issues/97 is resolved and implemented we |
| // need to disable these preloads. |
| {"http://example.test", "<link rel=preload href=bla as=video>", nullptr, |
| "http://example.test/", ResourceType::kVideo, 0}, |
| {"http://example.test", "<link rel=preload href=bla as=track>", "bla", |
| "http://example.test/", ResourceType::kTextTrack, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=image media=\"(max-width: 800px)\">", |
| "bla", "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<link rel=preload href=bla as=image media=\"(max-width: 400px)\">", |
| nullptr, "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", "<link rel=preload href=bla>", nullptr, |
| "http://example.test/", ResourceType::kRaw, 0}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, testNoDataUrls) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<link rel=preload href='data:text/html,<p>data</data>'>", nullptr, |
| "http://example.test/", ResourceType::kRaw, 0}, |
| {"http://example.test", "<img src='data:text/html,<p>data</data>'>", |
| nullptr, "http://example.test/", ResourceType::kImage, 0}, |
| {"data:text/html,<a>anchor</a>", "<img src='#anchor'>", nullptr, |
| "http://example.test/", ResourceType::kImage, 0}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| // The preload scanner should follow the same policy that the ScriptLoader does |
| // with regard to the type and language attribute. |
| TEST_F(HTMLPreloadScannerTest, testScriptTypeAndLanguage) { |
| PreloadScannerTestCase test_cases[] = { |
| // Allow empty src and language attributes. |
| {"http://example.test", "<script src='test.js'></script>", "test.js", |
| "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", |
| "<script type='' language='' src='test.js'></script>", "test.js", |
| "http://example.test/", ResourceType::kScript, 0}, |
| // Allow standard language and type attributes. |
| {"http://example.test", |
| "<script type='text/javascript' src='test.js'></script>", "test.js", |
| "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", |
| "<script type='text/javascript' language='javascript' " |
| "src='test.js'></script>", |
| "test.js", "http://example.test/", ResourceType::kScript, 0}, |
| // Allow legacy languages in the "language" attribute with an empty |
| // type. |
| {"http://example.test", |
| "<script language='javascript1.1' src='test.js'></script>", "test.js", |
| "http://example.test/", ResourceType::kScript, 0}, |
| // Allow legacy languages in the "type" attribute. |
| {"http://example.test", |
| "<script type='javascript' src='test.js'></script>", "test.js", |
| "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", |
| "<script type='javascript1.7' src='test.js'></script>", "test.js", |
| "http://example.test/", ResourceType::kScript, 0}, |
| // Do not allow invalid types in the "type" attribute. |
| {"http://example.test", "<script type='invalid' src='test.js'></script>", |
| nullptr, "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", "<script type='asdf' src='test.js'></script>", |
| nullptr, "http://example.test/", ResourceType::kScript, 0}, |
| // Do not allow invalid languages. |
| {"http://example.test", |
| "<script language='french' src='test.js'></script>", nullptr, |
| "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", |
| "<script language='python' src='test.js'></script>", nullptr, |
| "http://example.test/", ResourceType::kScript, 0}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| // Regression test for crbug.com/664744. |
| TEST_F(HTMLPreloadScannerTest, testUppercaseAsValues) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", "<link rel=preload href=bla as=SCRIPT>", "bla", |
| "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", "<link rel=preload href=bla as=fOnT>", "bla", |
| "http://example.test/", ResourceType::kFont, 0}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, ReferrerHeader) { |
| RunSetUp(kViewportEnabled, kPreloadEnabled, |
| network::mojom::ReferrerPolicy::kAlways); |
| |
| KURL preload_url("http://example.test/sheet.css"); |
| // TODO(crbug.com/751425): We should use the mock functionality |
| // via |PageTestBase::dummy_page_holder_|. |
| url_test_helpers::RegisterMockedURLLoadWithCustomResponse( |
| preload_url, "", WrappedResourceResponse(ResourceResponse())); |
| |
| ReferrerPolicyTestCase test_case = { |
| "http://example.test", |
| "<link rel='stylesheet' href='sheet.css' type='text/css'>", |
| "sheet.css", |
| "http://example.test/", |
| ResourceType::kCSSStyleSheet, |
| 0, |
| network::mojom::ReferrerPolicy::kAlways, |
| "http://whatever.test/"}; |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, Integrity) { |
| IntegrityTestCase test_cases[] = { |
| {0, "<script src=bla.js>"}, |
| {1, |
| "<script src=bla.js " |
| "integrity=sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=>"}, |
| {0, "<script src=bla.js integrity=sha257-XXX>"}, |
| {2, |
| "<script src=bla.js " |
| "integrity=sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng= " |
| "sha256-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxng=>"}, |
| {1, |
| "<script src=bla.js " |
| "integrity=sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng= " |
| "integrity=sha257-XXXX>"}, |
| {0, |
| "<script src=bla.js integrity=sha257-XXX " |
| "integrity=sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=>"}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| // Regression test for http://crbug.com/898795 where preloads after a |
| // dynamically inserted meta csp tag are dispatched on subsequent calls to the |
| // HTMLPreloadScanner, after they had been parsed. |
| TEST_F(HTMLPreloadScannerTest, MetaCsp_NoPreloadsAfter) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<meta http-equiv='Content-Security-Policy'><link rel=preload href=bla " |
| "as=SCRIPT>", |
| nullptr, "http://example.test/", ResourceType::kScript, 0}, |
| // The buffered text referring to the preload above should be cleared, so |
| // make sure it is not preloaded on subsequent calls to Scan. |
| {"http://example.test", "", nullptr, "http://example.test/", |
| ResourceType::kScript, 0}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, LazyLoadImage_DisabledForSmallImages) { |
| ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test(true); |
| ScopedAutomaticLazyImageLoadingForTest |
| scoped_automatic_lazy_image_loading_for_test(true); |
| ScopedRestrictAutomaticLazyImageLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_image_loading_to_data_saver_for_test( |
| false); |
| RunSetUp(kViewportEnabled); |
| LazyLoadImageTestCase test_cases[] = { |
| {"<img src='foo.jpg'>", true}, |
| {"<img src='foo.jpg' height='1px' width='1px'>", false}, |
| {"<img src='foo.jpg' style='height: 1px; width: 1px'>", false}, |
| {"<img src='foo.jpg' height='10px' width='10px'>", false}, |
| {"<img src='foo.jpg' style='height: 10px; width: 10px'>", false}, |
| {"<img src='foo.jpg' height='1px'>", true}, |
| {"<img src='foo.jpg' style='height: 1px;'>", true}, |
| {"<img src='foo.jpg' width='1px'>", true}, |
| {"<img src='foo.jpg' style='width: 1px;'>", true}, |
| }; |
| |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, LazyLoadImage_FeatureDisabledWithAttribute) { |
| ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test(false); |
| RunSetUp(kViewportEnabled); |
| LazyLoadImageTestCase test_cases[] = { |
| {"<img src='foo.jpg' loading='auto'>", false}, |
| {"<img src='foo.jpg' loading='lazy'>", false}, |
| {"<img src='foo.jpg' loading='eager'>", false}, |
| }; |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, |
| LazyLoadImage_FeatureAutomaticEnabledWithAttribute) { |
| ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test(true); |
| ScopedAutomaticLazyImageLoadingForTest |
| scoped_automatic_lazy_image_loading_for_test(true); |
| ScopedRestrictAutomaticLazyImageLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_image_loading_to_data_saver_for_test( |
| false); |
| RunSetUp(kViewportEnabled); |
| LazyLoadImageTestCase test_cases[] = { |
| {"<img src='foo.jpg' loading='auto'>", true}, |
| {"<img src='foo.jpg' loading='lazy'>", true}, |
| {"<img src='foo.jpg' loading='eager'>", false}, |
| // loading=lazy should override other conditions. |
| {"<img src='foo.jpg' style='height: 1px;' loading='lazy'>", true}, |
| {"<img src='foo.jpg' style='height: 1px; width: 1px' loading='lazy'>", |
| true}, |
| }; |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, |
| LazyLoadImage_FeatureExplicitEnabledWithAttribute) { |
| ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test(true); |
| RunSetUp(kViewportEnabled); |
| LazyLoadImageTestCase test_cases[] = { |
| {"<img src='foo.jpg' loading='auto'>", false}, |
| {"<img src='foo.jpg' loading='lazy'>", true}, |
| {"<img src='foo.jpg' loading='eager'>", false}, |
| }; |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, |
| LazyLoadImage_FeatureAutomaticPreloadForLargeImages) { |
| // Large images should not be preloaded, when loading is auto or lazy. |
| ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test(true); |
| ScopedAutomaticLazyImageLoadingForTest |
| scoped_automatic_lazy_image_loading_for_test(true); |
| ScopedRestrictAutomaticLazyImageLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_image_loading_to_data_saver_for_test( |
| false); |
| RunSetUp(kViewportEnabled); |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", "<img src='foo.jpg' height='20px' width='20px'>", |
| nullptr, "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<img src='foo.jpg' style='height: 20px; width: 20px'>", nullptr, |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<img src='foo.jpg' height='20px' width='20px' loading='lazy'>", nullptr, |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<img src='foo.jpg' height='20px' width='20px' loading='auto'>", nullptr, |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<img src='foo.jpg' style='height: 20px; width: 20px' loading='lazy'>", |
| nullptr, "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<img src='foo.jpg' style='height: 20px; width: 20px' loading='auto'>", |
| nullptr, "http://example.test/", ResourceType::kImage, 0}, |
| }; |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| |
| // When loading is eager, lazyload is disabled and preload happens. |
| LazyLoadImageTestCase test_cases_that_preload[] = { |
| {"<img src='foo.jpg' height='20px' width='20px' loading='eager'>", false}, |
| {"<img src='foo.jpg' style='height: 20px; width: 20px' loading='eager'>", |
| false}, |
| }; |
| for (const auto& test_case : test_cases_that_preload) |
| Test(test_case); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, |
| LazyLoadImage_FeatureExplicitPreloadForLargeImages) { |
| // Large images should not be preloaded, when loading is lazy. |
| ScopedLazyImageLoadingForTest scoped_lazy_image_loading_for_test(true); |
| RunSetUp(kViewportEnabled); |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", |
| "<img src='foo.jpg' height='20px' width='20px' loading='lazy'>", nullptr, |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<img src='foo.jpg' style='height: 20px; width: 20px' loading='lazy'>", |
| nullptr, "http://example.test/", ResourceType::kImage, 0}, |
| }; |
| for (const auto& test_case : test_cases) |
| Test(test_case); |
| |
| // When loading is eager or auto, lazyload is disabled and preload happens. |
| LazyLoadImageTestCase test_cases_that_preload[] = { |
| {"<img src='foo.jpg' height='20px' width='20px' loading='eager'>", false}, |
| {"<img src='foo.jpg' style='height: 20px; width: 20px' loading='eager'>", |
| false}, |
| {"<img src='foo.jpg' height='20px' width='20px' loading='auto'>", false}, |
| {"<img src='foo.jpg' style='height: 20px; width: 20px' loading='auto'>", |
| false}, |
| }; |
| for (const auto& test_case : test_cases_that_preload) |
| Test(test_case); |
| } |
| |
| // TODO(domfarolino): Before merging, can we just delete this test, since we no |
| // longer have metadata fetching? |
| TEST_F(HTMLPreloadScannerTest, LazyLoadImage_DisableMetadataFetch) { |
| struct TestCase { |
| bool automatic_lazy_image_loading_enabled; |
| const char* loading_attr_value; |
| bool expected_is_preload; |
| }; |
| const TestCase test_cases[] = { |
| // The lazyload eligible cases should not trigger a preload. |
| {false, "lazy", false}, |
| {true, "lazy", false}, |
| {true, "auto", false}, |
| |
| // Lazyload ineligible case. |
| {false, "auto", true}, |
| |
| // Full image should be fetched when loading='eager' irrespective of |
| // automatic lazyload feature state. |
| {false, "eager", true}, |
| {true, "eager", true}, |
| }; |
| for (const auto& test_case : test_cases) { |
| ScopedAutomaticLazyImageLoadingForTest |
| scoped_automatic_lazy_image_loading_for_test( |
| test_case.automatic_lazy_image_loading_enabled); |
| ScopedRestrictAutomaticLazyImageLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_image_loading_to_data_saver_for_test( |
| false); |
| RunSetUp(kViewportEnabled); |
| const std::string img_html = base::StringPrintf( |
| "<img src='foo.jpg' loading='%s'>", test_case.loading_attr_value); |
| if (test_case.expected_is_preload) { |
| LazyLoadImageTestCase test_preload = {img_html.c_str(), false}; |
| Test(test_preload); |
| } else { |
| PreloadScannerTestCase test_no_preload = { |
| "http://example.test", img_html.c_str(), nullptr, |
| "http://example.test/", ResourceType::kImage, 0}; |
| Test(test_no_preload); |
| } |
| } |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, |
| LazyLoadImage_FirstKImagesNotAppliesForExplicit) { |
| ScopedAutomaticLazyImageLoadingForTest |
| scoped_automatic_lazy_image_loading_for_test(false); |
| ScopedRestrictAutomaticLazyImageLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_image_loading_to_data_saver_for_test( |
| false); |
| GetDocument().GetSettings()->SetLazyImageFirstKFullyLoadUnknown(1); |
| RunSetUp(kViewportEnabled); |
| |
| // Neither of the images should be preloaded. |
| LazyLoadImageTestCase test1 = {"<img src='foo.jpg' loading='lazy'>", true}; |
| Test(test1); |
| LazyLoadImageTestCase test2 = {"<img src='bar.jpg' loading='lazy'>", true}; |
| Test(test2); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, LazyLoadImage_FirstKImagesAppliesForAutomatic) { |
| ScopedAutomaticLazyImageLoadingForTest |
| scoped_automatic_lazy_image_loading_for_test(true); |
| ScopedRestrictAutomaticLazyImageLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_image_loading_to_data_saver_for_test( |
| false); |
| GetDocument().GetSettings()->SetLazyImageFirstKFullyLoadUnknown(1); |
| RunSetUp(kViewportEnabled); |
| |
| // Only the first image should get preloaded |
| LazyLoadImageTestCase test1 = {"<img src='foo.jpg'>", false}; |
| Test(test1); |
| LazyLoadImageTestCase test2 = {"<img src='bar.jpg'>", true}; |
| Test(test2); |
| } |
| |
| TEST_F(HTMLPreloadScannerTest, |
| LazyLoadImage_ExplicitImageCountedForFirstKImages) { |
| ScopedAutomaticLazyImageLoadingForTest |
| scoped_automatic_lazy_image_loading_for_test(true); |
| ScopedRestrictAutomaticLazyImageLoadingToDataSaverForTest |
| scoped_restrict_automatic_lazy_image_loading_to_data_saver_for_test( |
| false); |
| GetDocument().GetSettings()->SetLazyImageFirstKFullyLoadUnknown(1); |
| RunSetUp(kViewportEnabled); |
| |
| // The first image should be counted towards first K images limit, even though |
| // it has loading='lazy'. |
| LazyLoadImageTestCase test1 = {"<img src='foo.jpg' loading='lazy'>", true}; |
| Test(test1); |
| LazyLoadImageTestCase test2 = {"<img src='bar.jpg'>", true}; |
| Test(test2); |
| } |
| |
| // https://crbug.com/1087854 |
| TEST_F(HTMLPreloadScannerTest, CSSImportWithSemicolonInUrl) { |
| PreloadScannerTestCase test_cases[] = { |
| {"https://example.test", |
| "<style>@import " |
| "url(\"https://example2.test/css?foo=a;b&bar=d\");</style>", |
| "https://example2.test/css?foo=a;b&bar=d", "https://example.test/", |
| ResourceType::kCSSStyleSheet, 0}, |
| {"https://example.test", |
| "<style>@import " |
| "url('https://example2.test/css?foo=a;b&bar=d');</style>", |
| "https://example2.test/css?foo=a;b&bar=d", "https://example.test/", |
| ResourceType::kCSSStyleSheet, 0}, |
| {"https://example.test", |
| "<style>@import " |
| "url(https://example2.test/css?foo=a;b&bar=d);</style>", |
| "https://example2.test/css?foo=a;b&bar=d", "https://example.test/", |
| ResourceType::kCSSStyleSheet, 0}, |
| {"https://example.test", |
| "<style>@import \"https://example2.test/css?foo=a;b&bar=d\";</style>", |
| "https://example2.test/css?foo=a;b&bar=d", "https://example.test/", |
| ResourceType::kCSSStyleSheet, 0}, |
| {"https://example.test", |
| "<style>@import 'https://example2.test/css?foo=a;b&bar=d';</style>", |
| "https://example2.test/css?foo=a;b&bar=d", "https://example.test/", |
| ResourceType::kCSSStyleSheet, 0}, |
| }; |
| |
| for (const auto& test : test_cases) |
| Test(test); |
| } |
| |
| // https://crbug.com/1181291 |
| TEST_F(HTMLPreloadScannerTest, TemplateInteractions) { |
| PreloadScannerTestCase test_cases[] = { |
| {"http://example.test", "<template><img src='bla.gif'></template>", |
| nullptr, "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<template><template><img src='bla.gif'></template></template>", nullptr, |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<template><template></template><img src='bla.gif'></template>", nullptr, |
| "http://example.test/", ResourceType::kImage, 0}, |
| {"http://example.test", |
| "<template><template></template><script " |
| "src='test.js'></script></template>", |
| nullptr, "http://example.test/", ResourceType::kScript, 0}, |
| {"http://example.test", |
| "<template><template></template><link rel=preload as=fetch " |
| "href=bla></template>", |
| nullptr, "http://example.test/", ResourceType::kRaw, 0}, |
| {"http://example.test", |
| "<template><template></template><link rel='stylesheet' href='sheet.css' " |
| "type='text/css'></template>", |
| nullptr, "http://example.test/", ResourceType::kCSSStyleSheet, 0}, |
| }; |
| for (const auto& test : test_cases) |
| Test(test); |
| } |
| |
| } // namespace blink |