blob: 1ce226581448ee69a87eb67514b3fe6fc2bb9803 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2022 The Chromium Authors
Max Curran646fb642022-03-16 00:44:092// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Sreeja Kamishettyf66553a2022-07-14 17:41:275#include "content/browser/preloading/prefetch/prefetch_container.h"
Max Curran18a6f2b2022-05-02 23:13:246
Max Curran679a3d52022-07-11 23:03:317#include "base/test/metrics/histogram_tester.h"
Hiroshige Hayashizaki1919c7c2023-10-13 21:46:428#include "base/test/scoped_feature_list.h"
Max Curran210cffa2022-09-06 22:24:319#include "components/ukm/test_ukm_recorder.h"
Liviu Tinta2e1ffe22024-06-21 21:01:3310#include "components/variations/net/variations_http_headers.h"
11#include "components/variations/scoped_variations_ids_provider.h"
12#include "components/variations/variations_ids_provider.h"
Max Curran5d4da4b42023-03-10 23:41:4613#include "content/browser/preloading/prefetch/prefetch_document_manager.h"
Hiroshige Hayashizaki1919c7c2023-10-13 21:46:4214#include "content/browser/preloading/prefetch/prefetch_features.h"
Taiyo Mizuhashi09f571f2025-08-04 16:05:5415#include "content/browser/preloading/prefetch/prefetch_match_resolver.h"
Max Curran210cffa2022-09-06 22:24:3116#include "content/browser/preloading/prefetch/prefetch_probe_result.h"
Hiroshige Hayashizakif55280f62025-08-19 17:23:2017#include "content/browser/preloading/prefetch/prefetch_request.h"
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:0818#include "content/browser/preloading/prefetch/prefetch_servable_state.h"
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:5719#include "content/browser/preloading/prefetch/prefetch_serving_handle.h"
Sreeja Kamishettyf66553a2022-07-14 17:41:2720#include "content/browser/preloading/prefetch/prefetch_status.h"
Taiyo Mizuhashi8aa07a32024-05-16 17:58:5721#include "content/browser/preloading/prefetch/prefetch_test_util_internal.h"
Sreeja Kamishettyf66553a2022-07-14 17:41:2722#include "content/browser/preloading/prefetch/prefetch_type.h"
Kevin McNee06824c72024-02-06 18:59:5223#include "content/browser/renderer_host/render_frame_host_impl.h"
Max Curranc4445fc2022-06-02 18:43:4324#include "content/public/browser/browser_context.h"
Max Curran646fb642022-03-16 00:44:0925#include "content/public/browser/global_routing_id.h"
kenossc3f9a2c2025-03-06 15:35:5126#include "content/public/browser/preload_pipeline_info.h"
Max Curranc4445fc2022-06-02 18:43:4327#include "content/public/browser/storage_partition.h"
Max Curran5d4da4b42023-03-10 23:41:4628#include "content/public/browser/web_contents.h"
Jeremy Roman21a705a42024-01-08 21:46:0129#include "content/public/common/content_features.h"
Kevin McNee06824c72024-02-06 18:59:5230#include "content/public/test/navigation_simulator.h"
Liviu Tinta2e1ffe22024-06-21 21:01:3331#include "content/public/test/test_browser_context.h"
Max Curranc4445fc2022-06-02 18:43:4332#include "content/public/test/test_renderer_host.h"
Dmitrii Kuragin8045a832022-07-18 17:44:3233#include "mojo/public/cpp/bindings/remote.h"
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:4534#include "mojo/public/cpp/system/string_data_source.h"
Max Curran210cffa2022-09-06 22:24:3135#include "services/metrics/public/cpp/metrics_utils.h"
36#include "services/metrics/public/cpp/ukm_builders.h"
Minoru Chikamune21c5f57d2024-11-27 05:01:1037#include "services/network/public/cpp/loading_params.h"
Max Curranc4445fc2022-06-02 18:43:4338#include "services/network/public/mojom/cookie_manager.mojom.h"
39#include "services/network/public/mojom/network_context.mojom.h"
40#include "services/network/public/mojom/url_response_head.mojom.h"
Max Curran646fb642022-03-16 00:44:0941#include "testing/gtest/include/gtest/gtest.h"
HuanPo Lin740620b2025-03-21 12:37:2642#include "third_party/blink/public/common/navigation/preloading_headers.h"
Max Curran646fb642022-03-16 00:44:0943
44namespace content {
Max Curran646fb642022-03-16 00:44:0945
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:0146class PrefetchContainerTestBase : public RenderViewHostTestHarness,
47 public WithPrefetchRearchParam {
Max Curranc4445fc2022-06-02 18:43:4348 public:
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:0149 explicit PrefetchContainerTestBase(PrefetchRearchParam param)
Max Curranc4445fc2022-06-02 18:43:4350 : RenderViewHostTestHarness(
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:0151 base::test::TaskEnvironment::TimeSource::MOCK_TIME),
52 WithPrefetchRearchParam(param) {}
Max Curranc4445fc2022-06-02 18:43:4353
54 void SetUp() override {
55 RenderViewHostTestHarness::SetUp();
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:0156 InitRearchFeatures();
Max Curranc4445fc2022-06-02 18:43:4357
58 browser_context()
59 ->GetDefaultStoragePartition()
60 ->GetNetworkContext()
61 ->GetCookieManager(cookie_manager_.BindNewPipeAndPassReceiver());
Hiroshige Hayashizaki1919c7c2023-10-13 21:46:4262 }
63
64 void TearDown() override {
65 scoped_feature_list_.Reset();
66 RenderViewHostTestHarness::TearDown();
Max Curranc4445fc2022-06-02 18:43:4367 }
68
69 network::mojom::CookieManager* cookie_manager() {
70 return cookie_manager_.get();
71 }
72
Kevin McNee06824c72024-02-06 18:59:5273 RenderFrameHostImpl* main_rfhi() {
74 return static_cast<RenderFrameHostImpl*>(main_rfh());
75 }
76
HuanPo Lin740620b2025-03-21 12:37:2677 struct SpeculationRulesPrefetchContainerOptions {
Taiyo Mizuhashi43066071f2025-04-25 23:40:2278 blink::mojom::SpeculationEagerness eagerness;
HuanPo Lin740620b2025-03-21 12:37:2679 SpeculationRulesTags speculation_rules_tags;
80 base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager;
81 };
82
Taiyo Mizuhashifb547bdf2024-03-11 15:18:3583 std::unique_ptr<PrefetchContainer> CreateSpeculationRulesPrefetchContainer(
84 const GURL& prefetch_url,
HuanPo Lin740620b2025-03-21 12:37:2685 SpeculationRulesPrefetchContainerOptions options = {}) {
Taiyo Mizuhashifb547bdf2024-03-11 15:18:3586 return std::make_unique<PrefetchContainer>(
87 *main_rfhi(), blink::DocumentToken(), prefetch_url,
88 PrefetchType(PreloadingTriggerType::kSpeculationRule,
Taiyo Mizuhashi43066071f2025-04-25 23:40:2289 /*use_prefetch_proxy=*/true, options.eagerness),
Taiyo Mizuhashifb547bdf2024-03-11 15:18:3590 blink::mojom::Referrer(),
HuanPo Lin740620b2025-03-21 12:37:2691 std::make_optional(std::move(options.speculation_rules_tags)),
Taiyo Mizuhashid7c856992025-06-23 08:56:0292 /*no_vary_search_hint=*/std::nullopt, /*priority=*/std::nullopt,
93 options.prefetch_document_manager,
kenossc3f9a2c2025-03-06 15:35:5194 PreloadPipelineInfo::Create(
kenoss8644f6bf2025-02-10 05:51:4495 /*planned_max_preloading_type=*/PreloadingType::kPrefetch));
Taiyo Mizuhashifb547bdf2024-03-11 15:18:3596 }
97
Taiyo Mizuhashi1b23ca62024-03-28 22:07:3798 std::unique_ptr<PrefetchContainer> CreateEmbedderPrefetchContainer(
99 const GURL& prefetch_url,
100 const std::optional<url::Origin> referring_origin = std::nullopt) {
101 return std::make_unique<PrefetchContainer>(
102 *web_contents(), prefetch_url,
103 PrefetchType(PreloadingTriggerType::kEmbedder,
104 /*use_prefetch_proxy=*/true),
Taiyo Mizuhashi49959d02025-04-22 16:07:54105 test::kPreloadingEmbedderHistgramSuffixForTesting,
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37106 blink::mojom::Referrer(), std::move(referring_origin),
Taiyo Mizuhashid7c856992025-06-23 08:56:02107 /*no_vary_search_hint=*/std::nullopt, /*priority=*/std::nullopt,
kenossa1af66f12025-03-07 06:10:55108 PreloadPipelineInfo::Create(
109 /*planned_max_preloading_type=*/PreloadingType::kPrefetch),
110 /*attempt=*/nullptr);
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37111 }
112
elabadysayed90651cc2025-03-28 00:23:22113 std::unique_ptr<PrefetchContainer> CreateBrowserContextPrefetchContainer(
114 const GURL& prefetch_url,
115 const net::HttpRequestHeaders& additional_headers = {},
116 bool should_append_additional_headers = true) {
117 return std::make_unique<PrefetchContainer>(
118 browser_context(), prefetch_url,
119 PrefetchType(PreloadingTriggerType::kEmbedder,
120 /*use_prefetch_proxy=*/true),
Taiyo Mizuhashi49959d02025-04-22 16:07:54121 test::kPreloadingEmbedderHistgramSuffixForTesting,
122 blink::mojom::Referrer(),
123 /*javascript_enabled=*/true,
elabadysayed90651cc2025-03-28 00:23:22124 /*referring_origin=*/std::nullopt,
125 /*no_vary_search_hint=*/std::nullopt,
Taiyo Mizuhashid13f8ca2025-06-23 13:29:02126 /*priority=*/PrefetchPriority::kHighest,
elabadysayed90651cc2025-03-28 00:23:22127 /*attempt=*/nullptr, additional_headers,
128 /*request_status_listener=*/nullptr, base::Minutes(10),
129 should_append_additional_headers);
130 }
Max Curranc4445fc2022-06-02 18:43:43131 bool SetCookie(const GURL& url, const std::string& value) {
Ari Chivukula92851c32024-04-09 12:37:44132 std::unique_ptr<net::CanonicalCookie> cookie(
133 net::CanonicalCookie::CreateForTesting(url, value, base::Time::Now()));
Max Curranc4445fc2022-06-02 18:43:43134
135 EXPECT_TRUE(cookie.get());
136
137 bool result = false;
138 base::RunLoop run_loop;
139
140 net::CookieOptions options;
141 options.set_include_httponly();
142 options.set_same_site_cookie_context(
143 net::CookieOptions::SameSiteCookieContext::MakeInclusive());
144
145 cookie_manager_->SetCanonicalCookie(
146 *cookie.get(), url, options,
147 base::BindOnce(
148 [](bool* result, base::RunLoop* run_loop,
149 net::CookieAccessResult set_cookie_access_result) {
150 *result = set_cookie_access_result.status.IsInclude();
151 run_loop->Quit();
152 },
153 &result, &run_loop));
154
155 // This will run until the cookie is set.
156 run_loop.Run();
157
158 // This will run until the cookie listener is updated.
Hiroshige Hayashizakib6a84d992023-10-02 17:57:54159 task_environment()->RunUntilIdle();
Max Curranc4445fc2022-06-02 18:43:43160
161 return result;
162 }
163
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:43164 protected:
165 base::test::ScopedFeatureList scoped_feature_list_;
166
Max Curranc4445fc2022-06-02 18:43:43167 private:
168 mojo::Remote<network::mojom::CookieManager> cookie_manager_;
169};
Max Curran646fb642022-03-16 00:44:09170
Jeremy Roman45c89d012023-08-30 21:22:02171namespace {
172
173// Add a redirect hop with dummy redirect info that should be good enough in
174// most cases.
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35175void AddRedirectHop(PrefetchContainer* container, const GURL& url) {
Jeremy Roman45c89d012023-08-30 21:22:02176 net::RedirectInfo redirect_info;
177 redirect_info.status_code = 302;
178 redirect_info.new_method = "GET";
179 redirect_info.new_url = url;
180 redirect_info.new_site_for_cookies = net::SiteForCookies::FromUrl(url);
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35181 container->AddRedirectHop(redirect_info);
Jeremy Roman45c89d012023-08-30 21:22:02182}
183
184} // namespace
185
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01186class PrefetchContainerTest
187 : public PrefetchContainerTestBase,
188 public ::testing::WithParamInterface<PrefetchRearchParam> {
189 public:
190 PrefetchContainerTest() : PrefetchContainerTestBase(GetParam()) {}
191
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:43192 private:
Liviu Tinta2e1ffe22024-06-21 21:01:33193 variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
194 variations::VariationsIdsProvider::Mode::kIgnoreSignedInState};
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:43195};
196
Liviu Tinta2e1ffe22024-06-21 21:01:33197class PrefetchContainerXClientDataHeaderTest
198 : public PrefetchContainerTestBase,
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01199 // bool: In incognito or not.
200 public ::testing::WithParamInterface<
201 std::tuple<PrefetchRearchParam, bool>> {
202 public:
203 PrefetchContainerXClientDataHeaderTest()
204 : PrefetchContainerTestBase(std::get<0>(GetParam())) {}
Liviu Tinta2e1ffe22024-06-21 21:01:33205
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01206 private:
Liviu Tinta2e1ffe22024-06-21 21:01:33207 variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
208 variations::VariationsIdsProvider::Mode::kIgnoreSignedInState};
209
210 protected:
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01211 bool IsIncognito() const { return std::get<1>(GetParam()); }
Liviu Tinta2e1ffe22024-06-21 21:01:33212 std::unique_ptr<BrowserContext> CreateBrowserContext() override {
213 auto browser_context = std::make_unique<TestBrowserContext>();
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01214 browser_context->set_is_off_the_record(IsIncognito());
Liviu Tinta2e1ffe22024-06-21 21:01:33215 return browser_context;
216 }
217};
218
219TEST_P(PrefetchContainerXClientDataHeaderTest,
220 AddHeaderForEligibleUrlOnlyWhenNotInIncognito) {
221 const GURL kTestEligibleUrl = GURL("https://google.com");
222
223 auto prefetch_container =
224 CreateSpeculationRulesPrefetchContainer(kTestEligibleUrl);
225 variations::VariationsIdsProvider::GetInstance()->ForceVariationIds({"1"},
226 {"2"});
227
228 prefetch_container->MakeResourceRequest({});
229 auto* request = prefetch_container->GetResourceRequest();
Liviu Tinta2e1ffe22024-06-21 21:01:33230 // Don't add the header when in incognito mode.
231 EXPECT_EQ(
232 request->cors_exempt_headers.HasHeader(variations::kClientDataHeader),
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01233 !IsIncognito());
Liviu Tinta2e1ffe22024-06-21 21:01:33234}
235
236TEST_P(PrefetchContainerXClientDataHeaderTest,
237 NeverAddHeaderForNonEligibleUrl) {
238 const GURL kTestNonEligibleUrl = GURL("https://non-eligible.com");
239
240 auto prefetch_container =
241 CreateSpeculationRulesPrefetchContainer(kTestNonEligibleUrl);
242 variations::VariationsIdsProvider::GetInstance()->ForceVariationIds({"1"},
243 {"2"});
244
245 prefetch_container->MakeResourceRequest({});
246 auto* request = prefetch_container->GetResourceRequest();
247 // Don't ever add the header.
248 EXPECT_FALSE(
249 request->cors_exempt_headers.HasHeader(variations::kClientDataHeader));
250}
251
252TEST_P(PrefetchContainerXClientDataHeaderTest,
253 AddHeaderForEligibleRedirectUrlOnlyWhenNotInIncognito) {
254 const GURL kTestNonEligibleUrl = GURL("https://non-eligible.com");
255 const GURL kTestEligibleUrl = GURL("https://google.com");
256
257 auto prefetch_container =
258 CreateSpeculationRulesPrefetchContainer(kTestNonEligibleUrl);
259 variations::VariationsIdsProvider::GetInstance()->ForceVariationIds({"1"},
260 {"2"});
261
262 prefetch_container->MakeResourceRequest({});
263 auto* request = prefetch_container->GetResourceRequest();
264 // Don't ever add the header.
265 EXPECT_FALSE(
266 request->cors_exempt_headers.HasHeader(variations::kClientDataHeader));
267
268 AddRedirectHop(prefetch_container.get(), kTestEligibleUrl);
Liviu Tinta2e1ffe22024-06-21 21:01:33269 EXPECT_EQ(
270 request->cors_exempt_headers.HasHeader(variations::kClientDataHeader),
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01271 !IsIncognito());
Liviu Tinta2e1ffe22024-06-21 21:01:33272}
273
274TEST_P(PrefetchContainerXClientDataHeaderTest,
275 NeverAddHeaderForNonEligibleRedirectUrl) {
276 const GURL kTestNonEligibleUrl1 = GURL("https://non-eligible1.com");
277 const GURL kTestNonEligibleUrl2 = GURL("https://non-eligible2.com");
278
279 auto prefetch_container =
280 CreateSpeculationRulesPrefetchContainer(kTestNonEligibleUrl1);
281 variations::VariationsIdsProvider::GetInstance()->ForceVariationIds({"1"},
282 {"2"});
283
284 prefetch_container->MakeResourceRequest({});
285 auto* request = prefetch_container->GetResourceRequest();
286 // Don't ever add the header.
287 EXPECT_FALSE(
288 request->cors_exempt_headers.HasHeader(variations::kClientDataHeader));
289
290 AddRedirectHop(prefetch_container.get(), kTestNonEligibleUrl2);
291 EXPECT_FALSE(
292 request->cors_exempt_headers.HasHeader(variations::kClientDataHeader));
293}
294
elabadysayed90651cc2025-03-28 00:23:22295TEST_P(PrefetchContainerXClientDataHeaderTest,
296 NeverAddHeaderIfBrowserContextSettingIsOff) {
297 const GURL kTestEligibleUrl = GURL("https://google.com");
298 net::HttpRequestHeaders additional_headers;
299 additional_headers.SetHeader(variations::kClientDataHeader,
300 "test_client_data");
301
302 auto prefetch_container = CreateBrowserContextPrefetchContainer(
303 kTestEligibleUrl, additional_headers, false);
304 variations::VariationsIdsProvider::GetInstance()->ForceVariationIds({"1"},
305 {"2"});
306
307 prefetch_container->MakeResourceRequest({});
308 auto* request = prefetch_container->GetResourceRequest();
309
310 EXPECT_TRUE(request->headers.HasHeader(variations::kClientDataHeader));
311 // It should be treated as non-trusted.
312 EXPECT_FALSE(
313 request->cors_exempt_headers.HasHeader(variations::kClientDataHeader));
314 // Make sure it doesn't get overridden.
315 EXPECT_EQ(request->headers.GetHeader(variations::kClientDataHeader).value(),
316 "test_client_data");
317}
318
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01319INSTANTIATE_TEST_SUITE_P(
320 PrefetchContainerXClientDataTests,
321 PrefetchContainerXClientDataHeaderTest,
322 testing::Combine(testing::ValuesIn(PrefetchRearchParam::Params()),
323 ::testing::Bool()));
Liviu Tinta2e1ffe22024-06-21 21:01:33324
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01325TEST_P(PrefetchContainerTest, CreatePrefetchContainer) {
Hiroshige Hayashizaki2df45292023-10-10 22:59:03326 blink::DocumentToken document_token;
Max Curran646fb642022-03-16 00:44:09327 PrefetchContainer prefetch_container(
Kevin McNee06824c72024-02-06 18:59:52328 *main_rfhi(), document_token, GURL("https://test.com"),
Kouhei Uenoc5c2ea202023-11-14 08:58:58329 PrefetchType(PreloadingTriggerType::kSpeculationRule,
330 /*use_prefetch_proxy=*/true,
Takashi Nakayama978f0a152025-06-17 08:26:25331 blink::mojom::SpeculationEagerness::kImmediate),
Takashi Toyoshima9e3ca212023-04-28 05:57:59332 blink::mojom::Referrer(),
HuanPo Lin740620b2025-03-21 12:37:26333 std::make_optional(SpeculationRulesTags({"example"})),
Rulong Chen(陈汝龙)bf12169c2024-12-16 05:38:16334 /*no_vary_search_hint=*/std::nullopt,
Taiyo Mizuhashid7c856992025-06-23 08:56:02335 /*priority=*/std::nullopt,
kenoss3bd73b82024-10-10 20:33:49336 /*prefetch_document_manager=*/nullptr,
kenossc3f9a2c2025-03-06 15:35:51337 PreloadPipelineInfo::Create(
kenoss8644f6bf2025-02-10 05:51:44338 /*planned_max_preloading_type=*/PreloadingType::kPrefetch));
Max Curran646fb642022-03-16 00:44:09339
Hiroshige Hayashizakif55280f62025-08-19 17:23:20340 ASSERT_TRUE(prefetch_container.request().GetRendererInitiatorInfo());
341 EXPECT_EQ(prefetch_container.request()
342 .GetRendererInitiatorInfo()
343 ->GetRenderFrameHostId(),
Kevin McNee06824c72024-02-06 18:59:52344 main_rfh()->GetGlobalId());
Max Curran646fb642022-03-16 00:44:09345 EXPECT_EQ(prefetch_container.GetURL(), GURL("https://test.com"));
Hiroshige Hayashizakif55280f62025-08-19 17:23:20346 EXPECT_EQ(prefetch_container.request().prefetch_type(),
Kouhei Uenoc5c2ea202023-11-14 08:58:58347 PrefetchType(PreloadingTriggerType::kSpeculationRule,
348 /*use_prefetch_proxy=*/true,
Takashi Nakayama978f0a152025-06-17 08:26:25349 blink::mojom::SpeculationEagerness::kImmediate));
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:58350 EXPECT_TRUE(
351 prefetch_container.IsIsolatedNetworkContextRequiredForCurrentPrefetch());
Max Curran646fb642022-03-16 00:44:09352
kenossaf6e0ae2024-09-05 03:06:50353 EXPECT_EQ(prefetch_container.key(),
Hiroshige Hayashizakic625e812025-08-19 18:42:35354 PrefetchKey(document_token, GURL("https://test.com")));
kenossf7b4d60d2024-07-16 15:15:08355 EXPECT_FALSE(prefetch_container.GetNonRedirectHead());
Max Curran646fb642022-03-16 00:44:09356}
357
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01358TEST_P(PrefetchContainerTest, CreatePrefetchContainer_Embedder) {
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37359 PrefetchContainer prefetch_container(
360 *web_contents(), GURL("https://test.com"),
361 PrefetchType(PreloadingTriggerType::kEmbedder,
Taiyo Mizuhashi9dfeb632024-10-24 08:44:20362 /*use_prefetch_proxy=*/false),
Taiyo Mizuhashi49959d02025-04-22 16:07:54363 test::kPreloadingEmbedderHistgramSuffixForTesting,
364 blink::mojom::Referrer(),
365 /*referring_origin=*/std::nullopt,
kenossa1af66f12025-03-07 06:10:55366 /*no_vary_search_hint=*/std::nullopt,
Taiyo Mizuhashid7c856992025-06-23 08:56:02367 /*priority=*/std::nullopt,
kenossa1af66f12025-03-07 06:10:55368 PreloadPipelineInfo::Create(
369 /*planned_max_preloading_type=*/PreloadingType::kPrefetch),
370 /*attempt=*/nullptr);
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37371
Hiroshige Hayashizakif55280f62025-08-19 17:23:20372 ASSERT_FALSE(prefetch_container.request().GetRendererInitiatorInfo());
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37373 EXPECT_EQ(prefetch_container.GetURL(), GURL("https://test.com"));
Hiroshige Hayashizakif55280f62025-08-19 17:23:20374 EXPECT_EQ(prefetch_container.request().prefetch_type(),
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37375 PrefetchType(PreloadingTriggerType::kEmbedder,
Taiyo Mizuhashi9dfeb632024-10-24 08:44:20376 /*use_prefetch_proxy=*/false));
377 EXPECT_FALSE(
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37378 prefetch_container.IsIsolatedNetworkContextRequiredForCurrentPrefetch());
379
kenossaf6e0ae2024-09-05 03:06:50380 EXPECT_EQ(prefetch_container.key(),
Hiroshige Hayashizakic625e812025-08-19 18:42:35381 PrefetchKey(std::nullopt, GURL("https://test.com")));
kenossf7b4d60d2024-07-16 15:15:08382 EXPECT_FALSE(prefetch_container.GetNonRedirectHead());
HuanPo Lin740620b2025-03-21 12:37:26383 // Embedder-initiated prefetch shouldn't include any tag.
Hiroshige Hayashizaki995741b2025-08-19 18:41:13384 EXPECT_FALSE(prefetch_container.request().speculation_rules_tags());
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37385}
386
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01387TEST_P(PrefetchContainerTest, PrefetchStatus) {
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35388 auto prefetch_container =
389 CreateSpeculationRulesPrefetchContainer(GURL("https://test.com"));
Max Curran146bf442022-03-28 23:22:14390
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35391 EXPECT_FALSE(prefetch_container->HasPrefetchStatus());
Max Curran146bf442022-03-28 23:22:14392
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35393 prefetch_container->SetPrefetchStatus(PrefetchStatus::kPrefetchNotStarted);
Max Curran146bf442022-03-28 23:22:14394
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35395 EXPECT_TRUE(prefetch_container->HasPrefetchStatus());
396 EXPECT_EQ(prefetch_container->GetPrefetchStatus(),
Max Curran146bf442022-03-28 23:22:14397 PrefetchStatus::kPrefetchNotStarted);
398}
399
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01400TEST_P(PrefetchContainerTest, IsDecoy) {
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35401 auto prefetch_container =
402 CreateSpeculationRulesPrefetchContainer(GURL("https://test.com"));
Max Curran18a6f2b2022-05-02 23:13:24403
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35404 EXPECT_FALSE(prefetch_container->IsDecoy());
Max Curran18a6f2b2022-05-02 23:13:24405
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35406 prefetch_container->SetIsDecoy(true);
407 EXPECT_TRUE(prefetch_container->IsDecoy());
Max Curran18a6f2b2022-05-02 23:13:24408}
409
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01410TEST_P(PrefetchContainerTest, Servable) {
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35411 auto prefetch_container =
412 CreateSpeculationRulesPrefetchContainer(GURL("https://test.com"));
Max Curranc4445fc2022-06-02 18:43:43413
Hiroshige Hayashizaki64802cf12025-01-16 23:18:46414 prefetch_container->SimulatePrefetchEligibleForTest();
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35415 MakeServableStreamingURLLoaderForTest(prefetch_container.get(),
416 network::mojom::URLResponseHead::New(),
417 "test body");
Max Curranc4445fc2022-06-02 18:43:43418
419 task_environment()->FastForwardBy(base::Minutes(2));
420
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35421 EXPECT_NE(prefetch_container->GetServableState(base::Minutes(1)),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:08422 PrefetchServableState::kServable);
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35423 EXPECT_EQ(prefetch_container->GetServableState(base::Minutes(3)),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:08424 PrefetchServableState::kServable);
kenossf7b4d60d2024-07-16 15:15:08425 EXPECT_TRUE(prefetch_container->GetNonRedirectHead());
Max Curranc4445fc2022-06-02 18:43:43426}
427
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01428TEST_P(PrefetchContainerTest, CookieListener) {
Max Curran5d4da4b42023-03-10 23:41:46429 const GURL kTestUrl1 = GURL("https://test1.com");
430 const GURL kTestUrl2 = GURL("https://test2.com");
431 const GURL kTestUrl3 = GURL("https://test3.com");
432
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35433 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(kTestUrl1);
434
435 prefetch_container->MakeResourceRequest({});
436 prefetch_container->RegisterCookieListener(cookie_manager());
Max Curranc4445fc2022-06-02 18:43:43437
Hiroshige Hayashizakieec97ed12023-05-26 06:38:32438 // Add redirect hops, and register its own cookie listener for each hop.
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35439 AddRedirectHop(prefetch_container.get(), kTestUrl2);
440 prefetch_container->RegisterCookieListener(cookie_manager());
441 AddRedirectHop(prefetch_container.get(), kTestUrl3);
442 prefetch_container->RegisterCookieListener(cookie_manager());
Max Curranc4445fc2022-06-02 18:43:43443
Hiroshige Hayashizaki980c130372023-05-26 04:05:01444 // Check the cookies for `kTestUrl1`, `kTestUrl2` and `kTestUrl3`,
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48445 // respectively. AdvanceCurrentURLToServe() is used to set the current hop to
446 // check the cookies.
447 {
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57448 auto serving_handle = prefetch_container->CreateServingHandle();
449 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
450 serving_handle.AdvanceCurrentURLToServe();
451 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
452 serving_handle.AdvanceCurrentURLToServe();
453 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48454 }
Max Curranc4445fc2022-06-02 18:43:43455
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48456 {
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57457 auto serving_handle = prefetch_container->CreateServingHandle();
458 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
459 serving_handle.AdvanceCurrentURLToServe();
460 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
461 serving_handle.AdvanceCurrentURLToServe();
462 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48463 }
Max Curranc4445fc2022-06-02 18:43:43464
Taiyo Mizuhashi8b5ddcc2025-02-21 22:12:12465 prefetch_container->PauseAllCookieListeners();
466 ASSERT_TRUE(SetCookie(kTestUrl1, "test-cookie0"));
467 {
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57468 auto serving_handle = prefetch_container->CreateServingHandle();
469 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
470 serving_handle.AdvanceCurrentURLToServe();
471 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
472 serving_handle.AdvanceCurrentURLToServe();
473 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
Taiyo Mizuhashi8b5ddcc2025-02-21 22:12:12474 }
475
476 prefetch_container->ResumeAllCookieListeners();
Max Curran5d4da4b42023-03-10 23:41:46477 ASSERT_TRUE(SetCookie(kTestUrl1, "test-cookie1"));
478
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48479 {
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57480 auto serving_handle = prefetch_container->CreateServingHandle();
481 EXPECT_TRUE(serving_handle.HaveDefaultContextCookiesChanged());
482 serving_handle.AdvanceCurrentURLToServe();
483 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
484 serving_handle.AdvanceCurrentURLToServe();
485 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48486 }
Max Curran5d4da4b42023-03-10 23:41:46487
488 ASSERT_TRUE(SetCookie(kTestUrl2, "test-cookie2"));
489
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48490 {
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57491 auto serving_handle = prefetch_container->CreateServingHandle();
492 EXPECT_TRUE(serving_handle.HaveDefaultContextCookiesChanged());
493 serving_handle.AdvanceCurrentURLToServe();
494 EXPECT_TRUE(serving_handle.HaveDefaultContextCookiesChanged());
495 serving_handle.AdvanceCurrentURLToServe();
496 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48497 }
Max Curranc4445fc2022-06-02 18:43:43498}
499
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01500TEST_P(PrefetchContainerTest, CookieCopy) {
Max Curran5d4da4b42023-03-10 23:41:46501 const GURL kTestUrl = GURL("https://test.com");
Max Curran679a3d52022-07-11 23:03:31502 base::HistogramTester histogram_tester;
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35503 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(kTestUrl);
Max Curranc4445fc2022-06-02 18:43:43504
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35505 prefetch_container->RegisterCookieListener(cookie_manager());
506
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57507 auto serving_handle = prefetch_container->CreateServingHandle();
Max Curranc4445fc2022-06-02 18:43:43508
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57509 EXPECT_FALSE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curranc4445fc2022-06-02 18:43:43510
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57511 serving_handle.OnIsolatedCookieCopyStart();
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48512
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57513 EXPECT_TRUE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curranc4445fc2022-06-02 18:43:43514
515 // Once the cookie copy process has started, we should stop the cookie
516 // listener.
Max Curran5d4da4b42023-03-10 23:41:46517 ASSERT_TRUE(SetCookie(kTestUrl, "test-cookie"));
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57518 EXPECT_FALSE(serving_handle.HaveDefaultContextCookiesChanged());
Max Curranc4445fc2022-06-02 18:43:43519
Max Curran679a3d52022-07-11 23:03:31520 task_environment()->FastForwardBy(base::Milliseconds(10));
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57521 serving_handle.OnIsolatedCookiesReadCompleteAndWriteStart();
Max Curran679a3d52022-07-11 23:03:31522 task_environment()->FastForwardBy(base::Milliseconds(20));
523
Max Curran1e6d79e32022-10-25 22:22:32524 // The URL interceptor checks on the cookie copy status when trying to serve a
525 // prefetch. If its still in progress, it registers a callback to be called
526 // once the copy is complete.
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57527 EXPECT_TRUE(serving_handle.IsIsolatedCookieCopyInProgress());
528 serving_handle.OnInterceptorCheckCookieCopy();
Max Curran1e6d79e32022-10-25 22:22:32529 task_environment()->FastForwardBy(base::Milliseconds(40));
Max Curranc4445fc2022-06-02 18:43:43530 bool callback_called = false;
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57531 serving_handle.SetOnCookieCopyCompleteCallback(
Max Curranc4445fc2022-06-02 18:43:43532 base::BindOnce([](bool* callback_called) { *callback_called = true; },
533 &callback_called));
534
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57535 serving_handle.OnIsolatedCookieCopyComplete();
Max Curranc4445fc2022-06-02 18:43:43536
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57537 EXPECT_FALSE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curranc4445fc2022-06-02 18:43:43538 EXPECT_TRUE(callback_called);
Max Curran679a3d52022-07-11 23:03:31539
540 histogram_tester.ExpectUniqueTimeSample(
541 "PrefetchProxy.AfterClick.Mainframe.CookieReadTime",
542 base::Milliseconds(10), 1);
543 histogram_tester.ExpectUniqueTimeSample(
544 "PrefetchProxy.AfterClick.Mainframe.CookieWriteTime",
Max Curran1e6d79e32022-10-25 22:22:32545 base::Milliseconds(60), 1);
546 histogram_tester.ExpectUniqueTimeSample(
547 "PrefetchProxy.AfterClick.Mainframe.CookieCopyStartToInterceptorCheck",
548 base::Milliseconds(30), 1);
Max Curran679a3d52022-07-11 23:03:31549 histogram_tester.ExpectUniqueTimeSample(
550 "PrefetchProxy.AfterClick.Mainframe.CookieCopyTime",
Max Curran1e6d79e32022-10-25 22:22:32551 base::Milliseconds(70), 1);
Max Curranc4445fc2022-06-02 18:43:43552}
553
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01554TEST_P(PrefetchContainerTest, CookieCopyWithRedirects) {
Max Curran7dbdea4d2023-03-21 23:47:37555 const GURL kTestUrl = GURL("https://test.com");
556 const GURL kRedirectUrl1 = GURL("https://redirect1.com");
557 const GURL kRedirectUrl2 = GURL("https://redirect2.com");
558 base::HistogramTester histogram_tester;
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35559 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(kTestUrl);
560 prefetch_container->MakeResourceRequest({});
561 prefetch_container->RegisterCookieListener(cookie_manager());
Max Curran7dbdea4d2023-03-21 23:47:37562
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35563 AddRedirectHop(prefetch_container.get(), kRedirectUrl1);
564 prefetch_container->RegisterCookieListener(cookie_manager());
Max Curran7dbdea4d2023-03-21 23:47:37565
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35566 AddRedirectHop(prefetch_container.get(), kRedirectUrl2);
567 prefetch_container->RegisterCookieListener(cookie_manager());
Max Curran7dbdea4d2023-03-21 23:47:37568
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57569 auto serving_handle = prefetch_container->CreateServingHandle();
Max Curran7dbdea4d2023-03-21 23:47:37570
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57571 EXPECT_EQ(serving_handle.GetCurrentURLToServe(), kTestUrl);
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48572
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57573 EXPECT_FALSE(serving_handle.IsIsolatedCookieCopyInProgress());
574 serving_handle.OnIsolatedCookieCopyStart();
575 EXPECT_TRUE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37576
577 // Once the cookie copy process has started, all cookie listeners are stopped.
578 ASSERT_TRUE(SetCookie(kTestUrl, "test-cookie"));
579 ASSERT_TRUE(SetCookie(kRedirectUrl1, "test-cookie"));
580 ASSERT_TRUE(SetCookie(kRedirectUrl2, "test-cookie"));
581
Hiroshige Hayashizaki980c130372023-05-26 04:05:01582 // Check the cookies for `kTestUrl`, `kRedirectUrl1` and `kRedirectUrl2`,
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48583 // respectively. AdvanceCurrentURLToServe() is used to set the current
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37584 // hop to check the cookies.
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48585 {
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57586 auto serving_handle1 = prefetch_container->CreateServingHandle();
587 EXPECT_FALSE(serving_handle1.HaveDefaultContextCookiesChanged());
588 serving_handle1.AdvanceCurrentURLToServe();
589 EXPECT_FALSE(serving_handle1.HaveDefaultContextCookiesChanged());
590 serving_handle1.AdvanceCurrentURLToServe();
591 EXPECT_FALSE(serving_handle1.HaveDefaultContextCookiesChanged());
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48592 }
Max Curran7dbdea4d2023-03-21 23:47:37593
594 task_environment()->FastForwardBy(base::Milliseconds(10));
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57595 serving_handle.OnIsolatedCookiesReadCompleteAndWriteStart();
Max Curran7dbdea4d2023-03-21 23:47:37596 task_environment()->FastForwardBy(base::Milliseconds(20));
597
598 // The URL interceptor checks on the cookie copy status when trying to serve a
599 // prefetch. If its still in progress, it registers a callback to be called
600 // once the copy is complete.
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57601 EXPECT_TRUE(serving_handle.IsIsolatedCookieCopyInProgress());
602 serving_handle.OnInterceptorCheckCookieCopy();
Max Curran7dbdea4d2023-03-21 23:47:37603 task_environment()->FastForwardBy(base::Milliseconds(40));
604 bool callback_called = false;
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57605 serving_handle.SetOnCookieCopyCompleteCallback(
Max Curran7dbdea4d2023-03-21 23:47:37606 base::BindOnce([](bool* callback_called) { *callback_called = true; },
607 &callback_called));
608
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57609 serving_handle.OnIsolatedCookieCopyComplete();
Max Curran7dbdea4d2023-03-21 23:47:37610
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57611 EXPECT_FALSE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37612 EXPECT_TRUE(callback_called);
613
614 // Simulate copying cookies for the next redirect hop.
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57615 serving_handle.AdvanceCurrentURLToServe();
616 EXPECT_EQ(serving_handle.GetCurrentURLToServe(), kRedirectUrl1);
617 EXPECT_FALSE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37618
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57619 serving_handle.OnIsolatedCookieCopyStart();
620 EXPECT_TRUE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37621 task_environment()->FastForwardBy(base::Milliseconds(10));
622
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57623 serving_handle.OnIsolatedCookiesReadCompleteAndWriteStart();
Max Curran7dbdea4d2023-03-21 23:47:37624 task_environment()->FastForwardBy(base::Milliseconds(20));
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57625 EXPECT_TRUE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37626
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57627 serving_handle.OnInterceptorCheckCookieCopy();
Max Curran7dbdea4d2023-03-21 23:47:37628 task_environment()->FastForwardBy(base::Milliseconds(40));
629
630 callback_called = false;
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57631 serving_handle.SetOnCookieCopyCompleteCallback(
Max Curran7dbdea4d2023-03-21 23:47:37632 base::BindOnce([](bool* callback_called) { *callback_called = true; },
633 &callback_called));
634
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57635 serving_handle.OnIsolatedCookieCopyComplete();
636 EXPECT_FALSE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37637 EXPECT_TRUE(callback_called);
638
639 // Simulate copying cookies for the last redirect hop.
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57640 serving_handle.AdvanceCurrentURLToServe();
641 EXPECT_EQ(serving_handle.GetCurrentURLToServe(), kRedirectUrl2);
642 EXPECT_FALSE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37643
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57644 serving_handle.OnIsolatedCookieCopyStart();
645 EXPECT_TRUE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37646 task_environment()->FastForwardBy(base::Milliseconds(10));
647
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57648 serving_handle.OnIsolatedCookiesReadCompleteAndWriteStart();
Max Curran7dbdea4d2023-03-21 23:47:37649 task_environment()->FastForwardBy(base::Milliseconds(20));
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57650 EXPECT_TRUE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37651
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57652 serving_handle.OnInterceptorCheckCookieCopy();
Max Curran7dbdea4d2023-03-21 23:47:37653 task_environment()->FastForwardBy(base::Milliseconds(40));
654
655 callback_called = false;
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57656 serving_handle.SetOnCookieCopyCompleteCallback(
Max Curran7dbdea4d2023-03-21 23:47:37657 base::BindOnce([](bool* callback_called) { *callback_called = true; },
658 &callback_called));
659
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57660 serving_handle.OnIsolatedCookieCopyComplete();
661 EXPECT_FALSE(serving_handle.IsIsolatedCookieCopyInProgress());
Max Curran7dbdea4d2023-03-21 23:47:37662 EXPECT_TRUE(callback_called);
663
664 histogram_tester.ExpectUniqueTimeSample(
665 "PrefetchProxy.AfterClick.Mainframe.CookieReadTime",
666 base::Milliseconds(10), 3);
667 histogram_tester.ExpectUniqueTimeSample(
668 "PrefetchProxy.AfterClick.Mainframe.CookieWriteTime",
669 base::Milliseconds(60), 3);
670 histogram_tester.ExpectUniqueTimeSample(
671 "PrefetchProxy.AfterClick.Mainframe.CookieCopyStartToInterceptorCheck",
672 base::Milliseconds(30), 3);
673 histogram_tester.ExpectUniqueTimeSample(
674 "PrefetchProxy.AfterClick.Mainframe.CookieCopyTime",
675 base::Milliseconds(70), 3);
676}
677
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01678TEST_P(PrefetchContainerTest, PrefetchProxyPrefetchedResourceUkm) {
Max Curran210cffa2022-09-06 22:24:31679 ukm::TestAutoSetUkmRecorder ukm_recorder;
680
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35681 auto prefetch_container =
682 CreateSpeculationRulesPrefetchContainer(GURL("https://test.com"));
683
Hiroshige Hayashizaki64802cf12025-01-16 23:18:46684 prefetch_container->SimulatePrefetchEligibleForTest();
Max Curran210cffa2022-09-06 22:24:31685
686 network::URLLoaderCompletionStatus completion_status;
687 completion_status.encoded_data_length = 100;
688 completion_status.completion_time =
689 base::TimeTicks() + base::Milliseconds(200);
690
691 network::mojom::URLResponseHeadPtr head =
692 network::mojom::URLResponseHead::New();
693 head->load_timing.request_start = base::TimeTicks();
694
Hiroshige Hayashizaki036b8d62023-06-21 09:08:01695 MakeServableStreamingURLLoaderForTest(prefetch_container.get(),
Hiroshige Hayashizaki3c298a02025-07-08 22:55:34696 std::move(head), "test body",
697 std::move(completion_status));
Max Curran210cffa2022-09-06 22:24:31698
699 // Simulates the URL of the prefetch being navigated to and the prefetch being
700 // considered for serving.
Taiyo Mizuhashi09f571f2025-08-04 16:05:54701 prefetch_container->OnUnregisterCandidate(
702 GURL("https://test.com"),
703 /*is_served=*/true, PrefetchPotentialCandidateServingResult::kServed,
704 /*is_nav_prerender=*/false,
705 /*blocked_duration=*/std::nullopt);
Max Curran210cffa2022-09-06 22:24:31706
707 // Simulate a successful DNS probe for this prefetch. Not this will also
708 // update the status of the prefetch to
709 // |PrefetchStatus::kPrefetchUsedProbeSuccess|.
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:57710 prefetch_container->CreateServingHandle().OnPrefetchProbeResult(
Max Curran210cffa2022-09-06 22:24:31711 PrefetchProbeResult::kDNSProbeSuccess);
712
713 // Deleting the prefetch container will trigger the recording of the
714 // PrefetchProxy_PrefetchedResource UKM event.
715 prefetch_container.reset();
716
717 auto ukm_entries = ukm_recorder.GetEntries(
718 ukm::builders::PrefetchProxy_PrefetchedResource::kEntryName,
719 {
720 ukm::builders::PrefetchProxy_PrefetchedResource::kResourceTypeName,
721 ukm::builders::PrefetchProxy_PrefetchedResource::kStatusName,
722 ukm::builders::PrefetchProxy_PrefetchedResource::kLinkClickedName,
723 ukm::builders::PrefetchProxy_PrefetchedResource::kDataLengthName,
724 ukm::builders::PrefetchProxy_PrefetchedResource::kFetchDurationMSName,
725 ukm::builders::PrefetchProxy_PrefetchedResource::
726 kISPFilteringStatusName,
727 ukm::builders::PrefetchProxy_PrefetchedResource::
728 kNavigationStartToFetchStartMSName,
729 ukm::builders::PrefetchProxy_PrefetchedResource::kLinkPositionName,
730 });
731
732 ASSERT_EQ(ukm_entries.size(), 1U);
733 EXPECT_EQ(ukm_entries[0].source_id, ukm::kInvalidSourceId);
734
735 const auto& ukm_metrics = ukm_entries[0].metrics;
736
737 ASSERT_TRUE(
738 ukm_metrics.find(
739 ukm::builders::PrefetchProxy_PrefetchedResource::kResourceTypeName) !=
740 ukm_metrics.end());
741 EXPECT_EQ(
742 ukm_metrics.at(
743 ukm::builders::PrefetchProxy_PrefetchedResource::kResourceTypeName),
744 /*mainfrmae*/ 1);
745
746 ASSERT_TRUE(
747 ukm_metrics.find(
748 ukm::builders::PrefetchProxy_PrefetchedResource::kStatusName) !=
749 ukm_metrics.end());
750 EXPECT_EQ(ukm_metrics.at(
751 ukm::builders::PrefetchProxy_PrefetchedResource::kStatusName),
William Liu77089052022-12-15 18:53:35752 static_cast<int>(PrefetchStatus::kPrefetchResponseUsed));
Max Curran210cffa2022-09-06 22:24:31753
754 ASSERT_TRUE(
755 ukm_metrics.find(
756 ukm::builders::PrefetchProxy_PrefetchedResource::kLinkClickedName) !=
757 ukm_metrics.end());
758 EXPECT_EQ(
759 ukm_metrics.at(
760 ukm::builders::PrefetchProxy_PrefetchedResource::kLinkClickedName),
761 1);
762
763 ASSERT_TRUE(
764 ukm_metrics.find(
765 ukm::builders::PrefetchProxy_PrefetchedResource::kDataLengthName) !=
766 ukm_metrics.end());
767 EXPECT_EQ(
768 ukm_metrics.at(
769 ukm::builders::PrefetchProxy_PrefetchedResource::kDataLengthName),
770 ukm::GetExponentialBucketMinForBytes(100));
771
772 ASSERT_TRUE(ukm_metrics.find(ukm::builders::PrefetchProxy_PrefetchedResource::
773 kFetchDurationMSName) != ukm_metrics.end());
774 EXPECT_EQ(ukm_metrics.at(ukm::builders::PrefetchProxy_PrefetchedResource::
775 kFetchDurationMSName),
776 200);
777
778 ASSERT_TRUE(ukm_metrics.find(ukm::builders::PrefetchProxy_PrefetchedResource::
779 kISPFilteringStatusName) !=
780 ukm_metrics.end());
781 EXPECT_EQ(ukm_metrics.at(ukm::builders::PrefetchProxy_PrefetchedResource::
782 kISPFilteringStatusName),
783 static_cast<int>(PrefetchProbeResult::kDNSProbeSuccess));
784
785 // These fields are not set and should not be in the UKM event.
786 EXPECT_TRUE(ukm_metrics.find(ukm::builders::PrefetchProxy_PrefetchedResource::
787 kNavigationStartToFetchStartMSName) ==
788 ukm_metrics.end());
789 EXPECT_TRUE(
790 ukm_metrics.find(
791 ukm::builders::PrefetchProxy_PrefetchedResource::kLinkPositionName) ==
792 ukm_metrics.end());
793}
794
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01795TEST_P(PrefetchContainerTest, PrefetchProxyPrefetchedResourceUkm_NothingSet) {
Max Curran210cffa2022-09-06 22:24:31796 ukm::TestAutoSetUkmRecorder ukm_recorder;
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35797 auto prefetch_container =
798 CreateSpeculationRulesPrefetchContainer(GURL("https://test.com"));
Max Curran210cffa2022-09-06 22:24:31799 prefetch_container.reset();
800
801 auto ukm_entries = ukm_recorder.GetEntries(
802 ukm::builders::PrefetchProxy_PrefetchedResource::kEntryName,
803 {
804 ukm::builders::PrefetchProxy_PrefetchedResource::kResourceTypeName,
805 ukm::builders::PrefetchProxy_PrefetchedResource::kStatusName,
806 ukm::builders::PrefetchProxy_PrefetchedResource::kLinkClickedName,
807 ukm::builders::PrefetchProxy_PrefetchedResource::kDataLengthName,
808 ukm::builders::PrefetchProxy_PrefetchedResource::kFetchDurationMSName,
809 ukm::builders::PrefetchProxy_PrefetchedResource::
810 kISPFilteringStatusName,
811 });
812
813 ASSERT_EQ(ukm_entries.size(), 1U);
814 EXPECT_EQ(ukm_entries[0].source_id, ukm::kInvalidSourceId);
815
816 const auto& ukm_metrics = ukm_entries[0].metrics;
817 ASSERT_TRUE(
818 ukm_metrics.find(
819 ukm::builders::PrefetchProxy_PrefetchedResource::kResourceTypeName) !=
820 ukm_metrics.end());
821 EXPECT_EQ(
822 ukm_metrics.at(
823 ukm::builders::PrefetchProxy_PrefetchedResource::kResourceTypeName),
824 /*mainfrmae*/ 1);
825
826 ASSERT_TRUE(
827 ukm_metrics.find(
828 ukm::builders::PrefetchProxy_PrefetchedResource::kStatusName) !=
829 ukm_metrics.end());
830 EXPECT_EQ(ukm_metrics.at(
831 ukm::builders::PrefetchProxy_PrefetchedResource::kStatusName),
832 static_cast<int>(PrefetchStatus::kPrefetchNotStarted));
833
834 ASSERT_TRUE(
835 ukm_metrics.find(
836 ukm::builders::PrefetchProxy_PrefetchedResource::kLinkClickedName) !=
837 ukm_metrics.end());
838 EXPECT_EQ(
839 ukm_metrics.at(
840 ukm::builders::PrefetchProxy_PrefetchedResource::kLinkClickedName),
841 0);
842
843 EXPECT_TRUE(
844 ukm_metrics.find(
845 ukm::builders::PrefetchProxy_PrefetchedResource::kDataLengthName) ==
846 ukm_metrics.end());
847 EXPECT_TRUE(ukm_metrics.find(ukm::builders::PrefetchProxy_PrefetchedResource::
848 kFetchDurationMSName) == ukm_metrics.end());
849 EXPECT_TRUE(ukm_metrics.find(ukm::builders::PrefetchProxy_PrefetchedResource::
850 kISPFilteringStatusName) ==
851 ukm_metrics.end());
852}
853
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01854TEST_P(PrefetchContainerTest, EligibilityCheck) {
Max Curran5d4da4b42023-03-10 23:41:46855 const GURL kTestUrl1 = GURL("https://test1.com");
856 const GURL kTestUrl2 = GURL("https://test2.com");
857
858 base::HistogramTester histogram_tester;
859
860 auto* prefetch_document_manager =
861 PrefetchDocumentManager::GetOrCreateForCurrentDocument(
862 &web_contents()->GetPrimaryPage().GetMainDocument());
863
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35864 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(
HuanPo Lin740620b2025-03-21 12:37:26865 kTestUrl1,
866 {.prefetch_document_manager = prefetch_document_manager->GetWeakPtr()});
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35867
868 prefetch_container->MakeResourceRequest({});
Max Curran5d4da4b42023-03-10 23:41:46869
870 // Mark initial prefetch as eligible
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35871 prefetch_container->OnEligibilityCheckComplete(
Hiroshige Hayashizaki939c5ed42023-11-01 03:29:21872 PreloadingEligibility::kEligible);
Max Curran5d4da4b42023-03-10 23:41:46873
874 EXPECT_EQ(prefetch_document_manager->GetReferringPageMetrics()
875 .prefetch_eligible_count,
876 1);
877
878 // Add a redirect, register a callback for it, and then mark it as eligible.
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35879 AddRedirectHop(prefetch_container.get(), kTestUrl2);
880 prefetch_container->OnEligibilityCheckComplete(
Hiroshige Hayashizaki939c5ed42023-11-01 03:29:21881 PreloadingEligibility::kEligible);
Max Curran5d4da4b42023-03-10 23:41:46882
883 // Referring page metrics is only incremented for the original prefetch URL
884 // and not any redirects.
885 EXPECT_EQ(prefetch_document_manager->GetReferringPageMetrics()
886 .prefetch_eligible_count,
887 1);
888}
889
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01890TEST_P(PrefetchContainerTest, IneligibleRedirect) {
Max Curran5d4da4b42023-03-10 23:41:46891 const GURL kTestUrl1 = GURL("https://test1.com");
892 const GURL kTestUrl2 = GURL("https://test2.com");
893
894 base::HistogramTester histogram_tester;
895
896 auto* prefetch_document_manager =
897 PrefetchDocumentManager::GetOrCreateForCurrentDocument(
898 &web_contents()->GetPrimaryPage().GetMainDocument());
899
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35900 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(
HuanPo Lin740620b2025-03-21 12:37:26901 kTestUrl1,
902 {.prefetch_document_manager = prefetch_document_manager->GetWeakPtr()});
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35903
904 prefetch_container->MakeResourceRequest({});
Max Curran5d4da4b42023-03-10 23:41:46905
906 // Mark initial prefetch as eligible
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35907 prefetch_container->OnEligibilityCheckComplete(
Hiroshige Hayashizaki939c5ed42023-11-01 03:29:21908 PreloadingEligibility::kEligible);
Max Curran5d4da4b42023-03-10 23:41:46909
910 EXPECT_EQ(prefetch_document_manager->GetReferringPageMetrics()
911 .prefetch_eligible_count,
912 1);
913
914 // Add a redirect, register a callback for it, and then mark it as ineligible.
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35915 AddRedirectHop(prefetch_container.get(), kTestUrl2);
916 prefetch_container->OnEligibilityCheckComplete(
Hiroshige Hayashizaki939c5ed42023-11-01 03:29:21917 PreloadingEligibility::kUserHasCookies);
Max Curran5d4da4b42023-03-10 23:41:46918
919 // Ineligible redirects are treated as failed prefetches, and not ineligible
920 // prefetches.
921 EXPECT_EQ(prefetch_document_manager->GetReferringPageMetrics()
922 .prefetch_eligible_count,
923 1);
Taiyo Mizuhashifb547bdf2024-03-11 15:18:35924 EXPECT_EQ(prefetch_container->GetPrefetchStatus(),
Max Curran5d4da4b42023-03-10 23:41:46925 PrefetchStatus::kPrefetchFailedIneligibleRedirect);
926}
927
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:01928TEST_P(PrefetchContainerTest, BlockUntilHeadHistograms) {
kenossf6fbd5652024-09-04 00:40:28929 struct TestCase {
Taiyo Mizuhashi43066071f2025-04-25 23:40:22930 PrefetchType prefetch_type;
kenossf6fbd5652024-09-04 00:40:28931 bool is_served;
kenoss4bdf2d82025-05-27 01:58:45932 bool is_nav_prerender;
933 std::optional<base::TimeDelta> blocked_duration;
kenossf6fbd5652024-09-04 00:40:28934 };
935
936 std::vector<TestCase> test_cases{
kenoss4bdf2d82025-05-27 01:58:45937 {
938 .prefetch_type =
939 PrefetchType(PreloadingTriggerType::kSpeculationRule,
940 /*use_prefetch_proxy=*/true,
Takashi Nakayama978f0a152025-06-17 08:26:25941 blink::mojom::SpeculationEagerness::kImmediate),
kenoss4bdf2d82025-05-27 01:58:45942 .is_served = true,
943 .is_nav_prerender = false,
944 .blocked_duration = std::nullopt,
945 },
946 {
947 .prefetch_type =
948 PrefetchType(PreloadingTriggerType::kSpeculationRule,
949 /*use_prefetch_proxy=*/true,
Takashi Nakayamac8183502025-08-04 14:18:50950 blink::mojom::SpeculationEagerness::kEager),
951 .is_served = true,
952 .is_nav_prerender = false,
953 .blocked_duration = base::Milliseconds(10),
954 },
955 {
956 .prefetch_type =
957 PrefetchType(PreloadingTriggerType::kSpeculationRule,
958 /*use_prefetch_proxy=*/true,
kenoss4bdf2d82025-05-27 01:58:45959 blink::mojom::SpeculationEagerness::kModerate),
960 .is_served = true,
961 .is_nav_prerender = false,
962 .blocked_duration = base::Milliseconds(10),
963 },
964 {
965 .prefetch_type =
966 PrefetchType(PreloadingTriggerType::kSpeculationRule,
967 /*use_prefetch_proxy=*/true,
968 blink::mojom::SpeculationEagerness::kConservative),
969 .is_served = false,
970 .is_nav_prerender = false,
971 .blocked_duration = std::nullopt,
972 },
973 {.prefetch_type = PrefetchType(PreloadingTriggerType::kEmbedder,
974 /*use_prefetch_proxy=*/true),
975 .is_served = false,
976 .is_nav_prerender = false,
977 .blocked_duration = base::Milliseconds(20)},
978 };
Taiyo Mizuhashi43066071f2025-04-25 23:40:22979
Takashi Nakayamac8183502025-08-04 14:18:50980 const GURL prefetch_url = GURL("https://test.example/?nvsparam=1");
981 const GURL navigated_url = GURL("https://test.example/");
kenossf6fbd5652024-09-04 00:40:28982
983 base::HistogramTester histogram_tester;
984 for (const auto& test_case : test_cases) {
Taiyo Mizuhashi43066071f2025-04-25 23:40:22985 auto prefetch_container = [&] {
986 if (test_case.prefetch_type.IsRendererInitiated()) {
987 return CreateSpeculationRulesPrefetchContainer(
988 prefetch_url,
989 {.eagerness = test_case.prefetch_type.GetEagerness()});
990 } else {
991 return CreateEmbedderPrefetchContainer(prefetch_url);
992 }
993 }();
kenossf6fbd5652024-09-04 00:40:28994
Taiyo Mizuhashi09f571f2025-08-04 16:05:54995 // For `PrefetchPotentialCandidateServingResult`, provides placeholder value
996 // which is consistent with `is_served`.
Taiyo Mizuhashi43066071f2025-04-25 23:40:22997 prefetch_container->OnUnregisterCandidate(
Taiyo Mizuhashi09f571f2025-08-04 16:05:54998 navigated_url, test_case.is_served,
999 test_case.is_served ? PrefetchPotentialCandidateServingResult::kServed
1000 : PrefetchPotentialCandidateServingResult::
1001 kNotServedBlockUntilHeadTimeout,
1002 test_case.is_nav_prerender, test_case.blocked_duration);
kenossf6fbd5652024-09-04 00:40:281003 }
1004
kenoss4bdf2d82025-05-27 01:58:451005 histogram_tester.ExpectUniqueSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221006 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
Takashi Nakayamac8183502025-08-04 14:18:501007 "SpeculationRule_Immediate2",
kenossf6fbd5652024-09-04 00:40:281008 false, 1);
kenoss4bdf2d82025-05-27 01:58:451009 histogram_tester.ExpectUniqueSample(
1010 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
Takashi Nakayamac8183502025-08-04 14:18:501011 "NonPrerender.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451012 false, 1);
1013 histogram_tester.ExpectTotalCount(
1014 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
Takashi Nakayamac8183502025-08-04 14:18:501015 "Prerender.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451016 0);
kenoss53a777ea2024-11-14 07:39:381017 histogram_tester.ExpectUniqueTimeSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221018 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served."
Takashi Nakayamac8183502025-08-04 14:18:501019 "SpeculationRule_Immediate2",
kenoss53a777ea2024-11-14 07:39:381020 base::Milliseconds(0), 1);
1021 histogram_tester.ExpectTotalCount(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221022 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed."
Takashi Nakayamac8183502025-08-04 14:18:501023 "SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451024 0);
1025 histogram_tester.ExpectUniqueTimeSample(
1026 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
Takashi Nakayamac8183502025-08-04 14:18:501027 "Served.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451028 base::Milliseconds(0), 1);
1029 histogram_tester.ExpectTotalCount(
1030 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
Takashi Nakayamac8183502025-08-04 14:18:501031 "NotServed.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451032 0);
1033 histogram_tester.ExpectTotalCount(
1034 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender.Served."
Takashi Nakayamac8183502025-08-04 14:18:501035 "SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451036 0);
1037 histogram_tester.ExpectTotalCount(
1038 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender."
Takashi Nakayamac8183502025-08-04 14:18:501039 "NotServed.SpeculationRule_Immediate2",
kenoss53a777ea2024-11-14 07:39:381040 0);
kenossf6fbd5652024-09-04 00:40:281041
kenoss4bdf2d82025-05-27 01:58:451042 histogram_tester.ExpectUniqueSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221043 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
Takashi Nakayamac8183502025-08-04 14:18:501044 "SpeculationRule_Eager2",
1045 true, 1);
1046 histogram_tester.ExpectUniqueSample(
1047 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
kenoss4bdf2d82025-05-27 01:58:451048 "SpeculationRule_Moderate",
kenossf6fbd5652024-09-04 00:40:281049 true, 1);
kenoss4bdf2d82025-05-27 01:58:451050 histogram_tester.ExpectUniqueSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221051 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
Takashi Nakayamac8183502025-08-04 14:18:501052 "NonPrerender.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451053 false, 1);
Takashi Nakayamac8183502025-08-04 14:18:501054
1055 histogram_tester.ExpectTotalCount(
1056 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
1057 "Prerender.SpeculationRule_Eager2",
1058 0);
1059 histogram_tester.ExpectUniqueTimeSample(
1060 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served."
1061 "SpeculationRule_Eager2",
1062 base::Milliseconds(10), 1);
1063 histogram_tester.ExpectTotalCount(
1064 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed."
1065 "SpeculationRule_Eager2",
1066 0);
1067 histogram_tester.ExpectUniqueTimeSample(
1068 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
1069 "Served.SpeculationRule_Eager2",
1070 base::Milliseconds(10), 1);
1071 histogram_tester.ExpectTotalCount(
1072 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
1073 "NotServed.SpeculationRule_Eager2",
1074 0);
1075 histogram_tester.ExpectTotalCount(
1076 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender.Served."
1077 "SpeculationRule_Eager2",
1078 0);
1079 histogram_tester.ExpectTotalCount(
1080 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender."
1081 "NotServed.SpeculationRule_Eager2",
1082 0);
1083
kenoss4bdf2d82025-05-27 01:58:451084 histogram_tester.ExpectTotalCount(
1085 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
1086 "Prerender.SpeculationRule_Moderate",
1087 0);
kenossf6fbd5652024-09-04 00:40:281088 histogram_tester.ExpectUniqueTimeSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221089 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served."
kenoss4bdf2d82025-05-27 01:58:451090 "SpeculationRule_Moderate",
kenoss53a777ea2024-11-14 07:39:381091 base::Milliseconds(10), 1);
1092 histogram_tester.ExpectTotalCount(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221093 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed."
kenoss4bdf2d82025-05-27 01:58:451094 "SpeculationRule_Moderate",
1095 0);
1096 histogram_tester.ExpectUniqueTimeSample(
1097 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
1098 "Served.SpeculationRule_Moderate",
1099 base::Milliseconds(10), 1);
1100 histogram_tester.ExpectTotalCount(
1101 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
1102 "NotServed.SpeculationRule_Moderate",
1103 0);
1104 histogram_tester.ExpectTotalCount(
1105 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender.Served."
1106 "SpeculationRule_Moderate",
1107 0);
1108 histogram_tester.ExpectTotalCount(
1109 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender."
1110 "NotServed.SpeculationRule_Moderate",
kenoss53a777ea2024-11-14 07:39:381111 0);
kenossf6fbd5652024-09-04 00:40:281112
kenoss4bdf2d82025-05-27 01:58:451113 histogram_tester.ExpectUniqueSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221114 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
kenoss4bdf2d82025-05-27 01:58:451115 "SpeculationRule_Conservative",
1116 false, 1);
1117 histogram_tester.ExpectUniqueSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221118 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
kenoss4bdf2d82025-05-27 01:58:451119 "NonPrerender.SpeculationRule_Conservative",
Taiyo Mizuhashi43066071f2025-04-25 23:40:221120 false, 1);
1121 histogram_tester.ExpectTotalCount(
kenoss4bdf2d82025-05-27 01:58:451122 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
1123 "Prerender.SpeculationRule_Conservative",
1124 0);
1125 histogram_tester.ExpectTotalCount(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221126 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served."
kenoss4bdf2d82025-05-27 01:58:451127 "SpeculationRule_Conservative",
Taiyo Mizuhashi43066071f2025-04-25 23:40:221128 0);
1129 histogram_tester.ExpectUniqueTimeSample(
1130 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed."
kenoss4bdf2d82025-05-27 01:58:451131 "SpeculationRule_Conservative",
Taiyo Mizuhashi43066071f2025-04-25 23:40:221132 base::Milliseconds(0), 1);
kenoss4bdf2d82025-05-27 01:58:451133 histogram_tester.ExpectTotalCount(
1134 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
1135 "Served.SpeculationRule_Conservative",
1136 0);
1137 histogram_tester.ExpectUniqueTimeSample(
1138 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
1139 "NotServed.SpeculationRule_Conservative",
1140 base::Milliseconds(0), 1);
1141 histogram_tester.ExpectTotalCount(
1142 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender.Served."
1143 "SpeculationRule_Conservative",
1144 0);
1145 histogram_tester.ExpectTotalCount(
1146 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender."
1147 "NotServed.SpeculationRule_Conservative",
1148 0);
Taiyo Mizuhashi43066071f2025-04-25 23:40:221149
kenoss4bdf2d82025-05-27 01:58:451150 histogram_tester.ExpectUniqueSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221151 base::StrCat({"Prefetch.PrefetchMatchingBlockedNavigation."
1152 "PerMatchingCandidate.Embedder_",
1153 test::kPreloadingEmbedderHistgramSuffixForTesting}),
kenossf6fbd5652024-09-04 00:40:281154 true, 1);
kenoss4bdf2d82025-05-27 01:58:451155 histogram_tester.ExpectTotalCount(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221156 base::StrCat({"Prefetch.PrefetchMatchingBlockedNavigation."
kenoss4bdf2d82025-05-27 01:58:451157 "PerMatchingCandidate.Prerender.Embedder_",
Taiyo Mizuhashi43066071f2025-04-25 23:40:221158 test::kPreloadingEmbedderHistgramSuffixForTesting}),
kenoss4bdf2d82025-05-27 01:58:451159 0);
kenossf6fbd5652024-09-04 00:40:281160 histogram_tester.ExpectTotalCount(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221161 base::StrCat({"Prefetch.BlockUntilHeadDuration.PerMatchingCandidate."
1162 "Served.Embedder_",
1163 test::kPreloadingEmbedderHistgramSuffixForTesting}),
kenoss53a777ea2024-11-14 07:39:381164 0);
1165 histogram_tester.ExpectUniqueTimeSample(
Taiyo Mizuhashi43066071f2025-04-25 23:40:221166 base::StrCat({"Prefetch.BlockUntilHeadDuration.PerMatchingCandidate."
1167 "NotServed.Embedder_",
1168 test::kPreloadingEmbedderHistgramSuffixForTesting}),
kenossf6fbd5652024-09-04 00:40:281169 base::Milliseconds(20), 1);
kenoss4bdf2d82025-05-27 01:58:451170 histogram_tester.ExpectTotalCount(
1171 base::StrCat({"Prefetch.BlockUntilHeadDuration.PerMatchingCandidate."
1172 "NonPrerender.Served.Embedder_",
1173 test::kPreloadingEmbedderHistgramSuffixForTesting}),
1174 0);
1175 histogram_tester.ExpectUniqueTimeSample(
1176 base::StrCat({"Prefetch.BlockUntilHeadDuration.PerMatchingCandidate."
1177 "NonPrerender.NotServed.Embedder_",
1178 test::kPreloadingEmbedderHistgramSuffixForTesting}),
1179 base::Milliseconds(20), 1);
1180 histogram_tester.ExpectTotalCount(
1181 base::StrCat({"Prefetch.BlockUntilHeadDuration.PerMatchingCandidate."
1182 "Prerender.Served.Embedder_",
1183 test::kPreloadingEmbedderHistgramSuffixForTesting}),
1184 0);
1185 histogram_tester.ExpectTotalCount(
1186 base::StrCat({"Prefetch.BlockUntilHeadDuration.PerMatchingCandidate."
1187 "Prerender.NotServed.Embedder_",
1188 test::kPreloadingEmbedderHistgramSuffixForTesting}),
1189 0);
1190}
1191
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011192TEST_P(PrefetchContainerTest, BlockUntilHeadHistograms_Prerender) {
kenoss4bdf2d82025-05-27 01:58:451193 struct TestCase {
1194 PrefetchType prefetch_type;
1195 bool is_served;
1196 bool is_nav_prerender;
1197 std::optional<base::TimeDelta> blocked_duration;
1198 };
1199
1200 TestCase test_case = {
Takashi Nakayama978f0a152025-06-17 08:26:251201 .prefetch_type =
1202 PrefetchType(PreloadingTriggerType::kSpeculationRule,
1203 /*use_prefetch_proxy=*/true,
1204 blink::mojom::SpeculationEagerness::kImmediate),
kenoss4bdf2d82025-05-27 01:58:451205 .is_served = true,
1206 .is_nav_prerender = true,
1207 .blocked_duration = base::Milliseconds(100),
1208 };
1209
1210 base::HistogramTester histogram_tester;
1211 const GURL prefetch_url = GURL("https://test.com/?nvsparam=1");
1212 const GURL navigated_url = GURL("https://test.com/");
1213
1214 auto prefetch_container = [&] {
1215 if (test_case.prefetch_type.IsRendererInitiated()) {
1216 return CreateSpeculationRulesPrefetchContainer(
1217 prefetch_url, {.eagerness = test_case.prefetch_type.GetEagerness()});
1218 } else {
1219 return CreateEmbedderPrefetchContainer(prefetch_url);
1220 }
1221 }();
1222
Taiyo Mizuhashi09f571f2025-08-04 16:05:541223 // For `PrefetchPotentialCandidateServingResult`, provides placeholder value
1224 // which is consistent with `is_served`.
1225 prefetch_container->OnUnregisterCandidate(
1226 navigated_url, test_case.is_served,
1227 test_case.is_served ? PrefetchPotentialCandidateServingResult::kServed
1228 : PrefetchPotentialCandidateServingResult::
1229 kNotServedBlockUntilHeadTimeout,
1230 test_case.is_nav_prerender, test_case.blocked_duration);
kenoss4bdf2d82025-05-27 01:58:451231
1232 histogram_tester.ExpectUniqueSample(
1233 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
Takashi Nakayamac8183502025-08-04 14:18:501234 "SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451235 true, 1);
1236 histogram_tester.ExpectTotalCount(
1237 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
Takashi Nakayamac8183502025-08-04 14:18:501238 "NonPrerender.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451239 0);
1240 histogram_tester.ExpectUniqueSample(
1241 "Prefetch.PrefetchMatchingBlockedNavigation.PerMatchingCandidate."
Takashi Nakayamac8183502025-08-04 14:18:501242 "Prerender.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451243 true, 1);
1244 histogram_tester.ExpectUniqueTimeSample(
1245 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Served."
Takashi Nakayamac8183502025-08-04 14:18:501246 "SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451247 test_case.blocked_duration.value_or(base::Seconds(0)), 1);
1248 histogram_tester.ExpectTotalCount(
1249 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NotServed."
Takashi Nakayamac8183502025-08-04 14:18:501250 "SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451251 0);
1252 histogram_tester.ExpectTotalCount(
1253 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
Takashi Nakayamac8183502025-08-04 14:18:501254 "Served.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451255 0);
1256 histogram_tester.ExpectTotalCount(
1257 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.NonPrerender."
Takashi Nakayamac8183502025-08-04 14:18:501258 "NotServed.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451259 0);
1260 histogram_tester.ExpectUniqueTimeSample(
1261 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender.Served."
Takashi Nakayamac8183502025-08-04 14:18:501262 "SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451263 test_case.blocked_duration.value_or(base::Seconds(0)), 1);
1264 histogram_tester.ExpectTotalCount(
1265 "Prefetch.BlockUntilHeadDuration.PerMatchingCandidate.Prerender."
Takashi Nakayamac8183502025-08-04 14:18:501266 "NotServed.SpeculationRule_Immediate2",
kenoss4bdf2d82025-05-27 01:58:451267 0);
kenossf6fbd5652024-09-04 00:40:281268}
1269
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011270TEST_P(PrefetchContainerTest, RecordRedirectChainSize) {
Max Curran7d2578b2023-04-12 19:19:281271 base::HistogramTester histogram_tester;
1272
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351273 auto prefetch_container =
1274 CreateSpeculationRulesPrefetchContainer(GURL("https://test.com"));
1275 prefetch_container->MakeResourceRequest({});
Max Curran7d2578b2023-04-12 19:19:281276
Hiroshige Hayashizaki6b7035c02025-07-18 21:06:321277 prefetch_container->SimulatePrefetchEligibleForTest();
1278 prefetch_container->SimulatePrefetchStartedForTest();
Hiroshige Hayashizaki77083bc82023-11-28 06:04:171279
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351280 AddRedirectHop(prefetch_container.get(), GURL("https://redirect1.com"));
1281 AddRedirectHop(prefetch_container.get(), GURL("https://redirect2.com"));
Hiroshige Hayashizaki6b7035c02025-07-18 21:06:321282 prefetch_container->OnDeterminedHead();
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351283 prefetch_container->OnPrefetchComplete(network::URLLoaderCompletionStatus());
Max Curran7d2578b2023-04-12 19:19:281284
1285 histogram_tester.ExpectUniqueSample(
1286 "PrefetchProxy.Prefetch.RedirectChainSize", 3, 1);
1287}
1288
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011289TEST_P(PrefetchContainerTest, IsIsolatedNetworkRequired) {
Kevin McNee06824c72024-02-06 18:59:521290 NavigationSimulator::NavigateAndCommitFromBrowser(
1291 web_contents(), GURL("https://test.com/referrer"));
Taiyo Mizuhashi1b23ca62024-03-28 22:07:371292 auto prefetch_container_same_origin = CreateSpeculationRulesPrefetchContainer(
1293 GURL("https://test.com/prefetch"));
1294 prefetch_container_same_origin->MakeResourceRequest({});
1295 EXPECT_FALSE(prefetch_container_same_origin
1296 ->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
1297
1298 NavigationSimulator::NavigateAndCommitFromBrowser(
1299 web_contents(), GURL("https://other.com/referrer"));
1300 auto prefetch_container_cross_origin =
1301 CreateSpeculationRulesPrefetchContainer(
1302 GURL("https://test.com/prefetch"));
1303 prefetch_container_cross_origin->MakeResourceRequest({});
1304 EXPECT_TRUE(prefetch_container_cross_origin
1305 ->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
1306}
1307
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011308TEST_P(PrefetchContainerTest, IsIsolatedNetworkRequired_Embedder) {
Taiyo Mizuhashi1b23ca62024-03-28 22:07:371309 auto prefetch_container_default = CreateEmbedderPrefetchContainer(
1310 GURL("https://test.com/prefetch"), std::nullopt);
1311 prefetch_container_default->MakeResourceRequest({});
Taiyo Mizuhashi9dfeb632024-10-24 08:44:201312 EXPECT_FALSE(prefetch_container_default
1313 ->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
Taiyo Mizuhashi1b23ca62024-03-28 22:07:371314
1315 auto prefetch_container_same_origin = CreateEmbedderPrefetchContainer(
1316 GURL("https://test.com/prefetch"),
1317 url::Origin::Create(GURL("https://test.com/referrer")));
1318 prefetch_container_same_origin->MakeResourceRequest({});
1319 EXPECT_FALSE(prefetch_container_same_origin
1320 ->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
1321
1322 auto prefetch_container_cross_origin = CreateEmbedderPrefetchContainer(
1323 GURL("https://test.com/prefetch"),
1324 url::Origin::Create(GURL("https://other.com/referrer")));
1325 prefetch_container_cross_origin->MakeResourceRequest({});
1326 EXPECT_TRUE(prefetch_container_cross_origin
1327 ->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
1328}
1329
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011330TEST_P(PrefetchContainerTest, IsIsolatedNetworkRequiredWithRedirect) {
Taiyo Mizuhashi1b23ca62024-03-28 22:07:371331 NavigationSimulator::NavigateAndCommitFromBrowser(
1332 web_contents(), GURL("https://test.com/referrer"));
Max Curran48700962023-05-15 18:35:521333
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351334 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(
1335 GURL("https://test.com/prefetch"));
1336
1337 prefetch_container->MakeResourceRequest({});
Max Curran48700962023-05-15 18:35:521338
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581339 EXPECT_FALSE(
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351340 prefetch_container->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581341
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351342 AddRedirectHop(prefetch_container.get(), GURL("https://test.com/redirect"));
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581343
1344 EXPECT_FALSE(
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351345 prefetch_container->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581346 EXPECT_FALSE(prefetch_container
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351347 ->IsIsolatedNetworkContextRequiredForPreviousRedirectHop());
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581348
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351349 AddRedirectHop(prefetch_container.get(), GURL("https://m.test.com/redirect"));
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581350
1351 EXPECT_FALSE(
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351352 prefetch_container->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581353 EXPECT_FALSE(prefetch_container
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351354 ->IsIsolatedNetworkContextRequiredForPreviousRedirectHop());
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581355
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351356 AddRedirectHop(prefetch_container.get(), GURL("https://other.com/redirect1"));
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581357
1358 EXPECT_TRUE(
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351359 prefetch_container->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581360 EXPECT_FALSE(prefetch_container
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351361 ->IsIsolatedNetworkContextRequiredForPreviousRedirectHop());
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581362
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351363 AddRedirectHop(prefetch_container.get(), GURL("https://other.com/redirect2"));
Max Curran48700962023-05-15 18:35:521364
Max Curran48700962023-05-15 18:35:521365 EXPECT_TRUE(
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351366 prefetch_container->IsIsolatedNetworkContextRequiredForCurrentPrefetch());
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:581367 EXPECT_TRUE(prefetch_container
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351368 ->IsIsolatedNetworkContextRequiredForPreviousRedirectHop());
Max Curran48700962023-05-15 18:35:521369}
1370
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011371TEST_P(PrefetchContainerTest, MultipleStreamingURLLoaders) {
Max Currana84311e2023-05-16 20:40:251372 const GURL kTestUrl1 = GURL("https://test1.com");
1373 const GURL kTestUrl2 = GURL("https://test2.com");
1374
1375 base::HistogramTester histogram_tester;
1376
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351377 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(kTestUrl1);
1378
Jeremy Roman45c89d012023-08-30 21:22:021379 prefetch_container->MakeResourceRequest({});
Max Currana84311e2023-05-16 20:40:251380
Hiroshige Hayashizaki5c50ec52023-09-13 00:35:491381 EXPECT_FALSE(prefetch_container->GetStreamingURLLoader());
Max Currana84311e2023-05-16 20:40:251382
Hiroshige Hayashizakie556eb02023-09-13 00:20:481383 EXPECT_NE(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081384 PrefetchServableState::kServable);
kenossf7b4d60d2024-07-16 15:15:081385 EXPECT_FALSE(prefetch_container->GetNonRedirectHead());
Max Currana84311e2023-05-16 20:40:251386
Hiroshige Hayashizaki64802cf12025-01-16 23:18:461387 prefetch_container->SimulatePrefetchEligibleForTest();
Hiroshige Hayashizaki638018f2023-09-12 17:05:451388 MakeServableStreamingURLLoadersWithNetworkTransitionRedirectForTest(
1389 prefetch_container.get(), kTestUrl1, kTestUrl2);
Hiroshige Hayashizakie556eb02023-09-13 00:20:481390 EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081391 PrefetchServableState::kServable);
kenossf7b4d60d2024-07-16 15:15:081392 EXPECT_TRUE(prefetch_container->GetNonRedirectHead());
Max Currana84311e2023-05-16 20:40:251393
Hiroshige Hayashizaki638018f2023-09-12 17:05:451394 // As the prefetch is already completed, the streaming loader is deleted
1395 // asynchronously.
Hiroshige Hayashizaki5c50ec52023-09-13 00:35:491396 EXPECT_TRUE(
1397 prefetch_container->IsStreamingURLLoaderDeletionScheduledForTesting());
Hiroshige Hayashizakib6a84d992023-10-02 17:57:541398 task_environment()->RunUntilIdle();
Hiroshige Hayashizaki638018f2023-09-12 17:05:451399 EXPECT_FALSE(prefetch_container->GetStreamingURLLoader());
1400
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571401 PrefetchServingHandle serving_handle =
1402 prefetch_container->CreateServingHandle();
Hiroshige Hayashizaki00b3f002023-07-15 00:32:481403
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391404 base::WeakPtr<PrefetchResponseReader> weak_first_response_reader =
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571405 serving_handle.GetCurrentResponseReaderToServeForTesting();
Hiroshige Hayashizaki055871f22025-03-14 03:27:381406 PrefetchRequestHandler first_request_handler =
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571407 serving_handle.CreateRequestHandler().first;
Max Currana84311e2023-05-16 20:40:251408
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391409 base::WeakPtr<PrefetchResponseReader> weak_second_response_reader =
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571410 serving_handle.GetCurrentResponseReaderToServeForTesting();
Hiroshige Hayashizaki055871f22025-03-14 03:27:381411 PrefetchRequestHandler second_request_handler =
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571412 serving_handle.CreateRequestHandler().first;
Hiroshige Hayashizakib23142452023-06-21 03:01:141413
Hiroshige Hayashizaki638018f2023-09-12 17:05:451414 // `CreateRequestHandler()` itself doesn't make the PrefetchContainer
1415 // non-servable.
Hiroshige Hayashizakie556eb02023-09-13 00:20:481416 EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081417 PrefetchServableState::kServable);
kenossf7b4d60d2024-07-16 15:15:081418 EXPECT_TRUE(prefetch_container->GetNonRedirectHead());
Hiroshige Hayashizakib23142452023-06-21 03:01:141419
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391420 std::unique_ptr<PrefetchTestURLLoaderClient> first_serving_url_loader_client =
1421 std::make_unique<PrefetchTestURLLoaderClient>();
1422 network::ResourceRequest first_serving_request;
1423 first_serving_request.url = kTestUrl1;
1424 first_serving_request.method = "GET";
1425
1426 std::move(first_request_handler)
1427 .Run(first_serving_request,
1428 first_serving_url_loader_client->BindURLloaderAndGetReceiver(),
1429 first_serving_url_loader_client->BindURLLoaderClientAndGetRemote());
1430
1431 std::unique_ptr<PrefetchTestURLLoaderClient>
1432 second_serving_url_loader_client =
1433 std::make_unique<PrefetchTestURLLoaderClient>();
1434 network::ResourceRequest second_serving_request;
1435 second_serving_request.url = kTestUrl2;
1436 second_serving_request.method = "GET";
1437
1438 std::move(second_request_handler)
1439 .Run(second_serving_request,
1440 second_serving_url_loader_client->BindURLloaderAndGetReceiver(),
1441 second_serving_url_loader_client->BindURLLoaderClientAndGetRemote());
1442
1443 prefetch_container.reset();
1444
Hiroshige Hayashizakib6a84d992023-10-02 17:57:541445 task_environment()->RunUntilIdle();
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391446
1447 EXPECT_EQ(first_serving_url_loader_client->received_redirects().size(), 1u);
1448
1449 EXPECT_EQ(second_serving_url_loader_client->body_content(), "test body");
1450 EXPECT_TRUE(
1451 second_serving_url_loader_client->completion_status().has_value());
1452
1453 EXPECT_TRUE(weak_first_response_reader);
1454 EXPECT_TRUE(weak_second_response_reader);
1455
1456 first_serving_url_loader_client->DisconnectMojoPipes();
1457 second_serving_url_loader_client->DisconnectMojoPipes();
Hiroshige Hayashizakib6a84d992023-10-02 17:57:541458 task_environment()->RunUntilIdle();
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391459
1460 EXPECT_FALSE(weak_first_response_reader);
1461 EXPECT_FALSE(weak_second_response_reader);
Max Currana84311e2023-05-16 20:40:251462}
1463
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011464TEST_P(PrefetchContainerTest, CancelAndClearStreamingLoader) {
Max Currana84311e2023-05-16 20:40:251465 const GURL kTestUrl1 = GURL("https://test1.com");
1466 const GURL kTestUrl2 = GURL("https://test2.com");
1467
1468 base::HistogramTester histogram_tester;
1469
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351470 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(kTestUrl1);
1471
1472 prefetch_container->MakeResourceRequest({});
Max Currana84311e2023-05-16 20:40:251473
Hiroshige Hayashizaki64802cf12025-01-16 23:18:461474 prefetch_container->SimulatePrefetchEligibleForTest();
Hiroshige Hayashizaki638018f2023-09-12 17:05:451475 auto pending_request =
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351476 MakeManuallyServableStreamingURLLoaderForTest(prefetch_container.get());
Max Currana84311e2023-05-16 20:40:251477
Hiroshige Hayashizaki638018f2023-09-12 17:05:451478 mojo::ScopedDataPipeConsumerHandle consumer_handle;
1479 mojo::ScopedDataPipeProducerHandle producer_handle;
1480 CHECK_EQ(mojo::CreateDataPipe(1024, producer_handle, consumer_handle),
1481 MOJO_RESULT_OK);
1482 pending_request.client->OnReceiveResponse(
1483 network::mojom::URLResponseHead::New(), std::move(consumer_handle),
Arthur Sonzognic686e8f2024-01-11 08:36:371484 std::nullopt);
Hiroshige Hayashizakib6a84d992023-10-02 17:57:541485 task_environment()->RunUntilIdle();
Hiroshige Hayashizaki638018f2023-09-12 17:05:451486
1487 // Prefetching is ongoing.
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351488 ASSERT_TRUE(prefetch_container->GetStreamingURLLoader());
Hiroshige Hayashizaki638018f2023-09-12 17:05:451489 base::WeakPtr<PrefetchStreamingURLLoader> streaming_loader =
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351490 prefetch_container->GetStreamingURLLoader();
1491 EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081492 PrefetchServableState::kServable);
Hiroshige Hayashizaki638018f2023-09-12 17:05:451493
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351494 prefetch_container->CancelStreamingURLLoaderIfNotServing();
Hiroshige Hayashizaki638018f2023-09-12 17:05:451495
1496 // `streaming_loader` is still alive and working.
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351497 EXPECT_FALSE(prefetch_container->GetStreamingURLLoader());
Hiroshige Hayashizaki638018f2023-09-12 17:05:451498 EXPECT_TRUE(streaming_loader);
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351499 EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081500 PrefetchServableState::kServable);
Hiroshige Hayashizaki638018f2023-09-12 17:05:451501
Hiroshige Hayashizakib6a84d992023-10-02 17:57:541502 task_environment()->RunUntilIdle();
Hiroshige Hayashizaki638018f2023-09-12 17:05:451503
1504 // `streaming_loader` is deleted asynchronously and its prefetching URL loader
1505 // is canceled. This itself doesn't make PrefetchContainer non-servable.
1506 EXPECT_FALSE(streaming_loader);
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351507 EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081508 PrefetchServableState::kServable);
Max Currana84311e2023-05-16 20:40:251509}
1510
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391511// To test lifetime and ownership issues, all possible event orderings for
1512// successful prefetching and serving are tested.
1513enum class Event {
1514 // Call OnComplete().
1515 kPrefetchOnComplete,
1516
1517 // Call CreateRequestHandler().
1518 kCreateRequestHandler,
1519
Hiroshige Hayashizakic853c0302023-09-13 08:51:071520 // Call the PrefetchRequestHandler returned by CreateRequestHandler().
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391521 kRequestHandler,
1522
1523 // Disconnect `serving_url_loader_client`.
1524 kDisconnectServingClient,
1525
1526 // Completely read the body mojo pipe.
1527 kCompleteBody,
1528
1529 // Destruct PrefetchContainer.
1530 kDestructPrefetchContainer,
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431531
kenossd26dc552025-07-01 10:11:441532 // Serve for the second serving client.
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431533 // All steps (corresponding to `kCreateRequestHandler`, `kRequestHandler`,
1534 // `kDisconnectServingClient` and `kCompleteBody`) are merged in order to
1535 // reduce the number of tests.
1536 kSecondClient,
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391537};
1538
Hiroshige Hayashizaki4d53c802023-09-28 05:36:401539std::ostream& operator<<(std::ostream& ostream, Event event) {
1540 switch (event) {
1541 case Event::kPrefetchOnComplete:
1542 return ostream << "kPrefetchOnComplete";
1543 case Event::kCreateRequestHandler:
1544 return ostream << "kCreateRequestHandler";
1545 case Event::kRequestHandler:
1546 return ostream << "kRequestHandler";
1547 case Event::kDisconnectServingClient:
1548 return ostream << "kDisconnectServingClient";
1549 case Event::kCompleteBody:
1550 return ostream << "kCompleteBody";
1551 case Event::kDestructPrefetchContainer:
1552 return ostream << "kDestructPrefetchContainer";
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431553 case Event::kSecondClient:
1554 return ostream << "kSecondClient";
Hiroshige Hayashizaki4d53c802023-09-28 05:36:401555 }
1556}
1557
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391558enum class BodySize { kSmall, kLarge };
Hiroshige Hayashizaki4d53c802023-09-28 05:36:401559std::ostream& operator<<(std::ostream& ostream, BodySize body_size) {
1560 switch (body_size) {
1561 case BodySize::kSmall:
1562 return ostream << "Small";
1563 case BodySize::kLarge:
1564 return ostream << "Large";
1565 }
1566}
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391567
1568// To detect corner cases around lifetime and ownership, test all possible
1569// permutations of the order of events.
1570class PrefetchContainerLifetimeTest
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431571 : public PrefetchContainerTestBase,
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391572 public ::testing::WithParamInterface<
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011573 std::tuple<PrefetchRearchParam, std::vector<Event>, BodySize>> {
1574 public:
1575 PrefetchContainerLifetimeTest()
1576 : PrefetchContainerTestBase(std::get<0>(GetParam())) {}
1577};
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391578
1579TEST_P(PrefetchContainerLifetimeTest, Lifetime) {
Taiyo Mizuhashifb547bdf2024-03-11 15:18:351580 auto prefetch_container =
1581 CreateSpeculationRulesPrefetchContainer(GURL("https://test.com"));
1582
Hiroshige Hayashizaki64802cf12025-01-16 23:18:461583 prefetch_container->SimulatePrefetchEligibleForTest();
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391584
1585 auto pending_request =
1586 MakeManuallyServableStreamingURLLoaderForTest(prefetch_container.get());
1587
Minoru Chikamune21c5f57d2024-11-27 05:01:101588 const auto producer_pipe_capacity = network::GetDataPipeDefaultAllocationSize(
1589 network::DataPipeAllocationSize::kLargerSizeIfPossible);
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451590
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011591 const BodySize body_size = std::get<2>(GetParam());
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391592 std::string content;
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451593 switch (body_size) {
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391594 case BodySize::kSmall:
1595 content = "Body";
1596 break;
1597 case BodySize::kLarge:
kenoss0c2b50152025-03-10 10:58:251598 // Set the minimum data size that makes write to data pipe fail
1599 // incomplete.
1600 //
1601 // - `features::kPrefetchReusableBodySizeLimit` (multiple of
1602 // `producer_pipe_capacity`) is used to fill buffer of
1603 // `PrefetchDataPipeTee`. `PrefetchDataPipeTee` doesn't close the
1604 // producer pipe at this stage and tries to read one more time (but it
1605 // will discard the next one as the limit exceeded).
1606 // - `producer_pipe_capacity` is used to fill data pipe after the above
1607 // buffer becomes full. The data is sent to `PrefetchDataPipeTee` (*)
1608 // and `PrefetchDataPipeTee` tries to read it, but discards it. At this
1609 // timing, `PrefetchDataPipeTee` closes the producer pipe (**).
1610 // - 1 is used to make the write incomplete as the producer tries to send
1611 // one more byte after (**).
1612 size_t limit =
1613 static_cast<size_t>(features::kPrefetchReusableBodySizeLimit.Get()) +
1614 producer_pipe_capacity;
1615 content = std::string(limit + 1, '-');
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391616 break;
1617 }
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451618
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391619 mojo::ScopedDataPipeConsumerHandle consumer_handle;
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451620 bool producer_completed = false;
1621
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391622 {
1623 mojo::ScopedDataPipeProducerHandle producer_handle;
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451624 ASSERT_EQ(mojo::CreateDataPipe(producer_pipe_capacity, producer_handle,
1625 consumer_handle),
1626 MOJO_RESULT_OK);
1627 auto producer =
1628 std::make_unique<mojo::DataPipeProducer>(std::move(producer_handle));
1629 mojo::DataPipeProducer* raw_producer = producer.get();
1630 raw_producer->Write(std::make_unique<mojo::StringDataSource>(
1631 content, mojo::StringDataSource::AsyncWritingMode::
1632 STRING_STAYS_VALID_UNTIL_COMPLETION),
1633 base::BindOnce(
1634 [](std::unique_ptr<mojo::DataPipeProducer> producer,
1635 bool* producer_completed, MojoResult result) {
1636 *producer_completed = true;
Hiroshige Hayashizaki44862202023-09-18 21:53:301637 CHECK_EQ(result, MOJO_RESULT_OK);
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451638 // `producer` is deleted here.
1639 },
1640 std::move(producer), &producer_completed));
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391641 }
1642
Hiroshige Hayashizakie556eb02023-09-13 00:20:481643 EXPECT_NE(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081644 PrefetchServableState::kServable);
kenossf7b4d60d2024-07-16 15:15:081645 EXPECT_FALSE(prefetch_container->GetNonRedirectHead());
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391646
1647 pending_request.client->OnReceiveResponse(
1648 network::mojom::URLResponseHead::New(), std::move(consumer_handle),
Arthur Sonzognic686e8f2024-01-11 08:36:371649 std::nullopt);
Hiroshige Hayashizakib6a84d992023-10-02 17:57:541650 task_environment()->RunUntilIdle();
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391651
Hiroshige Hayashizakie556eb02023-09-13 00:20:481652 EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081653 PrefetchServableState::kServable);
kenossf7b4d60d2024-07-16 15:15:081654 EXPECT_TRUE(prefetch_container->GetNonRedirectHead());
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391655
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571656 PrefetchServingHandle serving_handle =
1657 prefetch_container->CreateServingHandle();
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391658
1659 base::WeakPtr<PrefetchResponseReader> weak_response_reader =
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571660 serving_handle.GetCurrentResponseReaderToServeForTesting();
Hiroshige Hayashizaki638018f2023-09-12 17:05:451661 ASSERT_TRUE(prefetch_container->GetStreamingURLLoader());
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391662 base::WeakPtr<PrefetchStreamingURLLoader> weak_streaming_loader =
Hiroshige Hayashizaki638018f2023-09-12 17:05:451663 prefetch_container->GetStreamingURLLoader();
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391664
Hiroshige Hayashizakic853c0302023-09-13 08:51:071665 PrefetchRequestHandler request_handler;
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391666 std::unique_ptr<PrefetchTestURLLoaderClient> serving_url_loader_client;
1667
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571668 PrefetchServingHandle serving_handle2 =
1669 prefetch_container->CreateServingHandle();
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431670 ASSERT_EQ(weak_response_reader.get(),
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571671 serving_handle2.GetCurrentResponseReaderToServeForTesting().get());
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431672
1673 network::ResourceRequest serving_request;
1674 serving_request.url = GURL("https://test.com");
1675 serving_request.method = "GET";
1676
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391677 // `PrefetchStreamingURLLoader` and `PrefetchResponseReader` are initially
1678 // both expected alive, because they are needed for serving `request_handler`.
1679
1680 std::set<Event> done;
1681
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011682 for (const Event event : std::get<1>(GetParam())) {
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391683 switch (event) {
1684 case Event::kPrefetchOnComplete:
1685 pending_request.client->OnComplete(
1686 network::URLLoaderCompletionStatus(net::OK));
1687 break;
1688
1689 case Event::kCreateRequestHandler:
1690 ASSERT_FALSE(request_handler);
1691 ASSERT_TRUE(prefetch_container);
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431692 EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081693 PrefetchServableState::kServable);
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571694 request_handler = serving_handle.CreateRequestHandler().first;
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431695 ASSERT_TRUE(request_handler);
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391696 break;
1697
Hiroshige Hayashizakic853c0302023-09-13 08:51:071698 // Call the PrefetchRequestHandler returned by CreateRequestHandler().
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391699 case Event::kRequestHandler: {
1700 ASSERT_TRUE(request_handler); // NOLINT(bugprone-use-after-move)
1701 ASSERT_FALSE(serving_url_loader_client);
1702
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391703 serving_url_loader_client =
1704 std::make_unique<PrefetchTestURLLoaderClient>();
1705 serving_url_loader_client->SetAutoDraining(false);
1706
1707 // NOLINT(bugprone-use-after-move)
1708 std::move(request_handler)
1709 .Run(serving_request,
1710 serving_url_loader_client->BindURLloaderAndGetReceiver(),
1711 serving_url_loader_client->BindURLLoaderClientAndGetRemote());
1712 break;
1713 }
1714
1715 // Disconnect `serving_url_loader_client`.
1716 case Event::kDisconnectServingClient:
1717 ASSERT_TRUE(serving_url_loader_client);
1718 serving_url_loader_client->DisconnectMojoPipes();
1719 break;
1720
1721 // Completely read the body mojo pipe.
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451722 case Event::kCompleteBody: {
1723 if (body_size == BodySize::kLarge) {
1724 // The body is sufficiently large to fill the data pipes and thus the
1725 // producer should still have pending data to write before
1726 // `StartDraining()`.
1727 EXPECT_FALSE(producer_completed);
1728 }
1729 // Wait until the URLLoaderClient completion.
1730 // `base::RunLoop().RunUntilIdle()` is not sufficient here, because
1731 // `mojo::DataPipeProducer` uses thread pool.
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391732 serving_url_loader_client->StartDraining();
Hiroshige Hayashizakib6a84d992023-10-02 17:57:541733 task_environment()->RunUntilIdle();
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451734 EXPECT_TRUE(producer_completed);
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391735 break;
Hiroshige Hayashizakid2a405bc2023-08-16 22:36:451736 }
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391737
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431738 case Event::kSecondClient:
1739 ASSERT_TRUE(prefetch_container);
1740 EXPECT_EQ(prefetch_container->GetServableState(base::TimeDelta::Max()),
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:081741 PrefetchServableState::kServable);
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431742
1743 // The second request is servable if the body data pipe is finished and
1744 // the whole body fits within the data pipe tee size limit.
1745 if (!done.count(Event::kPrefetchOnComplete) ||
1746 body_size == BodySize::kLarge) {
1747 // Not servable.
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571748 ASSERT_FALSE(serving_handle2.CreateRequestHandler().first);
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431749 } else {
1750 // As the first client is already served, the body pipe producer
1751 // should be also completed.
1752 EXPECT_TRUE(producer_completed);
1753
Hiroshige Hayashizaki16b6e54f2025-08-12 06:56:571754 auto request_handler2 = serving_handle2.CreateRequestHandler().first;
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431755 ASSERT_TRUE(request_handler2);
1756
1757 auto serving_url_loader_client2 =
1758 std::make_unique<PrefetchTestURLLoaderClient>();
1759
1760 std::move(request_handler2)
1761 .Run(serving_request,
1762 serving_url_loader_client2->BindURLloaderAndGetReceiver(),
1763 serving_url_loader_client2
1764 ->BindURLLoaderClientAndGetRemote());
1765
1766 task_environment()->RunUntilIdle();
1767 serving_url_loader_client2->DisconnectMojoPipes();
1768
1769 EXPECT_TRUE(
1770 serving_url_loader_client2->completion_status().has_value());
1771 EXPECT_EQ(serving_url_loader_client2->body_content().size(),
1772 content.size());
1773 EXPECT_EQ(serving_url_loader_client2->body_content(), content);
1774 }
1775 break;
1776
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391777 case Event::kDestructPrefetchContainer:
1778 ASSERT_TRUE(prefetch_container);
1779 prefetch_container.reset();
1780 break;
1781 }
1782 done.insert(event);
1783
Hiroshige Hayashizakib6a84d992023-10-02 17:57:541784 task_environment()->RunUntilIdle();
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391785
1786 // `PrefetchResponseReader` should be kept alive as long as
1787 // `PrefetchContainer` is alive or serving URLLoaderClients are not
1788 // finished.
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431789 // The second client is not alive here because it is created and finished
1790 // within `kSecondClient`.
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391791 EXPECT_EQ(!!weak_response_reader,
1792 !done.count(Event::kDisconnectServingClient) ||
1793 !done.count(Event::kDestructPrefetchContainer));
1794
Hiroshige Hayashizaki638018f2023-09-12 17:05:451795 // `PrefetchStreamingURLLoader` is kept alive until prefetching is
1796 // completed.
1797 EXPECT_EQ(!!weak_streaming_loader, !done.count(Event::kPrefetchOnComplete));
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391798
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431799 if (done.count(Event::kPrefetchOnComplete) &&
1800 done.count(Event::kCompleteBody)) {
1801 EXPECT_TRUE(producer_completed);
1802 }
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391803 if (done.count(Event::kRequestHandler)) {
1804 EXPECT_EQ(serving_url_loader_client->completion_status().has_value(),
1805 done.count(Event::kPrefetchOnComplete));
1806 }
1807 if (done.count(Event::kCompleteBody)) {
1808 EXPECT_EQ(serving_url_loader_client->body_content().size(),
1809 content.size());
1810 EXPECT_EQ(serving_url_loader_client->body_content(), content);
1811 }
1812 }
1813}
1814
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011815TEST_P(PrefetchContainerTest, SpeculationRulesTagsAddedToRequestHeader) {
HuanPo Lind8887e32025-04-17 04:08:141816 NavigationSimulator::NavigateAndCommitFromBrowser(
1817 web_contents(), GURL("https://test.com/referrer"));
1818
HuanPo Lin740620b2025-03-21 12:37:261819 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(
1820 GURL("https://test.com"),
1821 {.speculation_rules_tags = SpeculationRulesTags({"tag1", "tag2"})});
1822 prefetch_container->MakeResourceRequest(net::HttpRequestHeaders());
1823 EXPECT_TRUE(prefetch_container->GetResourceRequest()
1824 ->headers.GetHeader(blink::kSecSpeculationTagsHeaderName)
1825 .has_value());
1826 EXPECT_EQ(prefetch_container->GetResourceRequest()
1827 ->headers.GetHeader(blink::kSecSpeculationTagsHeaderName)
1828 .value(),
1829 "\"tag1\", \"tag2\"");
1830}
1831
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011832TEST_P(PrefetchContainerTest, CrossSitePrefetchContainerNoSpeculationTag) {
HuanPo Lind8887e32025-04-17 04:08:141833 NavigationSimulator::NavigateAndCommitFromBrowser(
1834 web_contents(), GURL("https://other.com/referrer"));
1835
1836 auto prefetch_container = CreateSpeculationRulesPrefetchContainer(
1837 GURL("https://test.com"),
1838 {.speculation_rules_tags = SpeculationRulesTags({"tag1", "tag2"})});
1839
1840 EXPECT_TRUE(prefetch_container->IsCrossOriginRequest(
1841 url::Origin::Create(prefetch_container->GetURL())));
1842 // Cross-site Speculation rules prefetch should not contain tag in the header.
1843 prefetch_container->MakeResourceRequest(net::HttpRequestHeaders());
1844 EXPECT_FALSE(prefetch_container->GetResourceRequest()
1845 ->headers.GetHeader(blink::kSecSpeculationTagsHeaderName)
1846 .has_value());
1847}
1848
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011849TEST_P(PrefetchContainerTest, SpeculationRulesNoTagAddedToRequestHeader) {
HuanPo Lind8887e32025-04-17 04:08:141850 NavigationSimulator::NavigateAndCommitFromBrowser(
1851 web_contents(), GURL("https://test.com/referrer"));
HuanPo Lin740620b2025-03-21 12:37:261852 auto prefetch_container =
1853 CreateSpeculationRulesPrefetchContainer(GURL("https://test.com"), {});
1854 prefetch_container->MakeResourceRequest(net::HttpRequestHeaders());
1855 EXPECT_TRUE(prefetch_container->GetResourceRequest()
1856 ->headers.GetHeader(blink::kSecSpeculationTagsHeaderName)
1857 .has_value());
1858 EXPECT_EQ(prefetch_container->GetResourceRequest()
1859 ->headers.GetHeader(blink::kSecSpeculationTagsHeaderName)
1860 .value(),
1861 "null");
1862}
1863
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011864INSTANTIATE_TEST_SUITE_P(,
1865 PrefetchContainerTest,
1866 testing::ValuesIn(PrefetchRearchParam::Params()));
1867
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431868std::vector<std::vector<Event>> ValidEventPermutations(bool has_second_client) {
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391869 std::vector<Event> events({
1870 Event::kPrefetchOnComplete,
1871 Event::kCreateRequestHandler,
1872 Event::kRequestHandler,
1873 Event::kDisconnectServingClient,
1874 Event::kCompleteBody,
1875 Event::kDestructPrefetchContainer,
1876 });
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431877 if (has_second_client) {
1878 events.push_back(Event::kSecondClient);
1879 }
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391880
1881 std::vector<std::vector<Event>> params;
1882 do {
1883 const auto it_prefetch_on_complete =
1884 std::find(events.begin(), events.end(), Event::kPrefetchOnComplete);
1885 const auto it_create_request_handler =
1886 std::find(events.begin(), events.end(), Event::kCreateRequestHandler);
1887 const auto it_request_handler =
1888 std::find(events.begin(), events.end(), Event::kRequestHandler);
1889 const auto it_disconnect_serving_client = std::find(
1890 events.begin(), events.end(), Event::kDisconnectServingClient);
1891 const auto it_complete_body =
1892 std::find(events.begin(), events.end(), Event::kCompleteBody);
1893 const auto it_destruct_prefetch_container = std::find(
1894 events.begin(), events.end(), Event::kDestructPrefetchContainer);
1895
1896 // Ordering requirements due to direct data dependencies:
1897
1898 // `kCreateRequestHandler` -> `kRequestHandler` (`request_handler`)
1899 if (it_create_request_handler > it_request_handler) {
1900 continue;
1901 }
1902 // `kRequestHandler` -> `kDisconnectServingClient`
1903 // (`serving_url_loader_client`)
1904 if (it_request_handler > it_disconnect_serving_client) {
1905 continue;
1906 }
1907 // `kCreateRequestHandler` -> `kDestructPrefetchContainer`
1908 // (`prefetch_container`)
1909 if (it_create_request_handler > it_destruct_prefetch_container) {
1910 continue;
1911 }
1912 // `kRequestHandler` -> `kCompleteBody` (body data pipe)
1913 if (it_request_handler > it_complete_body) {
1914 continue;
1915 }
1916
1917 // `kPrefetchOnComplete` -> `kCompleteBody` and successful
1918 // `kDisconnectServingClient` (prefetch completion)
1919 if (it_prefetch_on_complete > it_complete_body) {
1920 continue;
1921 }
1922 if (it_prefetch_on_complete > it_disconnect_serving_client) {
1923 continue;
1924 }
1925
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431926 if (has_second_client) {
1927 const auto it_second_client =
1928 std::find(events.begin(), events.end(), Event::kSecondClient);
1929
1930 // `kPrefetchOnComplete` -> `kSecondClient` ->
1931 // `kDestructPrefetchContainer`
1932 if (it_prefetch_on_complete > it_second_client ||
1933 it_second_client > it_destruct_prefetch_container) {
1934 continue;
1935 }
1936
1937 // `kCreateRequestHandler` -> `kSecondClient` (the second request
1938 // starts after the first request, but doesn't necessarily complete
1939 // subsequent steps after those of the first request).
1940 if (it_create_request_handler > it_second_client) {
1941 continue;
1942 }
1943 }
1944
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391945 params.push_back(events);
1946 } while (std::next_permutation(events.begin(), events.end()));
1947
1948 // Make sure some particular sequences are tested, where:
1949
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431950 if (!has_second_client) {
1951 // - `PrefetchContainer` is destructed before prefetch is completed:
1952 CHECK(base::Contains(
1953 params,
1954 std::vector<Event>{Event::kCreateRequestHandler, Event::kRequestHandler,
1955 Event::kDestructPrefetchContainer,
1956 Event::kPrefetchOnComplete, Event::kCompleteBody,
1957 Event::kDisconnectServingClient}));
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391958
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431959 // - `PrefetchContainer` is destructed before PrefetchRequestHandler is
1960 // invoked and prefetch is completed:
1961 CHECK(base::Contains(
1962 params,
1963 std::vector<Event>{
1964 Event::kCreateRequestHandler, Event::kDestructPrefetchContainer,
1965 Event::kRequestHandler, Event::kPrefetchOnComplete,
1966 Event::kCompleteBody, Event::kDisconnectServingClient}));
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391967
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431968 // - `PrefetchContainer` is destructed before PrefetchRequestHandler is
1969 // invoked but after prefetch is completed:
1970 CHECK(base::Contains(
1971 params, std::vector<Event>{
1972 Event::kPrefetchOnComplete, Event::kCreateRequestHandler,
1973 Event::kDestructPrefetchContainer, Event::kRequestHandler,
1974 Event::kCompleteBody, Event::kDisconnectServingClient}));
1975 }
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391976
1977 return params;
1978}
1979
1980INSTANTIATE_TEST_SUITE_P(
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431981 SingleClient,
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391982 PrefetchContainerLifetimeTest,
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011983 testing::Combine(testing::ValuesIn(PrefetchRearchParam::Params()),
1984 testing::ValuesIn(ValidEventPermutations(false)),
kenossd26dc552025-07-01 10:11:441985 testing::Values(BodySize::kSmall, BodySize::kLarge)));
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:431986
1987INSTANTIATE_TEST_SUITE_P(
1988 TwoClients,
1989 PrefetchContainerLifetimeTest,
Hiroshige Hayashizaki09ca95b2025-08-19 19:54:011990 testing::Combine(testing::ValuesIn(PrefetchRearchParam::Params()),
1991 testing::ValuesIn(ValidEventPermutations(true)),
kenossd26dc552025-07-01 10:11:441992 testing::Values(BodySize::kSmall)));
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:391993
Max Curran646fb642022-03-16 00:44:091994} // namespace content