blob: beb9ff58c0d8f643ab7e3fff9436702301a98fc8 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2018 The Chromium Authors
Kinuko Yasuda3e68ee72018-02-08 15:40:252// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Kinuko Yasuda3e68ee72018-02-08 15:40:255#include <string>
Kinuko Yasuda5e06da62018-02-09 10:17:406#include <vector>
Kinuko Yasuda3e68ee72018-02-08 15:40:257
Lukasz Anforowicza2ab8682020-10-26 17:13:028#include "base/files/file_path.h"
9#include "base/files/file_util.h"
10#include "base/files/scoped_temp_dir.h"
11#include "base/run_loop.h"
Lei Zhang0a85e65a2025-05-23 19:22:0612#include "base/strings/string_number_conversions.h"
Kinuko Yasuda5e06da62018-02-09 10:17:4013#include "base/strings/stringprintf.h"
Xiaochen Zhoue377ec82024-06-28 14:50:5314#include "base/test/bind.h"
Kinuko Yasuda3e68ee72018-02-08 15:40:2515#include "base/test/scoped_feature_list.h"
Andrew Williams436331302024-08-21 23:05:5116#include "base/test/test_future.h"
Lukasz Anforowicza2ab8682020-10-26 17:13:0217#include "base/threading/thread_restrictions.h"
Kevin Marshall62936572022-12-01 22:49:3218#include "build/build_config.h"
Tsuyoshi Horof6017cd2019-05-07 03:01:5219#include "content/browser/loader/prefetch_browsertest_base.h"
Kinuko Yasuda8edb92462018-02-21 15:46:5720#include "content/browser/web_package/mock_signed_exchange_handler.h"
Eric Seckler8652dcd52018-09-20 10:42:2821#include "content/public/browser/browser_task_traits.h"
Gabriel Charette790754c2018-03-16 21:32:5922#include "content/public/browser/browser_thread.h"
Kinuko Yasudadb67b532018-02-19 09:11:5223#include "content/public/browser/web_contents.h"
Peter Kasting919ce652020-05-07 10:22:3624#include "content/public/test/browser_test.h"
Kinuko Yasuda3e68ee72018-02-08 15:40:2525#include "content/public/test/browser_test_utils.h"
26#include "content/public/test/content_browser_test.h"
27#include "content/public/test/content_browser_test_utils.h"
Xiaochen Zhou4faa25c22024-06-13 17:35:4928#include "content/public/test/fenced_frame_test_util.h"
29#include "content/public/test/test_frame_navigation_observer.h"
Matt Menke76af5ab2020-04-14 20:00:2930#include "content/public/test/url_loader_monitor.h"
Kinuko Yasuda3e68ee72018-02-08 15:40:2531#include "content/shell/browser/shell.h"
Tsuyoshi Horo342f6ea92019-03-13 05:35:4732#include "net/base/features.h"
Lukasz Anforowicza2ab8682020-10-26 17:13:0233#include "net/base/filename_util.h"
Matt Menke37c850e02020-04-20 22:17:4534#include "net/base/isolation_info.h"
Alex Turner53ddd032020-01-15 16:00:4635#include "net/dns/mock_host_resolver.h"
Xiaochen Zhou4faa25c22024-06-13 17:35:4936#include "net/test/embedded_test_server/default_handlers.h"
Andrew Williamsaeeec53b2024-08-20 22:32:3037#include "net/test/scoped_mutually_exclusive_feature_list.h"
Kinuko Yasuda3e68ee72018-02-08 15:40:2538#include "services/network/public/cpp/features.h"
Matt Menke76af5ab2020-04-14 20:00:2939#include "services/network/public/cpp/resource_request.h"
Dominic Farolino693fd72d2019-08-05 11:09:4440#include "third_party/blink/public/common/features.h"
Kinuko Yasuda3e68ee72018-02-08 15:40:2541
42namespace content {
43
Andrew Williamsaeeec53b2024-08-20 22:32:3044namespace {
45
46enum class SplitCacheTestCase {
47 kDisabled,
48 kEnabledTripleKeyed,
49 kEnabledTriplePlusCredsBool,
50 kEnabledTriplePlusCrossSiteMainFrameNavBool,
Andrew Williams82605732025-03-03 18:30:5551 // TODO(crbug.com/40186884): If we decide to launch SplitCacheByCredentials,
52 // we should add a test case for the SplitCacheByCredentials feature and the
53 // SplitCacheByCrossSiteMainFrameNavigationBoolean feature both enabled.
Andrew Williamsaeeec53b2024-08-20 22:32:3054};
55
Adam Ricec30c0912024-08-27 04:45:1656const struct {
Andrew Williamsaeeec53b2024-08-20 22:32:3057 const SplitCacheTestCase test_case;
58 base::test::FeatureRef feature;
59} kTestCaseToFeatureMapping[] = {
60 {SplitCacheTestCase::kEnabledTriplePlusCredsBool,
61 net::features::kSplitCacheByIncludeCredentials},
62 {SplitCacheTestCase::kEnabledTriplePlusCrossSiteMainFrameNavBool,
Andrew Williams82605732025-03-03 18:30:5563 net::features::kSplitCacheByCrossSiteMainFrameNavigationBoolean}};
Andrew Williamsaeeec53b2024-08-20 22:32:3064
65} // namespace
66
Tsuyoshi Horo2b541fe82019-04-17 07:46:4767class PrefetchBrowserTest
68 : public PrefetchBrowserTestBase,
Andrew Williamsaeeec53b2024-08-20 22:32:3069 public testing::WithParamInterface<SplitCacheTestCase> {
Tsuyoshi Horo2b541fe82019-04-17 07:46:4770 public:
Dominic Farolino80369b22019-08-23 08:53:3471 PrefetchBrowserTest()
Alex Turner53ddd032020-01-15 16:00:4672 : cross_origin_server_(std::make_unique<net::EmbeddedTestServer>()),
Andrew Williamsaeeec53b2024-08-20 22:32:3073 split_cache_test_case_(GetParam()),
74 split_cache_experiment_feature_list_(GetParam(),
Adam Ricec30c0912024-08-27 04:45:1675 kTestCaseToFeatureMapping) {
Kenichi Ishibashi79965112025-02-06 06:43:1476 std::vector<base::test::FeatureRef> enabled_features;
77 std::vector<base::test::FeatureRef> disabled_features;
Andrew Williamsaeeec53b2024-08-20 22:32:3078 if (IsSplitCacheEnabled()) {
Kenichi Ishibashi79965112025-02-06 06:43:1479 enabled_features.emplace_back(
Andrew Williamsaeeec53b2024-08-20 22:32:3080 net::features::kSplitCacheByNetworkIsolationKey);
81 } else {
Kenichi Ishibashi79965112025-02-06 06:43:1482 disabled_features.emplace_back(
Andrew Williamsaeeec53b2024-08-20 22:32:3083 net::features::kSplitCacheByNetworkIsolationKey);
84 }
Kenichi Ishibashi79965112025-02-06 06:43:1485 enabled_features.emplace_back(net::features::kHttpCacheNoVarySearch);
86 split_cache_enabled_feature_list_.InitWithFeatures(enabled_features,
87 disabled_features);
Andrew Williamsaeeec53b2024-08-20 22:32:3088 }
Peter Boström828b9022021-09-21 02:28:4389
90 PrefetchBrowserTest(const PrefetchBrowserTest&) = delete;
91 PrefetchBrowserTest& operator=(const PrefetchBrowserTest&) = delete;
92
Arthur Sonzogni54013f22021-09-03 14:57:1293 ~PrefetchBrowserTest() override = default;
Tsuyoshi Horo2b541fe82019-04-17 07:46:4794
Alex Turner53ddd032020-01-15 16:00:4695 void SetUpOnMainThread() override {
96 PrefetchBrowserTestBase::SetUpOnMainThread();
97 host_resolver()->AddRule("*", "127.0.0.1");
98 }
99
Andrew Williamsaeeec53b2024-08-20 22:32:30100 bool IsSplitCacheEnabled() const {
101 return split_cache_test_case_ != SplitCacheTestCase::kDisabled;
Tsuyoshi Horo2b541fe82019-04-17 07:46:47102 }
103
104 protected:
Tsuyoshi Horo342f6ea92019-03-13 05:35:47105 std::unique_ptr<net::EmbeddedTestServer> cross_origin_server_;
Andrew Williamsaeeec53b2024-08-20 22:32:30106 const SplitCacheTestCase split_cache_test_case_;
Kinuko Yasudadb67b532018-02-19 09:11:52107
Kinuko Yasuda3e68ee72018-02-08 15:40:25108 private:
Andrew Williamsaeeec53b2024-08-20 22:32:30109 net::test::ScopedMutuallyExclusiveFeatureList
110 split_cache_experiment_feature_list_;
111 base::test::ScopedFeatureList split_cache_enabled_feature_list_;
Kinuko Yasuda3e68ee72018-02-08 15:40:25112};
113
Alison Gale770f3fc2024-04-27 00:39:58114// TODO(crbug.com/40256279): De-flake and re-enable.
Dominic Farolino80369b22019-08-23 08:53:34115IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
L. David Baron8acd3af2023-02-17 17:56:04116 DISABLED_CrossOriginDocumentHasNoSameSiteCookies) {
Matt Menke76af5ab2020-04-14 20:00:29117 const char* prefetch_path = "/prefetch.html";
118 const char* target_path = "/target.html";
119 RegisterResponse(
120 target_path,
121 ResponseEntry("<head><title>Prefetch Target</title></head>"));
122
123 base::RunLoop prefetch_waiter;
124 auto request_counter = RequestCounter::CreateAndMonitor(
125 cross_origin_server_.get(), target_path, &prefetch_waiter);
126 RegisterRequestHandler(cross_origin_server_.get());
127 ASSERT_TRUE(cross_origin_server_->Start());
128
129 const GURL cross_origin_target_url =
130 cross_origin_server_->GetURL("3p.example", target_path);
131 RegisterResponse(
132 prefetch_path,
133 ResponseEntry(base::StringPrintf(
134 "<body><link rel='prefetch' as='document' href='%s'></body>",
135 cross_origin_target_url.spec().c_str())));
136 RegisterRequestHandler(embedded_test_server());
137 ASSERT_TRUE(embedded_test_server()->Start());
138 EXPECT_EQ(0, request_counter->GetRequestCount());
139 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
140
141 URLLoaderMonitor monitor({cross_origin_target_url});
142
143 // Loading a page that prefetches the target URL would increment the
144 // |request_counter|.
145 EXPECT_TRUE(
146 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
147 prefetch_waiter.Run();
148 EXPECT_EQ(1, request_counter->GetRequestCount());
149 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
150
151 monitor.WaitForUrls();
Arthur Sonzognic686e8f2024-01-11 08:36:37152 std::optional<network::ResourceRequest> request =
Matt Menke76af5ab2020-04-14 20:00:29153 monitor.GetRequestInfo(cross_origin_target_url);
154 ASSERT_TRUE(request);
155 ASSERT_TRUE(request->site_for_cookies.IsNull());
156 ASSERT_TRUE(request->trusted_params);
157 url::Origin cross_origin = url::Origin::Create(cross_origin_target_url);
Matt Menke37c850e02020-04-20 22:17:45158 EXPECT_TRUE(net::IsolationInfo::Create(
Andrew Williams85ba9d52024-08-09 12:09:30159 net::IsolationInfo::RequestType::kMainFrame, cross_origin,
shivanigithub4e78015f592020-10-21 13:26:23160 cross_origin, net::SiteForCookies())
Matt Menke37c850e02020-04-20 22:17:45161 .IsEqualForTesting(request->trusted_params->isolation_info));
Matt Menke76af5ab2020-04-14 20:00:29162}
163
Alison Gale770f3fc2024-04-27 00:39:58164// TODO(crbug.com/40256279): De-flake and re-enable.
Matt Menke76af5ab2020-04-14 20:00:29165IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
L. David Baron8acd3af2023-02-17 17:56:04166 DISABLED_CrossOriginDocumentReusedAsNavigation) {
Dominic Farolino56e10762019-08-06 13:33:34167 const char* prefetch_path = "/prefetch.html";
168 const char* target_path = "/target.html";
Andrew Williams85ba9d52024-08-09 12:09:30169 RegisterResponse(target_path,
170 ResponseEntry("<head><title>Prefetch Target</title></head>",
171 // The empty content type prevents this
172 // response from being blocked by ORB.
173 /*content_types=*/""));
Dominic Farolino56e10762019-08-06 13:33:34174
175 base::RunLoop prefetch_waiter;
176 auto request_counter = RequestCounter::CreateAndMonitor(
177 cross_origin_server_.get(), target_path, &prefetch_waiter);
178 RegisterRequestHandler(cross_origin_server_.get());
179 ASSERT_TRUE(cross_origin_server_->Start());
180
181 const GURL cross_origin_target_url =
Alex Turner53ddd032020-01-15 16:00:46182 cross_origin_server_->GetURL("3p.example", target_path);
Dominic Farolino56e10762019-08-06 13:33:34183 RegisterResponse(
184 prefetch_path,
185 ResponseEntry(base::StringPrintf(
186 "<body><link rel='prefetch' as='document' href='%s'></body>",
187 cross_origin_target_url.spec().c_str())));
188 RegisterRequestHandler(embedded_test_server());
189 ASSERT_TRUE(embedded_test_server()->Start());
190 EXPECT_EQ(0, request_counter->GetRequestCount());
191 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
192
193 // Loading a page that prefetches the target URL would increment the
194 // |request_counter|.
Alex Moshchuk4174c192019-08-20 16:58:09195 EXPECT_TRUE(
196 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Dominic Farolino56e10762019-08-06 13:33:34197 prefetch_waiter.Run();
198 EXPECT_EQ(1, request_counter->GetRequestCount());
199 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
200
201 // Shutdown the servers.
202 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
203 EXPECT_TRUE(cross_origin_server_->ShutdownAndWaitUntilComplete());
204
205 // Subsequent navigation to the cross-origin target URL shouldn't hit the
206 // network, and should be loaded from cache.
207 NavigateToURLAndWaitTitle(cross_origin_target_url, "Prefetch Target");
208}
209
Alison Gale770f3fc2024-04-27 00:39:58210// TODO(crbug.com/40256279): De-flake and re-enable.
Dominic Farolino80369b22019-08-23 08:53:34211IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
L. David Baron8acd3af2023-02-17 17:56:04212 DISABLED_CrossOriginDocumentFromOpaqueOrigin) {
Dominic Farolino5e9b51c2020-06-21 01:35:07213 // Prefetching as=document from a data: URL does not crash the renderer.
214 EXPECT_TRUE(NavigateToURL(
215 shell(),
216 GURL("data:text/html,<title>Data URL Prefetch Target</title><link "
217 "rel=prefetch as=document href=https://google.com>")));
218}
219
Alison Gale770f3fc2024-04-27 00:39:58220// TODO(crbug.com/40256279): De-flake and re-enable.
L. David Baron8acd3af2023-02-17 17:56:04221IN_PROC_BROWSER_TEST_P(
222 PrefetchBrowserTest,
223 DISABLED_CrossOriginDocumentNotReusedAsNestedFrameNavigation) {
Alison Gale770f3fc2024-04-27 00:39:58224 // TODO(crbug.com/40093267): Remove this early-return when SplitCache is
225 // enabled by default.
Andrew Williamsaeeec53b2024-08-20 22:32:30226 if (!IsSplitCacheEnabled()) {
227 GTEST_SKIP() << "This test is relevant only with SplitCache.";
228 }
Dominic Farolino56e10762019-08-06 13:33:34229 const char* prefetch_path = "/prefetch.html";
230 const char* host_path = "/host.html";
231 const char* iframe_path = "/iframe.html";
232 RegisterResponse(
233 host_path,
234 ResponseEntry(base::StringPrintf(
235 "<head><title>Cross-Origin Host</title></head><body><iframe "
236 "onload='document.title=\"Host Loaded\"' src='%s'></iframe></body>",
237 iframe_path)));
238 RegisterResponse(iframe_path, ResponseEntry("<h1>I am an iframe</h1>"));
239
240 base::RunLoop prefetch_waiter;
241 auto cross_origin_iframe_counter = RequestCounter::CreateAndMonitor(
242 cross_origin_server_.get(), iframe_path, &prefetch_waiter);
243 RegisterRequestHandler(cross_origin_server_.get());
244 ASSERT_TRUE(cross_origin_server_->Start());
245
Alex Turner53ddd032020-01-15 16:00:46246 const GURL cross_origin_host_url =
247 cross_origin_server_->GetURL("3p.example", host_path);
Dominic Farolino56e10762019-08-06 13:33:34248 const GURL cross_origin_iframe_url =
Alex Turner53ddd032020-01-15 16:00:46249 cross_origin_server_->GetURL("3p.example", iframe_path);
Dominic Farolino56e10762019-08-06 13:33:34250 RegisterResponse(
251 prefetch_path,
252 ResponseEntry(base::StringPrintf(
253 "<body><link rel='prefetch' as='document' href='%s'></body>",
254 cross_origin_iframe_url.spec().c_str())));
255 RegisterRequestHandler(embedded_test_server());
256 ASSERT_TRUE(embedded_test_server()->Start());
257 EXPECT_EQ(0, cross_origin_iframe_counter->GetRequestCount());
258 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
259
260 // Loading a page that prefetches the cross-origin iframe URL increments its
261 // counter.
Alex Moshchuk4174c192019-08-20 16:58:09262 EXPECT_TRUE(
263 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Dominic Farolino56e10762019-08-06 13:33:34264 prefetch_waiter.Run();
265 EXPECT_EQ(1, cross_origin_iframe_counter->GetRequestCount());
266 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
267
268 // Subsequent navigation to the cross-origin host site will trigger an iframe
269 // load which will not reuse the iframe that was prefetched from
270 // |prefetch_path|. This is because cross-origin document prefetches must
271 // only be reused for top-level navigations, and cannot be reused as
272 // cross-origin iframes.
273 NavigateToURLAndWaitTitle(cross_origin_host_url, "Host Loaded");
274 EXPECT_EQ(2, cross_origin_iframe_counter->GetRequestCount());
275 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
276
277 // Shutdown the servers.
278 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
279 EXPECT_TRUE(cross_origin_server_->ShutdownAndWaitUntilComplete());
280}
281
Alison Gale770f3fc2024-04-27 00:39:58282// TODO(crbug.com/40256279): De-flake and re-enable.
L. David Baron8acd3af2023-02-17 17:56:04283IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
284 DISABLED_CrossOriginSubresourceNotReused) {
Alison Gale770f3fc2024-04-27 00:39:58285 // TODO(crbug.com/40093267): Remove this early-return when SplitCache is
286 // enabled by default.
Andrew Williamsaeeec53b2024-08-20 22:32:30287 if (!IsSplitCacheEnabled()) {
288 GTEST_SKIP() << "This test is relevant only with SplitCache.";
289 }
Dominic Farolino56e10762019-08-06 13:33:34290 const char* prefetch_path = "/prefetch.html";
291 const char* host_path = "/host.html";
292 const char* subresource_path = "/subresource.js";
293 RegisterResponse(
294 host_path,
295 ResponseEntry(base::StringPrintf(
296 "<head><title>Cross-Origin Host</title></head><body><script src='%s' "
297 "onload='document.title=\"Host Loaded\"'></script></body>",
298 subresource_path)));
299 RegisterResponse(subresource_path, ResponseEntry("console.log('I loaded')"));
300
301 base::RunLoop prefetch_waiter;
302 auto cross_origin_subresource_counter = RequestCounter::CreateAndMonitor(
303 cross_origin_server_.get(), subresource_path, &prefetch_waiter);
304 RegisterRequestHandler(cross_origin_server_.get());
305 ASSERT_TRUE(cross_origin_server_->Start());
306
Alex Turner53ddd032020-01-15 16:00:46307 const GURL cross_origin_host_url =
308 cross_origin_server_->GetURL("3p.example", host_path);
Dominic Farolino56e10762019-08-06 13:33:34309 const GURL cross_origin_subresource_url =
Alex Turner53ddd032020-01-15 16:00:46310 cross_origin_server_->GetURL("3p.example", subresource_path);
Dominic Farolino56e10762019-08-06 13:33:34311 RegisterResponse(prefetch_path,
312 ResponseEntry(base::StringPrintf(
313 "<body><link rel='prefetch' href='%s'></body>",
314 cross_origin_subresource_url.spec().c_str())));
315 RegisterRequestHandler(embedded_test_server());
316 ASSERT_TRUE(embedded_test_server()->Start());
317 EXPECT_EQ(0, cross_origin_subresource_counter->GetRequestCount());
318 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
319
320 // Loading a page that prefetches the cross-origin subresource URL
321 // increments its counter.
Alex Moshchuk4174c192019-08-20 16:58:09322 EXPECT_TRUE(
323 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Dominic Farolino56e10762019-08-06 13:33:34324 prefetch_waiter.Run();
325 EXPECT_EQ(1, cross_origin_subresource_counter->GetRequestCount());
326 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
327
328 // Subsequent navigation to the cross-origin host attempting to reuse the
329 // resource that was prefetched results in the request hitting the network.
330 // This is because cross-origin subresources must only be reused within the
331 // frame they were fetched from.
332 NavigateToURLAndWaitTitle(cross_origin_host_url, "Host Loaded");
333 EXPECT_EQ(2, cross_origin_subresource_counter->GetRequestCount());
334 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
335
336 // Shutdown the servers.
337 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
338 EXPECT_TRUE(cross_origin_server_->ShutdownAndWaitUntilComplete());
339}
340
Alison Gale770f3fc2024-04-27 00:39:58341// TODO(crbug.com/40256279): De-flake and re-enable.
Dominic Farolino80369b22019-08-23 08:53:34342IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
L. David Baron8acd3af2023-02-17 17:56:04343 DISABLED_CrossOriginSubresourceReusedByCurrentFrame) {
Dominic Farolino56e10762019-08-06 13:33:34344 const char* prefetch_path = "/prefetch.html";
345 const char* use_prefetch_path = "/use-prefetch.html";
346 const char* subresource_path = "/subresource.js";
347 RegisterResponse(subresource_path, ResponseEntry("console.log('I loaded')"));
348
349 base::RunLoop prefetch_waiter;
350 auto cross_origin_subresource_counter = RequestCounter::CreateAndMonitor(
351 cross_origin_server_.get(), subresource_path, &prefetch_waiter);
352 RegisterRequestHandler(cross_origin_server_.get());
353 ASSERT_TRUE(cross_origin_server_->Start());
354
355 const GURL cross_origin_subresource_url =
Alex Turner53ddd032020-01-15 16:00:46356 cross_origin_server_->GetURL("3p.example", subresource_path);
Dominic Farolino56e10762019-08-06 13:33:34357 RegisterResponse(prefetch_path,
358 ResponseEntry(base::StringPrintf(
359 "<body><link rel='prefetch' href='%s'></body>",
360 cross_origin_subresource_url.spec().c_str())));
361 RegisterResponse(use_prefetch_path,
362 ResponseEntry(base::StringPrintf(
363 "<body><script src='%s' onload='document.title=\"Use "
364 "Prefetch Loaded\"'></script></body>",
365 cross_origin_subresource_url.spec().c_str())));
366 RegisterRequestHandler(embedded_test_server());
367 ASSERT_TRUE(embedded_test_server()->Start());
368 EXPECT_EQ(0, cross_origin_subresource_counter->GetRequestCount());
369 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
370
371 // Loading a page that prefetches the cross-origin subresource URL
372 // increments its counter.
Alex Moshchuk4174c192019-08-20 16:58:09373 EXPECT_TRUE(
374 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Dominic Farolino56e10762019-08-06 13:33:34375 prefetch_waiter.Run();
376 EXPECT_EQ(1, cross_origin_subresource_counter->GetRequestCount());
377 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
378
379 // Shut down the cross-origin server.
380 EXPECT_TRUE(cross_origin_server_->ShutdownAndWaitUntilComplete());
381
382 // Subsequent navigation to the same-origin document that attempts to reuse
383 // the cross-origin prefetch is able to reuse the resource from the cache.
384 NavigateToURLAndWaitTitle(embedded_test_server()->GetURL(use_prefetch_path),
385 "Use Prefetch Loaded");
386
387 // Shutdown the same-origin server.
388 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
389}
390
391// This tests more of an implementation detail than anything. A single resource
392// must be committed to the cache partition corresponding to a single
Brianna Goldsteind22b0642022-10-11 16:30:50393// NetworkAnonymizationKey. This means that even though it is considered "safe"
394// to reused cross-origin subresource prefetches for top-level navigations, we
Dominic Farolino56e10762019-08-06 13:33:34395// can't actually do this, because the subresource is only reusable from the
396// frame that fetched it.
Alison Gale770f3fc2024-04-27 00:39:58397// TODO(crbug.com/40256279): De-flake and re-enable.
Dominic Farolino80369b22019-08-23 08:53:34398IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
L. David Baron8acd3af2023-02-17 17:56:04399 DISABLED_CrossOriginSubresourceNotReusedAsNavigation) {
Alison Gale770f3fc2024-04-27 00:39:58400 // TODO(crbug.com/40093267): Remove this early-return when SplitCache is
401 // enabled by default.
Andrew Williamsaeeec53b2024-08-20 22:32:30402 if (!IsSplitCacheEnabled()) {
403 GTEST_SKIP() << "This test is relevant only with SplitCache.";
404 }
Dominic Farolino56e10762019-08-06 13:33:34405 const char* prefetch_path = "/prefetch.html";
406 const char* subresource_path = "/subresource.js";
407 RegisterResponse(subresource_path, ResponseEntry("console.log('I loaded');"));
408
409 base::RunLoop prefetch_waiter;
410 auto cross_origin_subresource_counter = RequestCounter::CreateAndMonitor(
411 cross_origin_server_.get(), subresource_path, &prefetch_waiter);
412 RegisterRequestHandler(cross_origin_server_.get());
413 ASSERT_TRUE(cross_origin_server_->Start());
414
415 const GURL cross_origin_subresource_url =
Alex Turner53ddd032020-01-15 16:00:46416 cross_origin_server_->GetURL("3p.example", subresource_path);
Dominic Farolino56e10762019-08-06 13:33:34417 RegisterResponse(prefetch_path,
418 ResponseEntry(base::StringPrintf(
419 "<body><link rel='prefetch' href='%s'></body>",
420 cross_origin_subresource_url.spec().c_str())));
421 RegisterRequestHandler(embedded_test_server());
422 ASSERT_TRUE(embedded_test_server()->Start());
423 EXPECT_EQ(0, cross_origin_subresource_counter->GetRequestCount());
424 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
425
426 // Loading a page that prefetches the cross-origin subresource URL
427 // increments its counter.
Alex Moshchuk4174c192019-08-20 16:58:09428 EXPECT_TRUE(
429 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Dominic Farolino56e10762019-08-06 13:33:34430 prefetch_waiter.Run();
431 EXPECT_EQ(1, cross_origin_subresource_counter->GetRequestCount());
432 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
433
434 // Shutdown the same-origin server.
435 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
436 // Subsequent navigation to the cross-origin subresource itself will not be
437 // reused from the cache, because the cached resource is not partitioned under
438 // the cross-origin it is served from.
Alex Moshchuk4174c192019-08-20 16:58:09439 EXPECT_TRUE(NavigateToURL(shell(), cross_origin_subresource_url));
Dominic Farolino56e10762019-08-06 13:33:34440 EXPECT_EQ(2, cross_origin_subresource_counter->GetRequestCount());
441 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
442
443 // Shutdown the cross-origin server.
444 EXPECT_TRUE(cross_origin_server_->ShutdownAndWaitUntilComplete());
445}
446
Kinuko Yasuda3e68ee72018-02-08 15:40:25447IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, Simple) {
Tsuyoshi Horo342f6ea92019-03-13 05:35:47448 const char* prefetch_path = "/prefetch.html";
449 const char* target_path = "/target.html";
Kinuko Yasuda5e06da62018-02-09 10:17:40450 RegisterResponse(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47451 prefetch_path,
Kinuko Yasuda5e06da62018-02-09 10:17:40452 ResponseEntry(base::StringPrintf(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47453 "<body><link rel='prefetch' href='%s'></body>", target_path)));
Kinuko Yasuda5e06da62018-02-09 10:17:40454 RegisterResponse(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47455 target_path,
Domenic Denicola2fd4b6e2024-12-02 09:00:14456 ResponseEntry("<head><title>Prefetch Target</title></head>", "text/html",
457 {{"cache-control", "public, max-age=3600"}}));
Kinuko Yasuda3e68ee72018-02-08 15:40:25458
459 base::RunLoop prefetch_waiter;
Tsuyoshi Horo295224932019-06-07 09:41:02460 auto request_counter = RequestCounter::CreateAndMonitor(
461 embedded_test_server(), target_path, &prefetch_waiter);
Tsuyoshi Horo342f6ea92019-03-13 05:35:47462 RegisterRequestHandler(embedded_test_server());
Kinuko Yasuda3e68ee72018-02-08 15:40:25463 ASSERT_TRUE(embedded_test_server()->Start());
Tsuyoshi Horo295224932019-06-07 09:41:02464 EXPECT_EQ(0, request_counter->GetRequestCount());
465 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47466
467 const GURL target_url = embedded_test_server()->GetURL(target_path);
Kinuko Yasuda3e68ee72018-02-08 15:40:25468
469 // Loading a page that prefetches the target URL would increment the
Tsuyoshi Horo295224932019-06-07 09:41:02470 // |request_counter|.
Alex Moshchuk4174c192019-08-20 16:58:09471 EXPECT_TRUE(
472 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Kinuko Yasuda3e68ee72018-02-08 15:40:25473 prefetch_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:02474 EXPECT_EQ(1, request_counter->GetRequestCount());
475 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47476
477 // Shutdown the server.
478 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
Kinuko Yasuda3e68ee72018-02-08 15:40:25479
480 // Subsequent navigation to the target URL wouldn't hit the network for
Tsuyoshi Horo342f6ea92019-03-13 05:35:47481 // the target URL. The target content should still be read correctly.
482 NavigateToURLAndWaitTitle(target_url, "Prefetch Target");
483}
484
Kinuko Yasuda5e06da62018-02-09 10:17:40485IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, DoublePrefetch) {
Tsuyoshi Horo342f6ea92019-03-13 05:35:47486 const char* prefetch_path = "/prefetch.html";
487 const char* target_path = "/target.html";
488 RegisterResponse(prefetch_path, ResponseEntry(base::StringPrintf(
489 "<body><link rel='prefetch' href='%s'>"
490 "<link rel='prefetch' href='%s'></body>",
491 target_path, target_path)));
Kinuko Yasuda5e06da62018-02-09 10:17:40492 RegisterResponse(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47493 target_path,
Domenic Denicola2fd4b6e2024-12-02 09:00:14494 ResponseEntry("<head><title>Prefetch Target</title></head>", "text/html",
495 {{"cache-control", "public, max-age=3600"}}));
Kinuko Yasuda5e06da62018-02-09 10:17:40496
497 base::RunLoop prefetch_waiter;
Tsuyoshi Horo295224932019-06-07 09:41:02498 auto request_counter = RequestCounter::CreateAndMonitor(
499 embedded_test_server(), target_path, &prefetch_waiter);
Tsuyoshi Horo342f6ea92019-03-13 05:35:47500 RegisterRequestHandler(embedded_test_server());
Kinuko Yasuda5e06da62018-02-09 10:17:40501 ASSERT_TRUE(embedded_test_server()->Start());
Tsuyoshi Horo295224932019-06-07 09:41:02502 EXPECT_EQ(0, request_counter->GetRequestCount());
503 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47504
505 const GURL target_url = embedded_test_server()->GetURL(target_path);
Kinuko Yasuda5e06da62018-02-09 10:17:40506
507 // Loading a page that prefetches the target URL would increment the
Tsuyoshi Horo295224932019-06-07 09:41:02508 // |request_counter|, but it should hit only once.
Alex Moshchuk4174c192019-08-20 16:58:09509 EXPECT_TRUE(
510 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Kinuko Yasuda5e06da62018-02-09 10:17:40511 prefetch_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:02512 EXPECT_EQ(1, request_counter->GetRequestCount());
513 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47514
515 // Shutdown the server.
516 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
Kinuko Yasuda5e06da62018-02-09 10:17:40517
518 // Subsequent navigation to the target URL wouldn't hit the network for
Tsuyoshi Horo342f6ea92019-03-13 05:35:47519 // the target URL. The target content should still be read correctly.
520 NavigateToURLAndWaitTitle(target_url, "Prefetch Target");
Kinuko Yasuda5e06da62018-02-09 10:17:40521}
522
523IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, NoCacheAndNoStore) {
Tsuyoshi Horo342f6ea92019-03-13 05:35:47524 const char* prefetch_path = "/prefetch.html";
525 const char* nocache_path = "/target1.html";
526 const char* nostore_path = "/target2.html";
527
528 RegisterResponse(prefetch_path, ResponseEntry(base::StringPrintf(
529 "<body>"
530 "<link rel='prefetch' href='%s'>"
531 "<link rel='prefetch' href='%s'></body>",
532 nocache_path, nostore_path)));
533 RegisterResponse(nocache_path,
Kinuko Yasuda5e06da62018-02-09 10:17:40534 ResponseEntry("<head><title>NoCache Target</title></head>",
535 "text/html", {{"cache-control", "no-cache"}}));
Tsuyoshi Horo342f6ea92019-03-13 05:35:47536 RegisterResponse(nostore_path,
Kinuko Yasuda5e06da62018-02-09 10:17:40537 ResponseEntry("<head><title>NoStore Target</title></head>",
538 "text/html", {{"cache-control", "no-store"}}));
539
540 base::RunLoop nocache_waiter;
541 base::RunLoop nostore_waiter;
Tsuyoshi Horo295224932019-06-07 09:41:02542 auto nocache_request_counter = RequestCounter::CreateAndMonitor(
543 embedded_test_server(), nocache_path, &nocache_waiter);
544 auto nostore_request_counter = RequestCounter::CreateAndMonitor(
545 embedded_test_server(), nostore_path, &nostore_waiter);
Tsuyoshi Horo342f6ea92019-03-13 05:35:47546 RegisterRequestHandler(embedded_test_server());
Kinuko Yasuda5e06da62018-02-09 10:17:40547 ASSERT_TRUE(embedded_test_server()->Start());
Tsuyoshi Horo295224932019-06-07 09:41:02548 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
Kinuko Yasuda5e06da62018-02-09 10:17:40549
550 // Loading a page that prefetches the target URL would increment the
551 // fetch count for the both targets.
Alex Moshchuk4174c192019-08-20 16:58:09552 EXPECT_TRUE(
553 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Kinuko Yasuda5e06da62018-02-09 10:17:40554 nocache_waiter.Run();
555 nostore_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:02556 EXPECT_EQ(1, nocache_request_counter->GetRequestCount());
557 EXPECT_EQ(1, nostore_request_counter->GetRequestCount());
558 EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
Kinuko Yasuda5e06da62018-02-09 10:17:40559
Domenic Denicola2fd4b6e2024-12-02 09:00:14560 // Subsequent navigation to the no-cache URL do hit the network, because
561 // prefetch respects cache semantics.
Tsuyoshi Horo342f6ea92019-03-13 05:35:47562 NavigateToURLAndWaitTitle(embedded_test_server()->GetURL(nocache_path),
563 "NoCache Target");
Domenic Denicola2fd4b6e2024-12-02 09:00:14564 EXPECT_EQ(2, nocache_request_counter->GetRequestCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47565
Domenic Denicola2fd4b6e2024-12-02 09:00:14566 // Subsequent navigation to the no-store URL hit the network again, for the
567 // same reason.
Tsuyoshi Horo342f6ea92019-03-13 05:35:47568 NavigateToURLAndWaitTitle(embedded_test_server()->GetURL(nostore_path),
569 "NoStore Target");
Tsuyoshi Horo295224932019-06-07 09:41:02570 EXPECT_EQ(2, nostore_request_counter->GetRequestCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47571
Tsuyoshi Horo295224932019-06-07 09:41:02572 EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
Kinuko Yasuda5e06da62018-02-09 10:17:40573}
574
575IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, WithPreload) {
Tsuyoshi Horo342f6ea92019-03-13 05:35:47576 const char* prefetch_path = "/prefetch.html";
577 const char* target_path = "/target.html";
578 const char* preload_path = "/preload.js";
Kinuko Yasuda5e06da62018-02-09 10:17:40579 RegisterResponse(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47580 prefetch_path,
Kinuko Yasuda5e06da62018-02-09 10:17:40581 ResponseEntry(base::StringPrintf(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47582 "<body><link rel='prefetch' href='%s'></body>", target_path)));
Kinuko Yasuda5e06da62018-02-09 10:17:40583 RegisterResponse(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47584 target_path,
585 ResponseEntry("<head><title>Prefetch Target</title><script "
586 "src=\"./preload.js\"></script></head>",
587 "text/html",
Domenic Denicola2fd4b6e2024-12-02 09:00:14588 {{"link", "</preload.js>;rel=\"preload\";as=\"script\""},
589 {"cache-control", "public, max-age=600"}}));
Tsuyoshi Horo342f6ea92019-03-13 05:35:47590 RegisterResponse(preload_path,
591 ResponseEntry("document.title=\"done\";", "text/javascript",
592 {{"cache-control", "public, max-age=600"}}));
Kinuko Yasuda5e06da62018-02-09 10:17:40593
594 base::RunLoop preload_waiter;
Tsuyoshi Horo295224932019-06-07 09:41:02595 auto target_request_counter =
596 RequestCounter::CreateAndMonitor(embedded_test_server(), target_path);
597 auto preload_request_counter = RequestCounter::CreateAndMonitor(
598 embedded_test_server(), preload_path, &preload_waiter);
Tsuyoshi Horo342f6ea92019-03-13 05:35:47599 RegisterRequestHandler(embedded_test_server());
Kinuko Yasuda5e06da62018-02-09 10:17:40600 ASSERT_TRUE(embedded_test_server()->Start());
Tsuyoshi Horo295224932019-06-07 09:41:02601 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47602
603 const GURL target_url = embedded_test_server()->GetURL(target_path);
Kinuko Yasuda5e06da62018-02-09 10:17:40604
605 // Loading a page that prefetches the target URL would increment both
Tsuyoshi Horo295224932019-06-07 09:41:02606 // |target_request_counter| and |preload_request_counter|.
Alex Moshchuk4174c192019-08-20 16:58:09607 EXPECT_TRUE(
608 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Kinuko Yasuda5e06da62018-02-09 10:17:40609 preload_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:02610 EXPECT_EQ(1, target_request_counter->GetRequestCount());
611 EXPECT_EQ(1, preload_request_counter->GetRequestCount());
612 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
Kinuko Yasuda5e06da62018-02-09 10:17:40613
Tsuyoshi Horo342f6ea92019-03-13 05:35:47614 WaitUntilLoaded(embedded_test_server()->GetURL(preload_path));
615
616 // Shutdown the server.
617 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
618
619 NavigateToURLAndWaitTitle(target_url, "done");
620}
621
Alison Gale770f3fc2024-04-27 00:39:58622// TODO(crbug.com/40256279): De-flake and re-enable.
Matt Menke76af5ab2020-04-14 20:00:29623IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
L. David Baron8acd3af2023-02-17 17:56:04624 DISABLED_CrossOriginWithPreloadHasNoSameSiteCookies) {
Matt Menke76af5ab2020-04-14 20:00:29625 const char* target_path = "/target.html";
626 const char* preload_path = "/preload.js";
627 RegisterResponse(
628 target_path,
629 ResponseEntry("<head><title>Prefetch Target</title><script "
630 "src=\"./preload.js\"></script></head>",
631 "text/html",
632 {{"link", "</preload.js>;rel=\"preload\";as=\"script\""},
633 {"access-control-allow-origin", "*"}}));
634 RegisterResponse(preload_path,
635 ResponseEntry("document.title=\"done\";", "text/javascript",
636 {{"cache-control", "public, max-age=600"}}));
637
638 base::RunLoop preload_waiter;
639 auto target_request_counter =
640 RequestCounter::CreateAndMonitor(cross_origin_server_.get(), target_path);
641 auto preload_request_counter = RequestCounter::CreateAndMonitor(
642 cross_origin_server_.get(), preload_path, &preload_waiter);
643 RegisterRequestHandler(cross_origin_server_.get());
644
645 ASSERT_TRUE(cross_origin_server_->Start());
646
647 const GURL cross_origin_target_url =
648 cross_origin_server_->GetURL("3p.example", target_path);
649
650 const char* prefetch_path = "/prefetch.html";
651 RegisterResponse(prefetch_path,
652 ResponseEntry(base::StringPrintf(
653 "<body><link rel='prefetch' href='%s' as='document' "
654 "crossorigin='anonymous'></body>",
655 cross_origin_target_url.spec().c_str())));
656 RegisterRequestHandler(embedded_test_server());
657 ASSERT_TRUE(embedded_test_server()->Start());
658 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
659
660 URLLoaderMonitor monitor({cross_origin_target_url});
661
662 // Loading a page that prefetches the target URL would increment both
663 // |target_request_counter| and |preload_request_counter|.
664 EXPECT_TRUE(
665 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
666 preload_waiter.Run();
667 EXPECT_EQ(1, target_request_counter->GetRequestCount());
668 EXPECT_EQ(1, preload_request_counter->GetRequestCount());
669 EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
670
671 GURL cross_origin_preload_url =
672 cross_origin_server_->GetURL("3p.example", preload_path);
673 WaitUntilLoaded(cross_origin_preload_url);
674
675 monitor.WaitForUrls();
Arthur Sonzognic686e8f2024-01-11 08:36:37676 std::optional<network::ResourceRequest> request =
Matt Menke76af5ab2020-04-14 20:00:29677 monitor.GetRequestInfo(cross_origin_target_url);
678 ASSERT_TRUE(request);
679 ASSERT_TRUE(request->site_for_cookies.IsNull());
680 ASSERT_TRUE(request->trusted_params);
681 url::Origin cross_origin = url::Origin::Create(cross_origin_target_url);
Matt Menke37c850e02020-04-20 22:17:45682 EXPECT_TRUE(net::IsolationInfo::Create(
Andrew Williams85ba9d52024-08-09 12:09:30683 net::IsolationInfo::RequestType::kMainFrame, cross_origin,
shivanigithub4e78015f592020-10-21 13:26:23684 cross_origin, net::SiteForCookies())
Matt Menke37c850e02020-04-20 22:17:45685 .IsEqualForTesting(request->trusted_params->isolation_info));
Matt Menke76af5ab2020-04-14 20:00:29686}
687
Arthur Sonzogni54013f22021-09-03 14:57:12688// Variants of this test:
689// - PrefetchBrowserTest.CrossOriginWithPreloadAnonymous
690// - PrefetchBrowserTest.CrossOriginWithPreloadCredentialled
Alison Gale770f3fc2024-04-27 00:39:58691// TODO(crbug.com/40256279): De-flake and re-enable.
L. David Baron8acd3af2023-02-17 17:56:04692IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
693 DISABLED_CrossOriginWithPreloadAnonymous) {
Tsuyoshi Horo342f6ea92019-03-13 05:35:47694 const char* target_path = "/target.html";
695 const char* preload_path = "/preload.js";
696 RegisterResponse(
697 target_path,
698 ResponseEntry("<head><title>Prefetch Target</title><script "
699 "src=\"./preload.js\"></script></head>",
700 "text/html",
701 {{"link", "</preload.js>;rel=\"preload\";as=\"script\""},
702 {"access-control-allow-origin", "*"}}));
703 RegisterResponse(preload_path,
704 ResponseEntry("document.title=\"done\";", "text/javascript",
705 {{"cache-control", "public, max-age=600"}}));
706
707 base::RunLoop preload_waiter;
Tsuyoshi Horo295224932019-06-07 09:41:02708 auto target_request_counter =
709 RequestCounter::CreateAndMonitor(cross_origin_server_.get(), target_path);
710 auto preload_request_counter = RequestCounter::CreateAndMonitor(
711 cross_origin_server_.get(), preload_path, &preload_waiter);
Tsuyoshi Horo342f6ea92019-03-13 05:35:47712 RegisterRequestHandler(cross_origin_server_.get());
Dominic Farolinoad850d62019-09-02 10:09:57713 base::RunLoop preload_waiter_second_request;
714 auto preload_request_counter_second_request =
715 RequestCounter::CreateAndMonitor(cross_origin_server_.get(), preload_path,
716 &preload_waiter_second_request);
717
Tsuyoshi Horo342f6ea92019-03-13 05:35:47718 ASSERT_TRUE(cross_origin_server_->Start());
719
720 const GURL cross_origin_target_url =
Alex Turner53ddd032020-01-15 16:00:46721 cross_origin_server_->GetURL("3p.example", target_path);
722
Tsuyoshi Horo342f6ea92019-03-13 05:35:47723 const char* prefetch_path = "/prefetch.html";
Dominic Farolinodee126242019-09-09 16:58:39724 RegisterResponse(prefetch_path,
725 ResponseEntry(base::StringPrintf(
726 "<body><link rel='prefetch' href='%s' as='document' "
727 "crossorigin='anonymous'></body>",
728 cross_origin_target_url.spec().c_str())));
Tsuyoshi Horo342f6ea92019-03-13 05:35:47729 RegisterRequestHandler(embedded_test_server());
730 ASSERT_TRUE(embedded_test_server()->Start());
Tsuyoshi Horo295224932019-06-07 09:41:02731 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47732
733 // Loading a page that prefetches the target URL would increment both
Tsuyoshi Horo295224932019-06-07 09:41:02734 // |target_request_counter| and |preload_request_counter|.
Alex Moshchuk4174c192019-08-20 16:58:09735 EXPECT_TRUE(
736 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Tsuyoshi Horo342f6ea92019-03-13 05:35:47737 preload_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:02738 EXPECT_EQ(1, target_request_counter->GetRequestCount());
739 EXPECT_EQ(1, preload_request_counter->GetRequestCount());
Dominic Farolino7275d7352020-04-07 23:25:48740 EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47741
Alex Turner53ddd032020-01-15 16:00:46742 GURL cross_origin_preload_url =
743 cross_origin_server_->GetURL("3p.example", preload_path);
Dominic Farolinoad850d62019-09-02 10:09:57744 WaitUntilLoaded(cross_origin_preload_url);
745
746 // When SplitCache is enabled and the prefetch resource and its headers are
Andrew Williams436331302024-08-21 23:05:51747 // fetched with a modified IsolationInfo, the preload header resource must
748 // not be reusable by any other origin but its parent prefetch's.
Alison Gale770f3fc2024-04-27 00:39:58749 // TODO(crbug.com/40093267): When SplitCache is enabled by default, get rid of
Dominic Farolinoad850d62019-09-02 10:09:57750 // the below conditional.
Andrew Williamsaeeec53b2024-08-20 22:32:30751 if (IsSplitCacheEnabled()) {
Dominic Farolinoad850d62019-09-02 10:09:57752 // Spin up another server, hosting a page with a preload header identical to
753 // the one in |target_path|.
754 const char* reuse_preload_attempt_path = "/reuse.html";
755 RegisterResponse(
756 reuse_preload_attempt_path,
757 ResponseEntry(
758 base::StringPrintf("<head><title>Other site</title><script "
759 "src='%s'></script></head>",
760 cross_origin_preload_url.spec().c_str()),
761 "text/html",
762 {{"link",
763 base::StringPrintf("<%s>;rel=\"preload\";as=\"script\"",
764 cross_origin_preload_url.spec().c_str())},
765 {"access-control-allow-origin", "*"}}));
766 std::unique_ptr<net::EmbeddedTestServer> other_cross_origin_server =
Alex Turner53ddd032020-01-15 16:00:46767 std::make_unique<net::EmbeddedTestServer>();
Dominic Farolinoad850d62019-09-02 10:09:57768 RegisterRequestHandler(other_cross_origin_server.get());
769
770 ASSERT_TRUE(other_cross_origin_server->Start());
771
772 // Navigate to a page on the above-created server. A request for the same
773 // preload header fetched earlier must not be reusable, and must hit the
774 // network.
Alex Turner53ddd032020-01-15 16:00:46775 EXPECT_TRUE(NavigateToURL(
776 shell(), other_cross_origin_server->GetURL(
777 "other3p.example", reuse_preload_attempt_path)));
Dominic Farolinoad850d62019-09-02 10:09:57778 preload_waiter_second_request.Run();
779 EXPECT_EQ(2, preload_request_counter_second_request->GetRequestCount());
780
781 // We won't need this server again.
782 EXPECT_TRUE(other_cross_origin_server->ShutdownAndWaitUntilComplete());
Andrew Williams436331302024-08-21 23:05:51783 }
784
785 if (split_cache_test_case_ ==
786 SplitCacheTestCase::kEnabledTriplePlusCredsBool) {
787 // The navigation is requested with credentials, but the prefetch is
Arthur Sonzogni54013f22021-09-03 14:57:12788 // requested anonymously. As a result of "SplitCacheByIncludeCredentials",
789 // those aren't considered the same for the HTTP cache. Early return.
790 // See the variant of this test in:
Andrew Williams436331302024-08-21 23:05:51791 // PrefetchBrowserTest.CrossOriginWithPreloadCredentialled
Arthur Sonzogni54013f22021-09-03 14:57:12792 return;
Dominic Farolinoad850d62019-09-02 10:09:57793 }
Tsuyoshi Horo342f6ea92019-03-13 05:35:47794
795 // Shutdown the servers.
796 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
797 EXPECT_TRUE(cross_origin_server_->ShutdownAndWaitUntilComplete());
798
Andrew Williams436331302024-08-21 23:05:51799 EXPECT_TRUE(ExecJs(shell()->web_contents(), "document.title = 'not done';"));
800
Tsuyoshi Horo342f6ea92019-03-13 05:35:47801 // Subsequent navigation to the target URL wouldn't hit the network for
802 // the target URL. The target content should still be read correctly.
803 NavigateToURLAndWaitTitle(cross_origin_target_url, "done");
Kinuko Yasuda5e06da62018-02-09 10:17:40804}
805
Andrew Williams436331302024-08-21 23:05:51806// Regression test for crbug.com/357325599 - If a Link header with
807// rel="preload" has as="document" (which is invalid), we shouldn't attempt to
808// treat this as a rel="prefetch" as="document" and instead should just ignore
809// the header.
810// TODO(crbug.com/40256279): De-flake and enable.
811IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
812 DISABLED_CrossOriginWithInvalidPreloadAsDocument) {
813 const char* target_path = "/target.html";
814 const char* preload_path = "/preload.js";
815 RegisterResponse(
816 target_path,
817 ResponseEntry("<head><title>Prefetch Target</title><script "
818 "src=\"./preload.js\"></script></head>",
819 "text/html",
820 {{"link", "</preload.js>;rel=\"preload\";as=\"document\""},
821 {"access-control-allow-origin", "*"}}));
822 RegisterResponse(preload_path,
823 ResponseEntry("document.title=\"done\";", "text/javascript",
824 {{"cache-control", "public, max-age=600"}}));
825
826 auto target_request_counter =
827 RequestCounter::CreateAndMonitor(cross_origin_server_.get(), target_path);
828 auto preload_request_counter = RequestCounter::CreateAndMonitor(
829 cross_origin_server_.get(), preload_path);
830 RegisterRequestHandler(cross_origin_server_.get());
831 base::RunLoop preload_waiter_second_request;
832 auto preload_request_counter_second_request =
833 RequestCounter::CreateAndMonitor(cross_origin_server_.get(), preload_path,
834 &preload_waiter_second_request);
835
836 ASSERT_TRUE(cross_origin_server_->Start());
837
838 const GURL cross_origin_target_url =
839 cross_origin_server_->GetURL("3p.example", target_path);
840
841 const char* prefetch_path = "/prefetch.html";
842 RegisterResponse(prefetch_path,
843 ResponseEntry(base::StringPrintf(
844 "<body><link rel='prefetch' href='%s' as='document' "
845 "crossorigin='anonymous'></body>",
846 cross_origin_target_url.spec().c_str())));
847 RegisterRequestHandler(embedded_test_server());
848 ASSERT_TRUE(embedded_test_server()->Start());
849 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
850
851 // Loading a page that prefetches the target URL would increment
852 // `target_request_counter` but not `preload_request_counter` because the
853 // preload header should be ignored.
854 base::test::TestFuture<void> prefetch_future;
855 RegisterPrefetchLoaderCallback(prefetch_future.GetCallback());
856
857 EXPECT_TRUE(
858 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
859 EXPECT_TRUE(prefetch_future.Wait());
860 EXPECT_EQ(1, target_request_counter->GetRequestCount());
861 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
862 EXPECT_EQ(0, preload_request_counter->GetRequestCount());
863
864 // Subsequent navigation to the target URL should result in the preloaded JS
865 // being served from the network.
866 NavigateToURLAndWaitTitle(cross_origin_target_url, "done");
867 EXPECT_EQ(1, preload_request_counter->GetRequestCount());
868}
869
Arthur Sonzogni54013f22021-09-03 14:57:12870// Variants of this test:
871// - PrefetchBrowserTest.CrossOriginWithPreloadAnonymous
872// - PrefetchBrowserTest.CrossOriginWithPreloadCredentialled
Alison Gale770f3fc2024-04-27 00:39:58873// TODO(crbug.com/40256279): De-flake and re-enable.
Arthur Sonzogni54013f22021-09-03 14:57:12874IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
L. David Baron8acd3af2023-02-17 17:56:04875 DISABLED_CrossOriginWithPreloadCredentialled) {
Alex Kalugin96398d92021-10-18 05:17:21876 ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
877 const auto port = embedded_test_server()->port();
Arthur Sonzogni54013f22021-09-03 14:57:12878 const char target_path[] = "/target.html";
879 const char preload_path[] = "/preload.js";
880 RegisterResponse(
881 target_path,
882 ResponseEntry("<head><title>Prefetch Target</title><script "
883 "src=\"./preload.js\"></script></head>",
884 "text/html",
885 {
886 {
887 "link",
888 "</preload.js>;rel=\"preload\";as=\"script\"",
889 },
890 {
891 "Access-Control-Allow-Origin",
Alex Kalugin96398d92021-10-18 05:17:21892 "http://prefetch.com:" + base::NumberToString(port),
Arthur Sonzogni54013f22021-09-03 14:57:12893 },
894 {
895 "Access-Control-Allow-Credentials",
896 "true",
897 },
898 }));
899 RegisterResponse(preload_path,
900 ResponseEntry("document.title=\"done\";", "text/javascript",
901 {{"cache-control", "public, max-age=600"}}));
902
903 base::RunLoop preload_waiter;
904 auto target_request_counter =
905 RequestCounter::CreateAndMonitor(cross_origin_server_.get(), target_path);
906 auto preload_request_counter = RequestCounter::CreateAndMonitor(
907 cross_origin_server_.get(), preload_path, &preload_waiter);
908 RegisterRequestHandler(cross_origin_server_.get());
909 base::RunLoop preload_waiter_second_request;
910 auto preload_request_counter_second_request =
911 RequestCounter::CreateAndMonitor(cross_origin_server_.get(), preload_path,
912 &preload_waiter_second_request);
913
914 ASSERT_TRUE(cross_origin_server_->Start());
915
916 const GURL cross_origin_target_url =
917 cross_origin_server_->GetURL("3p.example", target_path);
918
919 const char* prefetch_path = "/prefetch.html";
920 RegisterResponse(prefetch_path,
921 ResponseEntry(base::StringPrintf(
922 "<body><link rel='prefetch' href='%s' as='document' "
923 "crossorigin='use-credentials'></body>",
924 cross_origin_target_url.spec().c_str())));
925 RegisterRequestHandler(embedded_test_server());
Alex Kalugin96398d92021-10-18 05:17:21926 embedded_test_server()->StartAcceptingConnections();
Arthur Sonzogni54013f22021-09-03 14:57:12927 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
928
929 // Loading a page that prefetches the target URL would increment both
930 // |target_request_counter| and |preload_request_counter|.
931 EXPECT_TRUE(NavigateToURL(
932 shell(), embedded_test_server()->GetURL("prefetch.com", prefetch_path)));
933 preload_waiter.Run();
934 EXPECT_EQ(1, target_request_counter->GetRequestCount());
935 EXPECT_EQ(1, preload_request_counter->GetRequestCount());
936 EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
937
938 GURL cross_origin_preload_url =
939 cross_origin_server_->GetURL("3p.example", preload_path);
940 WaitUntilLoaded(cross_origin_preload_url);
941
942 // Shutdown the servers.
943 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
944 EXPECT_TRUE(cross_origin_server_->ShutdownAndWaitUntilComplete());
945
946 // Subsequent navigation to the target URL wouldn't hit the network for
947 // the target URL. The target content should still be read correctly.
948 NavigateToURLAndWaitTitle(cross_origin_target_url, "done");
949}
950
Tsuyoshi Horo295224932019-06-07 09:41:02951IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, SignedExchangeWithPreload) {
Tsuyoshi Horo342f6ea92019-03-13 05:35:47952 const char* prefetch_path = "/prefetch.html";
953 const char* target_sxg_path = "/target.sxg";
954 const char* target_path = "/target.html";
955 const char* preload_path_in_sxg = "/preload.js";
Kinuko Yasuda8edb92462018-02-21 15:46:57956
957 RegisterResponse(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47958 prefetch_path,
Kinuko Yasuda8edb92462018-02-21 15:46:57959 ResponseEntry(base::StringPrintf(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47960 "<body><link rel='prefetch' href='%s'></body>", target_sxg_path)));
Kinuko Yasuda8edb92462018-02-21 15:46:57961 RegisterResponse(
Tsuyoshi Horo342f6ea92019-03-13 05:35:47962 target_sxg_path,
Kinuko Yasuda8edb92462018-02-21 15:46:57963 // We mock the SignedExchangeHandler, so just return a HTML content
Kunihiko Sakamotod6373b2d2019-01-23 04:09:43964 // as "application/signed-exchange;v=b3".
Lukasz Anforowicz6d029de2022-04-21 20:24:10965 ResponseEntry(MockSignedExchangeHandler::kMockSxgPrefix +
966 "<head><title>Prefetch Target (SXG)</title><script "
967 "src=\"./preload.js\"></script></head>",
Kunihiko Sakamotod6373b2d2019-01-23 04:09:43968 "application/signed-exchange;v=b3",
Kouhei Ueno7ebbeee2018-12-19 09:59:35969 {{"x-content-type-options", "nosniff"}}));
Tsuyoshi Horo342f6ea92019-03-13 05:35:47970 RegisterResponse(preload_path_in_sxg,
971 ResponseEntry("document.title=\"done\";", "text/javascript",
972 {{"cache-control", "public, max-age=600"}}));
Kinuko Yasuda8edb92462018-02-21 15:46:57973
974 base::RunLoop preload_waiter;
975 base::RunLoop prefetch_waiter;
Tsuyoshi Horo295224932019-06-07 09:41:02976 auto target_request_counter = RequestCounter::CreateAndMonitor(
977 embedded_test_server(), target_sxg_path, &prefetch_waiter);
978 auto preload_request_counter = RequestCounter::CreateAndMonitor(
979 embedded_test_server(), preload_path_in_sxg, &preload_waiter);
Tsuyoshi Horo342f6ea92019-03-13 05:35:47980 RegisterRequestHandler(embedded_test_server());
Kinuko Yasuda8edb92462018-02-21 15:46:57981 ASSERT_TRUE(embedded_test_server()->Start());
Tsuyoshi Horo295224932019-06-07 09:41:02982 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:47983
984 const GURL preload_url_in_sxg =
985 embedded_test_server()->GetURL(preload_path_in_sxg);
986 const GURL target_sxg_url = embedded_test_server()->GetURL(target_sxg_path);
Kinuko Yasuda8edb92462018-02-21 15:46:57987
Tsuyoshi Horo2b541fe82019-04-17 07:46:47988 MockSignedExchangeHandlerFactory factory({MockSignedExchangeHandlerParams(
989 target_sxg_url, SignedExchangeLoadResult::kSuccess, net::OK,
Tsuyoshi Horo342f6ea92019-03-13 05:35:47990 GURL(embedded_test_server()->GetURL(target_path)), "text/html",
Matt Menke141ff562020-04-15 01:33:23991 {{"Link", base::StringPrintf("<%s>;rel=\"preload\";as=\"script\"",
992 preload_url_in_sxg.spec().c_str())}},
Tsuyoshi Horo242ee8f2019-04-26 06:37:07993 net::SHA256HashValue({{0x00}}))});
Kinuko Yasuda8edb92462018-02-21 15:46:57994 ScopedSignedExchangeHandlerFactory scoped_factory(&factory);
995
996 // Loading a page that prefetches the target URL would increment both
Tsuyoshi Horo295224932019-06-07 09:41:02997 // |target_request_counter| and |preload_request_counter|.
Alex Moshchuk4174c192019-08-20 16:58:09998 EXPECT_TRUE(
999 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Kinuko Yasuda8edb92462018-02-21 15:46:571000 prefetch_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:021001 EXPECT_EQ(1, target_request_counter->GetRequestCount());
Kinuko Yasuda8edb92462018-02-21 15:46:571002
Kunihiko Sakamoto00040e595d2018-07-11 01:15:551003 // If the header in the .sxg file is correctly extracted, we should
Kinuko Yasuda8edb92462018-02-21 15:46:571004 // be able to also see the preload.
1005 preload_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:021006 EXPECT_EQ(1, preload_request_counter->GetRequestCount());
1007 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:471008
1009 // Shutdown the server.
1010 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
1011
1012 // Subsequent navigation to the target URL wouldn't hit the network for
1013 // the target URL. The target content should still be read correctly.
1014 NavigateToURLAndWaitTitle(target_sxg_url, "done");
1015}
1016
Alison Gale770f3fc2024-04-27 00:39:581017// TODO(crbug.com/40256279): De-flake and re-enable.
Tsuyoshi Horo295224932019-06-07 09:41:021018IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest,
L. David Baron8acd3af2023-02-17 17:56:041019 DISABLED_CrossOriginSignedExchangeWithPreload) {
Tsuyoshi Horo342f6ea92019-03-13 05:35:471020 const char* prefetch_path = "/prefetch.html";
1021 const char* target_sxg_path = "/target.sxg";
1022 const char* target_path = "/target.html";
1023 const char* preload_path_in_sxg = "/preload.js";
1024
1025 RegisterResponse(
1026 target_sxg_path,
1027 // We mock the SignedExchangeHandler, so just return a HTML content
1028 // as "application/signed-exchange;v=b3".
Lukasz Anforowicz6d029de2022-04-21 20:24:101029 ResponseEntry(MockSignedExchangeHandler::kMockSxgPrefix +
1030 "<head><title>Prefetch Target (SXG)</title><script "
1031 "src=\"./preload.js\"></script></head>",
Tsuyoshi Horo342f6ea92019-03-13 05:35:471032 "application/signed-exchange;v=b3",
1033 {{"x-content-type-options", "nosniff"}}));
1034 RegisterResponse(preload_path_in_sxg,
1035 ResponseEntry("document.title=\"done\";", "text/javascript",
1036 {{"cache-control", "public, max-age=600"}}));
1037
1038 base::RunLoop preload_waiter;
1039 base::RunLoop prefetch_waiter;
Tsuyoshi Horo295224932019-06-07 09:41:021040 auto target_request_counter = RequestCounter::CreateAndMonitor(
1041 cross_origin_server_.get(), target_sxg_path, &prefetch_waiter);
1042 auto preload_request_counter = RequestCounter::CreateAndMonitor(
1043 cross_origin_server_.get(), preload_path_in_sxg, &preload_waiter);
Tsuyoshi Horo342f6ea92019-03-13 05:35:471044 RegisterRequestHandler(cross_origin_server_.get());
1045 ASSERT_TRUE(cross_origin_server_->Start());
1046
Alex Turner53ddd032020-01-15 16:00:461047 const GURL target_sxg_url =
1048 cross_origin_server_->GetURL("3p.example", target_sxg_path);
Tsuyoshi Horo342f6ea92019-03-13 05:35:471049 const GURL preload_url_in_sxg =
Alex Turner53ddd032020-01-15 16:00:461050 cross_origin_server_->GetURL("3p.example", preload_path_in_sxg);
Tsuyoshi Horo342f6ea92019-03-13 05:35:471051
Dominic Farolinodee126242019-09-09 16:58:391052 RegisterResponse(
1053 prefetch_path,
1054 ResponseEntry(base::StringPrintf(
1055 "<body><link rel='prefetch' as='document' href='%s'></body>",
1056 target_sxg_url.spec().c_str())));
Tsuyoshi Horo342f6ea92019-03-13 05:35:471057 RegisterRequestHandler(embedded_test_server());
1058 ASSERT_TRUE(embedded_test_server()->Start());
Tsuyoshi Horo295224932019-06-07 09:41:021059 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:471060
Tsuyoshi Horo2b541fe82019-04-17 07:46:471061 MockSignedExchangeHandlerFactory factory({MockSignedExchangeHandlerParams(
1062 target_sxg_url, SignedExchangeLoadResult::kSuccess, net::OK,
Alex Turner53ddd032020-01-15 16:00:461063 GURL(cross_origin_server_->GetURL("3p.example", target_path)),
1064 "text/html",
Matt Menke141ff562020-04-15 01:33:231065 {{"Link", base::StringPrintf("<%s>;rel=\"preload\";as=\"script\"",
1066 preload_url_in_sxg.spec().c_str())}},
Tsuyoshi Horo242ee8f2019-04-26 06:37:071067 net::SHA256HashValue({{0x00}}))});
Tsuyoshi Horo342f6ea92019-03-13 05:35:471068 ScopedSignedExchangeHandlerFactory scoped_factory(&factory);
1069
1070 // Loading a page that prefetches the target URL would increment both
Tsuyoshi Horo295224932019-06-07 09:41:021071 // |target_request_counter| and |preload_request_counter|.
Alex Moshchuk4174c192019-08-20 16:58:091072 EXPECT_TRUE(
1073 NavigateToURL(shell(), embedded_test_server()->GetURL(prefetch_path)));
Tsuyoshi Horo342f6ea92019-03-13 05:35:471074 prefetch_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:021075 EXPECT_EQ(1, target_request_counter->GetRequestCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:471076
Tsuyoshi Horo342f6ea92019-03-13 05:35:471077 // If the header in the .sxg file is correctly extracted, we should
1078 // be able to also see the preload.
1079 preload_waiter.Run();
Tsuyoshi Horo295224932019-06-07 09:41:021080 EXPECT_EQ(1, preload_request_counter->GetRequestCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:471081
Dominic Farolino7275d7352020-04-07 23:25:481082 EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
Tsuyoshi Horo342f6ea92019-03-13 05:35:471083
1084 WaitUntilLoaded(preload_url_in_sxg);
1085
1086 // Shutdown the servers.
1087 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
1088 EXPECT_TRUE(cross_origin_server_->ShutdownAndWaitUntilComplete());
1089
1090 // Subsequent navigation to the target URL wouldn't hit the network for
1091 // the target URL. The target content should still be read correctly.
1092 NavigateToURLAndWaitTitle(target_sxg_url, "done");
Kinuko Yasuda8edb92462018-02-21 15:46:571093}
1094
Lukasz Anforowicza2ab8682020-10-26 17:13:021095IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, FileToHttp) {
1096 const char* target_path = "/target.html";
Domenic Denicola2fd4b6e2024-12-02 09:00:141097 RegisterResponse(
1098 target_path,
1099 ResponseEntry("<head><title>Prefetch Target</title></head>",
1100 // The empty content type prevents this
1101 // response from being blocked by ORB.
1102 /*content_types=*/"",
1103 {{"cache-control", "public, max-age=31536000"}}));
Lukasz Anforowicza2ab8682020-10-26 17:13:021104
1105 base::RunLoop prefetch_waiter;
1106 auto request_counter = RequestCounter::CreateAndMonitor(
1107 embedded_test_server(), target_path, &prefetch_waiter);
1108 RegisterRequestHandler(embedded_test_server());
1109 ASSERT_TRUE(embedded_test_server()->Start());
1110 EXPECT_EQ(0, request_counter->GetRequestCount());
1111 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
1112
1113 const GURL target_url = embedded_test_server()->GetURL(target_path);
1114
1115 {
1116 base::ScopedAllowBlockingForTesting allow_blocking;
1117 base::ScopedTempDir temp_dir;
1118 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1119 base::FilePath file_path = temp_dir.GetPath().AppendASCII("test.html");
1120 std::string file_content = base::StringPrintf(
1121 "<body><link rel='prefetch' as='document' href='%s'></body>",
1122 target_url.spec().c_str());
1123 ASSERT_TRUE(base::WriteFile(file_path, file_content));
1124
1125 // Loading a page that prefetches the target URL would increment the
1126 // |request_counter|.
1127 GURL file_url = net::FilePathToFileURL(file_path);
1128 EXPECT_TRUE(NavigateToURL(shell(), file_url));
1129 prefetch_waiter.Run();
1130 EXPECT_EQ(1, request_counter->GetRequestCount());
1131 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
1132 }
1133
Andrew Williams82605732025-03-03 18:30:551134 // Shutdown the server.
1135 EXPECT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
Lukasz Anforowicza2ab8682020-10-26 17:13:021136
Andrew Williams82605732025-03-03 18:30:551137 // Subsequent navigation to the target URL wouldn't hit the network for
1138 // the target URL. The target content should still be read correctly.
1139 NavigateToURLAndWaitTitle(target_url, "Prefetch Target");
Lukasz Anforowicza2ab8682020-10-26 17:13:021140}
1141
Xiaochen Zhou4faa25c22024-06-13 17:35:491142class FencedFramePrefetchTest : public PrefetchBrowserTestBase {
1143 public:
Xiaochen Zhoue377ec82024-06-28 14:50:531144 FencedFramePrefetchTest()
1145 : cross_origin_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
Xiaochen Zhou4faa25c22024-06-13 17:35:491146
1147 void SetUpOnMainThread() override {
1148 PrefetchBrowserTestBase::SetUpOnMainThread();
1149 host_resolver()->AddRule("*", "127.0.0.1");
1150
1151 // Set up the embedded https test server for fenced frame which requires a
1152 // secure context to load.
1153 embedded_https_test_server().SetSSLConfig(
1154 net::EmbeddedTestServer::CERT_TEST_NAMES);
1155 SetupCrossSiteRedirector(&embedded_https_test_server());
1156 net::test_server::RegisterDefaultHandlers(&embedded_https_test_server());
Xiaochen Zhoue377ec82024-06-28 14:50:531157
1158 cross_origin_server()->SetSSLConfig(
1159 net::EmbeddedTestServer::CERT_TEST_NAMES);
1160 SetupCrossSiteRedirector(cross_origin_server());
1161 net::test_server::RegisterDefaultHandlers(cross_origin_server());
Xiaochen Zhou4faa25c22024-06-13 17:35:491162 }
1163
1164 content::test::FencedFrameTestHelper& fenced_frame_test_helper() {
1165 return fenced_frame_test_helper_;
1166 }
1167
Xiaochen Zhoue377ec82024-06-28 14:50:531168 net::EmbeddedTestServer* cross_origin_server() {
1169 return &cross_origin_server_;
1170 }
1171
Xiaochen Zhou4faa25c22024-06-13 17:35:491172 private:
1173 test::FencedFrameTestHelper fenced_frame_test_helper_;
Xiaochen Zhoue377ec82024-06-28 14:50:531174 net::EmbeddedTestServer cross_origin_server_;
Xiaochen Zhou4faa25c22024-06-13 17:35:491175};
1176
1177// Verify that prefetch works in fenced frame.
1178IN_PROC_BROWSER_TEST_F(FencedFramePrefetchTest, BasicPrefetch) {
1179 base::RunLoop prefetch_waiter;
1180 auto request_counter = RequestCounter::CreateAndMonitor(
1181 &embedded_https_test_server(), "/image.jpg", &prefetch_waiter);
1182
1183 RegisterRequestHandler(&embedded_https_test_server());
1184 ASSERT_TRUE(embedded_https_test_server().Start());
1185 EXPECT_EQ(0, request_counter->GetRequestCount());
1186 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
1187
1188 GURL prefetch_url =
1189 embedded_https_test_server().GetURL("a.test", "/image.jpg");
1190 URLLoaderMonitor monitor({prefetch_url});
1191
1192 const GURL main_url =
1193 embedded_https_test_server().GetURL("a.test", "/title1.html");
1194 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1195
1196 const GURL fenced_frame_url = embedded_https_test_server().GetURL(
1197 "a.test", "/fenced_frames/title1.html");
1198 RenderFrameHost* fenced_frame_rfh =
1199 fenced_frame_test_helper().CreateFencedFrame(
1200 shell()->web_contents()->GetPrimaryMainFrame(), fenced_frame_url);
1201
1202 // Loading a page that prefetches the URL would increment the
1203 // |request_counter|.
1204 TestFrameNavigationObserver observer(fenced_frame_rfh);
1205 EXPECT_TRUE(ExecJs(shell()->web_contents()->GetPrimaryMainFrame(),
1206 JsReplace(
1207 R"(document.querySelector('fencedframe').config
1208 = new FencedFrameConfig($1);)",
1209 embedded_https_test_server().GetURL(
1210 "a.test", "/link_rel_prefetch.html"))));
1211 observer.WaitForCommit();
1212
1213 // Expect there is a prefetch request.
1214 prefetch_waiter.Run();
1215 monitor.WaitForUrls();
1216 std::optional<network::ResourceRequest> request =
1217 monitor.GetRequestInfo(prefetch_url);
1218 EXPECT_TRUE(request->load_flags & net::LOAD_PREFETCH);
1219
1220 EXPECT_EQ(1, request_counter->GetRequestCount());
1221 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
1222
1223 // Shutdown the server.
1224 EXPECT_TRUE(embedded_https_test_server().ShutdownAndWaitUntilComplete());
1225}
1226
1227// Test that after fenced frame disables untrusted network access, prefetch
1228// request is not allowed.
1229IN_PROC_BROWSER_TEST_F(FencedFramePrefetchTest, NetworkCutoffDisablesPrefetch) {
1230 base::RunLoop prefetch_waiter;
1231 auto request_counter = RequestCounter::CreateAndMonitor(
1232 &embedded_https_test_server(), "/image.jpg", &prefetch_waiter);
1233
1234 RegisterRequestHandler(&embedded_https_test_server());
1235 ASSERT_TRUE(embedded_https_test_server().Start());
1236 EXPECT_EQ(0, request_counter->GetRequestCount());
1237 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
1238
1239 GURL prefetch_url =
1240 embedded_https_test_server().GetURL("a.test", "/image.jpg");
1241 URLLoaderMonitor monitor({prefetch_url});
1242
1243 const GURL main_url =
1244 embedded_https_test_server().GetURL("a.test", "/title1.html");
1245 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1246
1247 const GURL fenced_frame_url = embedded_https_test_server().GetURL(
1248 "a.test", "/fenced_frames/title1.html");
1249 RenderFrameHost* fenced_frame_rfh =
1250 fenced_frame_test_helper().CreateFencedFrame(
1251 shell()->web_contents()->GetPrimaryMainFrame(), fenced_frame_url);
1252
1253 // Loading a page that immediately disables untrusted network by calling
1254 // `window.fence.disableUntrustedNetwork()`.
1255 TestFrameNavigationObserver observer(fenced_frame_rfh);
1256 EXPECT_TRUE(
1257 ExecJs(shell()->web_contents()->GetPrimaryMainFrame(),
1258 JsReplace(
1259 R"(document.querySelector('fencedframe').config
1260 = new FencedFrameConfig($1);)",
1261 embedded_https_test_server().GetURL(
1262 "a.test", "/link_rel_prefetch_disable_network.html"))));
1263 observer.WaitForCommit();
1264
1265 // There should be no prefetch request because the untrusted network has been
1266 // disabled.
1267 prefetch_waiter.RunUntilIdle();
1268 EXPECT_EQ(monitor.WaitForRequestCompletion(prefetch_url).error_code,
1269 net::ERR_NETWORK_ACCESS_REVOKED);
1270 EXPECT_EQ(0, request_counter->GetRequestCount());
1271
1272 // The `PrefetchURLLoader` count is 1 because the request did go through it.
1273 // It was eventually blocked by the nonce network status check in
1274 // `CorsURLLoaderFactory::CreateLoaderAndStart`.
1275 EXPECT_EQ(1, GetPrefetchURLLoaderCallCount());
1276
1277 // Shutdown the server.
1278 EXPECT_TRUE(embedded_https_test_server().ShutdownAndWaitUntilComplete());
1279}
1280
Xiaochen Zhoue377ec82024-06-28 14:50:531281// Similar to "PrefetchBrowserTest.CrossOriginWithPreloadCredentialled" but the
1282// test procedure takes place within a fenced frame.
1283// 1. Fenced frame navigates to `prefetch_path`.
1284// 2. The response to navigation triggers a prefetch request to
1285// `cross_origin_target_url`.
1286// 3. The response to prefetch triggers a recursive prefetch request to
1287// `preload_url`.
1288IN_PROC_BROWSER_TEST_F(FencedFramePrefetchTest,
1289 CrossOriginWithPreloadCredentialled) {
1290 ASSERT_TRUE(embedded_https_test_server().InitializeAndListen());
1291 const auto port = embedded_https_test_server().port();
1292 const char target_path[] = "/target.html";
1293 const char preload_path[] = "/preload.js";
1294
1295 // Register the response to the recursive prefetch request.
1296 RegisterResponse(preload_path,
1297 ResponseEntry(/*content=*/"document.title=\"done\";",
1298 /*content_types=*/"text/javascript",
1299 /*headers=*/
1300 {{"cache-control", "public, max-age=600"},
1301 {"Supports-Loading-Mode", "fenced-frame"}}));
1302
1303 // Set up request counters.
1304 auto target_request_counter =
1305 RequestCounter::CreateAndMonitor(cross_origin_server(), target_path);
1306
1307 base::RunLoop preload_waiter;
1308 auto preload_request_counter = RequestCounter::CreateAndMonitor(
1309 cross_origin_server(), preload_path, &preload_waiter);
1310
1311 // Start cross origin server.
1312 RegisterRequestHandler(cross_origin_server());
1313 ASSERT_TRUE(cross_origin_server()->Start());
1314
1315 // Register the response to the navigation request.
1316 const GURL cross_origin_target_url =
1317 cross_origin_server()->GetURL("b.test", target_path);
1318 const char* prefetch_path = "/prefetch.html";
1319 RegisterResponse(
1320 prefetch_path,
1321 ResponseEntry(/*content=*/JsReplace(
1322 R"(
1323 <body>
1324 <link rel='prefetch' href=$1 as='document'
1325 crossorigin='use-credentials'>
1326 </body>
1327 )",
1328 cross_origin_target_url),
1329 /*content_types=*/"text/html",
1330 /*headers=*/{{"Supports-Loading-Mode", "fenced-frame"}}));
1331
1332 RegisterRequestHandler(&embedded_https_test_server());
1333 embedded_https_test_server().StartAcceptingConnections();
1334 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
1335
1336 // Register the response to the initial prefetch request.
1337 const GURL preload_url =
1338 cross_origin_server()->GetURL("c.test", preload_path);
1339 RegisterResponse(
1340 target_path,
1341 ResponseEntry(
1342 /*content=*/JsReplace(R"(
1343 <head>
1344 <title>
1345 Prefetch Target
1346 </title>
1347 <script src=$1></script>
1348 </head>
1349 )",
1350 preload_url),
1351 /*content_types=*/"text/html",
1352 /*headers=*/
1353 {{
1354 "link",
1355 base::StringPrintf("<%s>;rel=\"preload\";as=\"script\"",
1356 preload_url.spec().c_str()),
1357 },
1358 {
1359 "Access-Control-Allow-Origin",
1360 "https://a.test:" + base::NumberToString(port),
1361 },
1362 {
1363 "Access-Control-Allow-Credentials",
1364 "true",
1365 },
1366 {"Supports-Loading-Mode", "fenced-frame"}}));
1367
1368 // Create the fenced frame.
1369 const GURL main_url =
1370 embedded_https_test_server().GetURL("a.test", "/title1.html");
1371 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1372
1373 const GURL fenced_frame_url = embedded_https_test_server().GetURL(
1374 "a.test", "/fenced_frames/title1.html");
1375 RenderFrameHost* fenced_frame_rfh =
1376 fenced_frame_test_helper().CreateFencedFrame(
1377 shell()->web_contents()->GetPrimaryMainFrame(), fenced_frame_url);
1378
1379 // Loading a page that prefetches the target URL would increment both
1380 // |target_request_counter| and |preload_request_counter|.
1381 TestFrameNavigationObserver observer(fenced_frame_rfh);
1382 EXPECT_TRUE(ExecJs(
1383 shell()->web_contents()->GetPrimaryMainFrame(),
1384 JsReplace(
1385 R"(document.querySelector('fencedframe').config
1386 = new FencedFrameConfig($1);)",
1387 embedded_https_test_server().GetURL("a.test", prefetch_path))));
1388 observer.WaitForCommit();
1389
1390 // Expect there are two prefetch requests:
1391 // 1. Navigation to `prefetch_path` which responses with a `link` element with
1392 // `prefetch` attribute. This triggers a prefetch request.
1393 // 2. The prefetch request from 1 to `cross_origin_target_url` gets a response
1394 // with a `link` header with `preload` attribute. This is turned into a
1395 // prefetch request because of the recursive prefetch token.
1396 preload_waiter.Run();
1397 EXPECT_EQ(1, target_request_counter->GetRequestCount());
1398 EXPECT_EQ(1, preload_request_counter->GetRequestCount());
1399 EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
1400
1401 // Shutdown the servers.
1402 EXPECT_TRUE(embedded_https_test_server().ShutdownAndWaitUntilComplete());
1403 EXPECT_TRUE(cross_origin_server()->ShutdownAndWaitUntilComplete());
1404}
1405
1406// Similar to FencedFramePrefetchTest.CrossOriginWithPreloadCredentialled except
1407// the fenced frame disables its network with exemption of the first prefetch
1408// request url. This allows the first prefetch request to go through. However,
1409// the second prefetch request, which is changed from a preload request because
1410// of the recursive prefetch token, is blocked.
Xiaochen Zhou0c32d362024-08-06 13:00:191411// TODO(crbug.com/336778624): This test is based on
1412// PrefetchBrowserTest.CrossOriginWithPreloadCredentialled, which is flaky. Once
1413// the flakiness is addressed, re-enable this test as well.
Xiaochen Zhoue377ec82024-06-28 14:50:531414IN_PROC_BROWSER_TEST_F(FencedFramePrefetchTest,
Xiaochen Zhou0c32d362024-08-06 13:00:191415 DISABLED_NetworkCutoffDisablesRecursivePrefetch) {
Xiaochen Zhoue377ec82024-06-28 14:50:531416 ASSERT_TRUE(embedded_https_test_server().InitializeAndListen());
1417 const auto port = embedded_https_test_server().port();
1418 const char target_path[] = "/target.html";
1419 const char preload_path[] = "/preload.js";
1420
1421 // Register the response to the recursive prefetch request.
1422 RegisterResponse(preload_path,
1423 ResponseEntry(/*content=*/"document.title=\"done\";",
1424 /*content_types=*/"text/javascript",
1425 /*headers=*/
1426 {{"cache-control", "public, max-age=600"},
1427 {"Supports-Loading-Mode", "fenced-frame"}}));
1428
1429 // Set up request counters.
1430 auto target_request_counter =
1431 RequestCounter::CreateAndMonitor(cross_origin_server(), target_path);
1432 auto preload_request_counter =
1433 RequestCounter::CreateAndMonitor(cross_origin_server(), preload_path);
1434
1435 // Start cross origin server.
1436 RegisterRequestHandler(cross_origin_server());
1437 ASSERT_TRUE(cross_origin_server()->Start());
1438
1439 // Register the response to the navigation request.
1440 const GURL cross_origin_target_url =
1441 cross_origin_server()->GetURL("b.test", target_path);
1442 const char* prefetch_path = "/prefetch.html";
1443 RegisterResponse(
1444 prefetch_path,
1445 ResponseEntry(/*content=*/JsReplace(
1446 R"(
1447 <body>
1448 <link rel='prefetch' href=$1 as='document'
1449 crossorigin='use-credentials'>
1450 </body>
1451 )",
1452 cross_origin_target_url),
1453 /*content_types=*/"text/html",
1454 /*headers=*/
1455 {{
1456 "Access-Control-Allow-Origin",
1457 "https://a.test:" + base::NumberToString(port),
1458 },
1459 {"Supports-Loading-Mode", "fenced-frame"}}));
1460
1461 RegisterRequestHandler(&embedded_https_test_server());
1462 embedded_https_test_server().StartAcceptingConnections();
1463 EXPECT_EQ(0, GetPrefetchURLLoaderCallCount());
1464
1465 // Register the response to the initial prefetch request.
1466 const GURL preload_url =
1467 cross_origin_server()->GetURL("c.test", preload_path);
1468 RegisterResponse(
1469 target_path,
1470 ResponseEntry(
1471 /*content=*/JsReplace(R"(
1472 <head>
1473 <title>
1474 Prefetch Target
1475 </title>
1476 <script src=$1></script>
1477 </head>
1478 )",
1479 preload_url),
1480 /*content_types=*/"text/html",
1481 /*headers=*/
1482 {{
1483 "link",
1484 base::StringPrintf("<%s>;rel=\"preload\";as=\"script\"",
1485 preload_url.spec().c_str()),
1486 },
1487 {
1488 "Access-Control-Allow-Origin",
1489 "https://a.test:" + base::NumberToString(port),
1490 },
1491 {
1492 "Access-Control-Allow-Credentials",
1493 "true",
1494 },
1495 {"Supports-Loading-Mode", "fenced-frame"}}));
1496
1497 // Create the fenced frame.
1498 const GURL main_url =
1499 embedded_https_test_server().GetURL("a.test", "/title1.html");
1500 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1501
1502 const GURL fenced_frame_url = embedded_https_test_server().GetURL(
1503 "a.test", "/fenced_frames/title1.html");
1504 RenderFrameHost* fenced_frame_rfh =
1505 fenced_frame_test_helper().CreateFencedFrame(
1506 shell()->web_contents()->GetPrimaryMainFrame(), fenced_frame_url);
1507
1508 // This callback is invoked when the first `PrefetchURLLoader` is created.
1509 // This is needed because once fenced frame commits the navigation, it gets
1510 // a new nonce. The network revocation call needs to take place after the
1511 // navigation but before the prefetch request is sent.
1512 RegisterPrefetchLoaderCallback(base::BindLambdaForTesting([&]() {
1513 // Disable fenced frame untrusted network but exempt
1514 // `cross_origin_target_url`. This allows the prefetch request to this url.
1515 // Note the exemption must be done first, otherwise the in-progress prefetch
1516 // request to `cross_origin_target_url` will be blocked.
1517 RenderFrameHost* rfh =
1518 test::FencedFrameTestHelper::GetMostRecentlyAddedFencedFrame(
1519 shell()->web_contents()->GetPrimaryMainFrame());
1520
1521 test::ExemptUrlsFromFencedFrameNetworkRevocation(rfh,
1522 {cross_origin_target_url});
1523 EXPECT_TRUE(ExecJs(rfh, R"(
1524 (async () => {
1525 return window.fence.disableUntrustedNetwork();
1526 })();
1527 )"));
1528 }));
1529
1530 // Monitor requests to `preload_url`.
1531 URLLoaderMonitor monitor({preload_url});
1532
1533 // Navigate the fenced frame.
1534 TestFrameNavigationObserver observer(fenced_frame_rfh);
1535 EXPECT_TRUE(ExecJs(
1536 shell()->web_contents()->GetPrimaryMainFrame(),
1537 JsReplace(
1538 R"(document.querySelector('fencedframe').config
1539 = new FencedFrameConfig($1);)",
1540 embedded_https_test_server().GetURL("a.test", prefetch_path))));
1541 observer.WaitForCommit();
1542
1543 // There should only be one prefetch request to `cross_origin_target_url`.
1544 // The recursive prefetch request is blocked because the fenced frame has
1545 // disabled its network and the request destination `preload_url` is not
1546 // exempted.
1547 EXPECT_EQ(monitor.WaitForRequestCompletion(preload_url).error_code,
1548 net::ERR_NETWORK_ACCESS_REVOKED);
1549 EXPECT_EQ(1, target_request_counter->GetRequestCount());
1550 EXPECT_EQ(0, preload_request_counter->GetRequestCount());
1551
1552 // The `PrefetchURLLoader` is still called twice because the request did go
1553 // through it. The recursive prefetch request was eventually blocked by the
1554 // nonce network status check in `CorsURLLoaderFactory::CreateLoaderAndStart`.
1555 EXPECT_EQ(2, GetPrefetchURLLoaderCallCount());
1556
1557 // Shutdown the servers.
1558 EXPECT_TRUE(embedded_https_test_server().ShutdownAndWaitUntilComplete());
1559 EXPECT_TRUE(cross_origin_server()->ShutdownAndWaitUntilComplete());
1560}
1561
Andrew Williamsaeeec53b2024-08-20 22:32:301562INSTANTIATE_TEST_SUITE_P(
1563 All,
1564 PrefetchBrowserTest,
1565 testing::ValuesIn(
1566 {SplitCacheTestCase::kDisabled, SplitCacheTestCase::kEnabledTripleKeyed,
1567 SplitCacheTestCase::kEnabledTriplePlusCredsBool,
Andrew Williams82605732025-03-03 18:30:551568 SplitCacheTestCase::kEnabledTriplePlusCrossSiteMainFrameNavBool}),
Andrew Williamsaeeec53b2024-08-20 22:32:301569 [](const testing::TestParamInfo<SplitCacheTestCase>& info) {
1570 switch (info.param) {
1571 case SplitCacheTestCase::kDisabled:
1572 return "SplitCacheDisabled";
1573 case SplitCacheTestCase::kEnabledTripleKeyed:
1574 return "SplitCacheEnabledTripleKeyed";
1575 case SplitCacheTestCase::kEnabledTriplePlusCredsBool:
1576 return "SplitCacheEnabledTriplePlusCredsBool";
1577 case SplitCacheTestCase::kEnabledTriplePlusCrossSiteMainFrameNavBool:
1578 return "SplitCacheEnabledTriplePlusCrossSiteMainFrameNavigationBool";
Andrew Williamsaeeec53b2024-08-20 22:32:301579 }
1580 });
Kinuko Yasuda3e68ee72018-02-08 15:40:251581
Kinuko Yasuda3e68ee72018-02-08 15:40:251582} // namespace content