blob: f4715c0386ee5ed707fb5787b5a50e3156514e20 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2022 The Chromium Authors
Max Curran6c2835ea2022-03-07 19:52:382// 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_document_manager.h"
Max Curran6c2835ea2022-03-07 19:52:386
Kevin McNeee6ca0892022-09-28 15:36:227#include <tuple>
Max Curran6c2835ea2022-03-07 19:52:388
Adithya Srinivasanb60483492023-06-14 21:22:149#include "base/containers/contains.h"
Max Curran6c2835ea2022-03-07 19:52:3810#include "content/browser/browser_context_impl.h"
Kevin McNee7ca2e852024-04-30 02:38:3111#include "content/browser/preloading/prefetch/no_vary_search_helper.h"
Sreeja Kamishettyf66553a2022-07-14 17:41:2712#include "content/browser/preloading/prefetch/prefetch_container.h"
Hiroshige Hayashizaki22be5e4c2025-03-07 21:39:5913#include "content/browser/preloading/prefetch/prefetch_handle_impl.h"
Iman Saboorid74fb3c2022-07-21 15:34:3814#include "content/browser/preloading/prefetch/prefetch_params.h"
Hiroshige Hayashizakif55280f62025-08-19 17:23:2015#include "content/browser/preloading/prefetch/prefetch_request.h"
Sreeja Kamishettyf66553a2022-07-14 17:41:2716#include "content/browser/preloading/prefetch/prefetch_service.h"
kenossc3f9a2c2025-03-06 15:35:5117#include "content/browser/preloading/preload_pipeline_info_impl.h"
Taiyo Mizuhashi0192d3f2024-02-15 05:09:4318#include "content/browser/preloading/preloading.h"
19#include "content/browser/preloading/preloading_attempt_impl.h"
Hiroshige Hayashizakia00e4c82023-10-31 20:20:1720#include "content/browser/preloading/preloading_data_impl.h"
Kouhei Uenoc5c2ea202023-11-14 08:58:5821#include "content/browser/preloading/preloading_trigger_type_impl.h"
HuanPo Lin740620b2025-03-21 12:37:2622#include "content/browser/preloading/speculation_rules/speculation_rules_tags.h"
Takashi Nakayama9eb7988f2025-06-25 06:14:0023#include "content/browser/preloading/speculation_rules/speculation_rules_util.h"
Hiroshige Hayashizaki2df45292023-10-10 22:59:0324#include "content/browser/renderer_host/render_frame_host_impl.h"
Jeremy Roman7308f282024-02-01 03:13:2925#include "content/public/browser/content_browser_client.h"
Max Curran210cffa2022-09-06 22:24:3126#include "content/public/browser/prefetch_metrics.h"
Max Curran6c2835ea2022-03-07 19:52:3827#include "content/public/browser/render_frame_host.h"
Max Curranc4445fc2022-06-02 18:43:4328#include "content/public/browser/web_contents.h"
Jeremy Roman7308f282024-02-01 03:13:2929#include "content/public/common/content_client.h"
Liviu Tintad97a6a32022-12-08 23:28:4030#include "net/http/http_no_vary_search_data.h"
Liviu Tintad97a6a32022-12-08 23:28:4031#include "services/network/public/mojom/no_vary_search.mojom.h"
Max Curran6c2835ea2022-03-07 19:52:3832
33namespace content {
34
Max Curran18a6f2b2022-05-02 23:13:2435namespace {
36static PrefetchService* g_prefetch_service_for_testing = nullptr;
Liviu Tintad608e012023-05-10 19:16:4137
Hiroki Nakagawac33034f2025-03-31 07:39:3038struct PrefetchUrlParams {
39 explicit PrefetchUrlParams(
40 const blink::mojom::SpeculationCandidatePtr& candidate)
41 : prefetch_url(candidate->url),
42 prefetch_type(PreloadingTriggerTypeFromSpeculationInjectionType(
43 candidate->injection_type),
44 /*use_prefetch_proxy=*/
45 candidate->requires_anonymous_client_ip_when_cross_origin,
46 candidate->eagerness),
47 referrer(*candidate->referrer),
48 no_vary_search_hint(candidate->no_vary_search_hint.Clone()),
49 tags(candidate->tags.empty() ? std::nullopt
50 : std::make_optional(candidate->tags)) {
51 if (prefetch_type.IsProxyRequiredWhenCrossOrigin() &&
52 ShouldPrefetchBypassProxyForTestHost(prefetch_url.host())) {
53 // TODO(crbug.com/40942006): Remove SetProxyBypassedForTest, since it is
54 // the only mutator of the PrefetchType.
55 prefetch_type.SetProxyBypassedForTest(); // IN-TEST
56 }
Adithya Srinivasan3bdb5ce2023-06-05 13:22:1257 }
58
Hiroki Nakagawac33034f2025-03-31 07:39:3059 GURL prefetch_url;
60 PrefetchType prefetch_type;
61 blink::mojom::Referrer referrer;
62 network::mojom::NoVarySearchPtr no_vary_search_hint;
63 std::optional<SpeculationRulesTags> tags;
64};
Adithya Srinivasan3bdb5ce2023-06-05 13:22:1265
Max Curran18a6f2b2022-05-02 23:13:2466} // namespace
67
Max Curran6c2835ea2022-03-07 19:52:3868PrefetchDocumentManager::PrefetchDocumentManager(RenderFrameHost* rfh)
Max Curranc4445fc2022-06-02 18:43:4369 : DocumentUserData(rfh),
Hiroshige Hayashizaki2df45292023-10-10 22:59:0370 document_token_(
71 static_cast<RenderFrameHostImpl*>(rfh)->GetDocumentToken()),
Adithya Srinivasand476f4f82023-06-20 15:55:1372 prefetch_destruction_callback_(base::DoNothing()) {}
Max Curran6c2835ea2022-03-07 19:52:3873
Max Currane0444942022-09-06 23:55:2374PrefetchDocumentManager::~PrefetchDocumentManager() {
Max Currane0444942022-09-06 23:55:2375 PrefetchService* prefetch_service = GetPrefetchService();
76 if (!prefetch_service)
77 return;
78
Hiroshige Hayashizaki7a34d0182023-11-07 20:54:3479 // Invalidate weak pointers to `this` a little earlier to avoid callbacks to
Taiyo Mizuhashi94ce74f2025-01-28 04:20:1480 // `this` (especially `PrefetchWillBeDestroyed()`) during
81 // `MayReleasePrefetch()` below.
Hiroshige Hayashizaki7a34d0182023-11-07 20:54:3482 weak_method_factory_.InvalidateWeakPtrs();
Max Currane0444942022-09-06 23:55:2383}
Max Curran6c2835ea2022-03-07 19:52:3884
Hiroshige Hayashizaki6a2bc752023-10-31 19:08:1185// static
86PrefetchDocumentManager* PrefetchDocumentManager::FromDocumentToken(
87 int process_id,
88 const blink::DocumentToken& document_token) {
89 if (auto* rfh =
90 RenderFrameHostImpl::FromDocumentToken(process_id, document_token)) {
91 if (auto* prefetch_document_manager = GetForCurrentDocument(rfh)) {
92 // A RenderFrameHost can have multiple Documents/PrefetchDocumentManagers
93 // and the Document of `document_token` might be pending deletion or
94 // bfcached, so check `document_token_` to confirm we get the correct
95 // `PrefetchDocumentManager`.
Alison Gale770f3fc2024-04-27 00:39:5896 // TODO(crbug.com/40615943): clean this up once RenderDocument ships.
Hiroshige Hayashizaki6a2bc752023-10-31 19:08:1197 if (prefetch_document_manager->document_token_ == document_token) {
98 return prefetch_document_manager;
99 }
100 }
101 }
102 return nullptr;
103}
104
Max Curran6c2835ea2022-03-07 19:52:38105void PrefetchDocumentManager::ProcessCandidates(
kenoss1ce36df592024-12-03 01:04:35106 std::vector<blink::mojom::SpeculationCandidatePtr>& candidates) {
Max Curran646fb642022-03-16 00:44:09107 // Filter out candidates that can be handled by |PrefetchService| and
108 // determine the type of prefetch required.
Alison Gale770f3fc2024-04-27 00:39:58109 // TODO(crbug.com/40215782): Once this code becomes enabled by default
Max Curran646fb642022-03-16 00:44:09110 // to handle all prefetches and the prefetch proxy code in chrome/browser/ is
111 // removed, then we can move the logic of which speculation candidates this
112 // code can handle up a layer to |SpeculationHostImpl|.
Hiroki Nakagawac33034f2025-03-31 07:39:30113 std::vector<PrefetchUrlParams> prefetches;
Max Curran646fb642022-03-16 00:44:09114
Adithya Srinivasanb60483492023-06-14 21:22:14115 // Evicts an existing prefetch if there is no longer a matching speculation
116 // candidate for it. Note: A matching candidate is not necessarily the
117 // candidate that originally triggered the prefetch, but is any prefetch
118 // candidate that has the same URL.
Adithya Srinivasan9d1b6fa2024-08-29 15:04:35119 std::vector<GURL> urls_from_candidates;
120 urls_from_candidates.reserve(candidates.size());
121 for (const auto& candidate_ptr : candidates) {
122 if (candidate_ptr->action == blink::mojom::SpeculationAction::kPrefetch) {
123 urls_from_candidates.push_back(candidate_ptr->url);
Adithya Srinivasanb60483492023-06-14 21:22:14124 }
Adithya Srinivasan9d1b6fa2024-08-29 15:04:35125 }
126 base::flat_set<GURL> url_set(std::move(urls_from_candidates));
Hiroshige Hayashizaki22be5e4c2025-03-07 21:39:59127 std::vector<std::pair<GURL, PreloadingType>> prefetches_to_evict;
kenossf7d063142024-10-10 08:34:28128 for (const auto& [all_prefetches_key, prefetch] : all_prefetches_) {
129 const auto& [url, planned_max_preloading_type] = all_prefetches_key;
130
131 // Don't evict prefetch ahead of prerender, which is initiated by
132 // `PrerenderImpl`, as `PrefetchDocumentManager::ProcessCandidates()` is
133 // only called for prefeches managed by `Prefetcher`.
134 if (planned_max_preloading_type != PreloadingType::kPrefetch) {
135 continue;
136 }
137
Hiroshige Hayashizaki22be5e4c2025-03-07 21:39:59138 if (!base::Contains(url_set, url)) {
139 static_cast<PrefetchHandleImpl*>(prefetch.get())
140 ->SetPrefetchStatusOnReleaseStartedPrefetch(
141 PrefetchStatus::kPrefetchEvictedAfterCandidateRemoved);
142 prefetches_to_evict.push_back(all_prefetches_key);
Adithya Srinivasanb60483492023-06-14 21:22:14143 }
Adithya Srinivasan9d1b6fa2024-08-29 15:04:35144 }
Hiroshige Hayashizaki22be5e4c2025-03-07 21:39:59145 for (const auto& all_prefetches_key : prefetches_to_evict) {
146 all_prefetches_.erase(all_prefetches_key);
Adithya Srinivasanb60483492023-06-14 21:22:14147 }
148
Max Curran646fb642022-03-16 00:44:09149 auto should_process_entry =
150 [&](const blink::mojom::SpeculationCandidatePtr& candidate) {
Max Curran646fb642022-03-16 00:44:09151 // This code doesn't not support speculation candidates with the action
152 // of |blink::mojom::SpeculationAction::kPrefetchWithSubresources|. See
153 // https://crbug.com/1296309.
Max Curranc0137502023-05-02 18:06:22154 if (candidate->action != blink::mojom::SpeculationAction::kPrefetch) {
155 return false;
Max Curran646fb642022-03-16 00:44:09156 }
Max Curranc0137502023-05-02 18:06:22157
Hiroki Nakagawac33034f2025-03-31 07:39:30158 prefetches.emplace_back(candidate);
Max Curranc0137502023-05-02 18:06:22159 return true;
Max Curran646fb642022-03-16 00:44:09160 };
161
Andrew Rayskiyf65990362024-02-27 18:43:24162 std::erase_if(candidates, should_process_entry);
Max Curran646fb642022-03-16 00:44:09163
HuanPo Lin740620b2025-03-21 12:37:26164 for (auto& [prefetch_url, prefetch_type, referrer, no_vary_search_hint,
165 tags] : prefetches) {
Takashi Nakayama978f0a152025-06-17 08:26:25166 // Immediate candidates are enacted by the same predictor that creates them.
Kevin McNee98e068a2024-04-09 20:12:34167 const PreloadingPredictor enacting_predictor =
168 GetPredictorForPreloadingTriggerType(prefetch_type.trigger_type());
kenoss8644f6bf2025-02-10 05:51:44169 PrefetchUrl(prefetch_url, prefetch_type, enacting_predictor, referrer,
Hiroki Nakagawac33034f2025-03-31 07:39:30170 std::move(tags), no_vary_search_hint,
kenossc3f9a2c2025-03-06 15:35:51171 PreloadPipelineInfo::Create(
kenoss8644f6bf2025-02-10 05:51:44172 /*planned_max_preloading_type=*/PreloadingType::kPrefetch));
Max Curran646fb642022-03-16 00:44:09173 }
Adithya Srinivasand5e37cb2023-07-05 14:45:23174
175 if (PrefetchService* prefetch_service = GetPrefetchService()) {
176 prefetch_service->OnCandidatesUpdated();
177 }
Max Curran6c2835ea2022-03-07 19:52:38178}
179
Adithya Srinivasan3bdb5ce2023-06-05 13:22:12180bool PrefetchDocumentManager::MaybePrefetch(
181 blink::mojom::SpeculationCandidatePtr candidate,
kenoss1ce36df592024-12-03 01:04:35182 const PreloadingPredictor& enacting_predictor) {
Adithya Srinivasan3bdb5ce2023-06-05 13:22:12183 if (candidate->action != blink::mojom::SpeculationAction::kPrefetch) {
184 return false;
185 }
186
Hiroki Nakagawac33034f2025-03-31 07:39:30187 PrefetchUrlParams params(candidate);
188 PrefetchUrl(params.prefetch_url, params.prefetch_type, enacting_predictor,
189 params.referrer, std::move(params.tags),
190 params.no_vary_search_hint,
kenossc3f9a2c2025-03-06 15:35:51191 PreloadPipelineInfo::Create(
kenoss8644f6bf2025-02-10 05:51:44192 /*planned_max_preloading_type=*/PreloadingType::kPrefetch));
Adithya Srinivasan3bdb5ce2023-06-05 13:22:12193 return true;
194}
195
kenoss9d57ee7b2024-06-03 01:36:43196void PrefetchDocumentManager::PrefetchAheadOfPrerender(
kenoss3bd73b82024-10-10 20:33:49197 scoped_refptr<PreloadPipelineInfo> preload_pipeline_info,
kenoss9d57ee7b2024-06-03 01:36:43198 blink::mojom::SpeculationCandidatePtr candidate,
199 const PreloadingPredictor& enacting_predictor) {
Hiroki Nakagawac33034f2025-03-31 07:39:30200 PrefetchUrlParams params(candidate);
201 PrefetchUrl(params.prefetch_url, params.prefetch_type, enacting_predictor,
202 params.referrer, std::move(params.tags),
203 params.no_vary_search_hint, std::move(preload_pipeline_info));
kenoss9d57ee7b2024-06-03 01:36:43204}
205
Iman Saboori65c356d2022-07-15 14:47:47206void PrefetchDocumentManager::PrefetchUrl(
207 const GURL& url,
208 const PrefetchType& prefetch_type,
Kevin McNee98e068a2024-04-09 20:12:34209 const PreloadingPredictor& enacting_predictor,
Kevin McNeee6ca0892022-09-28 15:36:22210 const blink::mojom::Referrer& referrer,
Hiroki Nakagawac33034f2025-03-31 07:39:30211 std::optional<SpeculationRulesTags> speculation_rules_tags,
Rulong Chen(陈汝龙)bf12169c2024-12-16 05:38:16212 const network::mojom::NoVarySearchPtr& mojo_no_vary_search_hint,
kenoss1ce36df592024-12-03 01:04:35213 scoped_refptr<PreloadPipelineInfo> preload_pipeline_info) {
kenossf7d063142024-10-10 08:34:28214 const std::pair<GURL, PreloadingType> all_prefetches_key =
kenossc3f9a2c2025-03-06 15:35:51215 std::make_pair(url, PreloadPipelineInfoImpl::From(*preload_pipeline_info)
216 .planned_max_preloading_type());
kenossf7d063142024-10-10 08:34:28217
218 // Skip prefetches that have already been requested.
219 auto prefetch_container_iter = all_prefetches_.find(all_prefetches_key);
Max Curran646fb642022-03-16 00:44:09220 if (prefetch_container_iter != all_prefetches_.end() &&
Hiroshige Hayashizaki22be5e4c2025-03-07 21:39:59221 static_cast<PrefetchHandleImpl*>(prefetch_container_iter->second.get())
222 ->IsAlive()) {
Max Curran646fb642022-03-16 00:44:09223 return;
224 }
225
Jeremy Roman7308f282024-02-01 03:13:29226 // Log that a prefetch is occurring. Paths that reach this point go through
227 // speculation rules in some form or another.
228 GetContentClient()->browser()->LogWebFeatureForCurrentPage(
229 &render_frame_host(),
230 blink::mojom::WebFeature::kSpeculationRulesPrefetch);
231
Rulong Chen(陈汝龙)bf12169c2024-12-16 05:38:16232 std::optional<net::HttpNoVarySearchData> no_vary_search_hint;
233 if (mojo_no_vary_search_hint) {
234 no_vary_search_hint = no_vary_search::ParseHttpNoVarySearchDataFromMojom(
235 mojo_no_vary_search_hint);
Liviu Tinta68a45802023-04-05 18:32:20236 }
Hiroshige Hayashizakia00e4c82023-10-31 20:20:17237 PrefetchService* prefetch_service = GetPrefetchService();
Hiroshige Hayashizaki7a34d0182023-11-07 20:54:34238 if (!prefetch_service) {
239 return;
240 }
241
Taiyo Mizuhashi0192d3f2024-02-15 05:09:43242 auto* web_contents = WebContents::FromRenderFrameHost(&render_frame_host());
243 auto* preloading_data =
Kevin McNee98e068a2024-04-09 20:12:34244 PreloadingDataImpl::GetOrCreateForWebContents(web_contents);
Taiyo Mizuhashi0192d3f2024-02-15 05:09:43245
Kevin McNee98e068a2024-04-09 20:12:34246 const PreloadingPredictor creating_predictor =
247 GetPredictorForPreloadingTriggerType(prefetch_type.trigger_type());
Taiyo Mizuhashi0192d3f2024-02-15 05:09:43248 PreloadingURLMatchCallback matcher =
249 PreloadingDataImpl::GetPrefetchServiceMatcher(
Hiroshige Hayashizakic625e812025-08-19 18:42:35250 *prefetch_service, PrefetchKey(document_token_, url));
Taiyo Mizuhashi0192d3f2024-02-15 05:09:43251
252 auto* attempt =
253 static_cast<PreloadingAttemptImpl*>(preloading_data->AddPreloadingAttempt(
Kevin McNee98e068a2024-04-09 20:12:34254 creating_predictor, enacting_predictor, PreloadingType::kPrefetch,
kenoss8644f6bf2025-02-10 05:51:44255 std::move(matcher),
Taiyo Mizuhashi0192d3f2024-02-15 05:09:43256 web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId()));
257
258 attempt->SetSpeculationEagerness(prefetch_type.GetEagerness());
Takashi Nakayama9eb7988f2025-06-25 06:14:00259 CHECK(!IsImmediateSpeculationEagerness(prefetch_type.GetEagerness()) ||
Kevin McNee98e068a2024-04-09 20:12:34260 creating_predictor == enacting_predictor);
Taiyo Mizuhashi0192d3f2024-02-15 05:09:43261
262 // `PreloadingPrediction` is added in `PreloadingDecider`.
263
Iman Saboori65c356d2022-07-15 14:47:47264 auto container = std::make_unique<PrefetchContainer>(
Kevin McNee06824c72024-02-06 18:59:52265 static_cast<RenderFrameHostImpl&>(render_frame_host()), document_token_,
Hiroki Nakagawac33034f2025-03-31 07:39:30266 url, prefetch_type, referrer, std::move(speculation_rules_tags),
Taiyo Mizuhashid7c856992025-06-23 08:56:02267 std::move(no_vary_search_hint), /*priority=*/std::nullopt,
268 weak_method_factory_.GetWeakPtr(), std::move(preload_pipeline_info),
269 attempt->GetWeakPtr());
Hiroshige Hayashizaki3876eee2023-03-27 04:42:04270 DVLOG(1) << *container << ": created";
Max Curran646fb642022-03-16 00:44:09271
Max Curran210cffa2022-09-06 22:24:31272 referring_page_metrics_.prefetch_attempted_count++;
273
Hiroshige Hayashizaki22be5e4c2025-03-07 21:39:59274 all_prefetches_[all_prefetches_key] =
275 prefetch_service->AddPrefetchContainerWithHandle(std::move(container));
Max Curran18a6f2b2022-05-02 23:13:24276}
277
Iman Sabooriab85b132022-11-15 22:17:23278bool PrefetchDocumentManager::IsPrefetchAttemptFailedOrDiscarded(
279 const GURL& url) {
Hiroshige Hayashizakia129d91c2025-03-05 22:28:12280 PrefetchService* prefetch_service = GetPrefetchService();
281 if (!prefetch_service) {
Iman Sabooriab85b132022-11-15 22:17:23282 return true;
Iman Sabooriab85b132022-11-15 22:17:23283 }
Hiroshige Hayashizakia129d91c2025-03-05 22:28:12284
285 return prefetch_service->IsPrefetchAttemptFailedOrDiscardedInternal(
286 base::PassKey<PrefetchDocumentManager>(),
Hiroshige Hayashizakic625e812025-08-19 18:42:35287 PrefetchKey(document_token_, url));
Iman Sabooriab85b132022-11-15 22:17:23288}
289
Max Curran18a6f2b2022-05-02 23:13:24290// static
291void PrefetchDocumentManager::SetPrefetchServiceForTesting(
292 PrefetchService* prefetch_service) {
293 g_prefetch_service_for_testing = prefetch_service;
294}
295
kenoss087ae232024-12-10 05:06:04296void PrefetchDocumentManager::ResetPrefetchAheadOfPrerenderIfExist(
297 const GURL& url) {
Lingqi Chi844e05d42025-07-23 02:50:50298 // TODO(https://crbug.com/428500219): Update the logic for
299 // prerender-until-script.
kenoss087ae232024-12-10 05:06:04300 auto it =
301 all_prefetches_.find(std::make_pair(url, PreloadingType::kPrerender));
302 if (it == all_prefetches_.end()) {
303 return;
304 }
305
Hiroshige Hayashizaki22be5e4c2025-03-07 21:39:59306 static_cast<PrefetchHandleImpl*>(it->second.get())
307 ->SetPrefetchStatusOnReleaseStartedPrefetch(
kenoss087ae232024-12-10 05:06:04308 PrefetchStatus::kPrefetchEvictedAfterCandidateRemoved);
kenoss087ae232024-12-10 05:06:04309 all_prefetches_.erase(it);
310}
311
Max Curranc4445fc2022-06-02 18:43:43312PrefetchService* PrefetchDocumentManager::GetPrefetchService() const {
313 if (g_prefetch_service_for_testing) {
314 return g_prefetch_service_for_testing;
315 }
316
317 DCHECK(BrowserContextImpl::From(render_frame_host().GetBrowserContext())
318 ->GetPrefetchService());
319 return BrowserContextImpl::From(render_frame_host().GetBrowserContext())
320 ->GetPrefetchService();
321}
322
Max Curran210cffa2022-09-06 22:24:31323void PrefetchDocumentManager::OnEligibilityCheckComplete(bool is_eligible) {
324 if (is_eligible)
325 referring_page_metrics_.prefetch_eligible_count++;
326}
327
Adithya Srinivasanf393dd02023-05-16 20:26:16328void PrefetchDocumentManager::OnPrefetchSuccessful(
329 PrefetchContainer* prefetch) {
Max Curran210cffa2022-09-06 22:24:31330 referring_page_metrics_.prefetch_successful_count++;
Takashi Nakayama9eb7988f2025-06-25 06:14:00331 if (IsImmediateSpeculationEagerness(
Hiroshige Hayashizakif55280f62025-08-19 17:23:20332 prefetch->request().prefetch_type().GetEagerness())) {
Takashi Nakayama978f0a152025-06-17 08:26:25333 completed_immediate_prefetches_.push_back(prefetch->GetWeakPtr());
Adithya Srinivasanf393dd02023-05-16 20:26:16334 } else {
Takashi Nakayama978f0a152025-06-17 08:26:25335 completed_non_immediate_prefetches_.push_back(prefetch->GetWeakPtr());
Adithya Srinivasanf393dd02023-05-16 20:26:16336 }
Max Curran210cffa2022-09-06 22:24:31337}
338
Adithya Srinivasand5e37cb2023-07-05 14:45:23339std::tuple<bool, base::WeakPtr<PrefetchContainer>>
340PrefetchDocumentManager::CanPrefetchNow(PrefetchContainer* prefetch) {
Adithya Srinivasand5e37cb2023-07-05 14:45:23341 RenderFrameHost* rfh = &render_frame_host();
342 // The document needs to be active, primary and in a visible WebContents for
343 // the prefetch to be eligible.
344 if (!rfh->IsActive() || !rfh->GetPage().IsPrimary() ||
345 WebContents::FromRenderFrameHost(rfh)->GetVisibility() !=
346 Visibility::VISIBLE) {
347 return std::make_tuple(false, nullptr);
348 }
Takashi Nakayama9eb7988f2025-06-25 06:14:00349 if (IsImmediateSpeculationEagerness(
Hiroshige Hayashizakif55280f62025-08-19 17:23:20350 prefetch->request().prefetch_type().GetEagerness())) {
Takashi Nakayama978f0a152025-06-17 08:26:25351 return std::make_tuple(completed_immediate_prefetches_.size() <
352 kMaxNumberOfImmediatePrefetchesPerPage,
353 nullptr);
Adithya Srinivasanf393dd02023-05-16 20:26:16354 } else {
Takashi Nakayama978f0a152025-06-17 08:26:25355 if (completed_non_immediate_prefetches_.size() <
356 kMaxNumberOfNonImmediatePrefetchesPerPage) {
Adithya Srinivasand5e37cb2023-07-05 14:45:23357 return std::make_tuple(true, nullptr);
Adithya Srinivasan6054e132023-05-18 17:38:39358 }
Takashi Nakayama978f0a152025-06-17 08:26:25359 // We are at capacity, and now need to evict the oldest non-immediate
360 // prefetch to make space for a new one.
Adithya Srinivasan6054e132023-05-18 17:38:39361 DCHECK(GetPrefetchService());
362 base::WeakPtr<PrefetchContainer> oldest_prefetch =
Takashi Nakayama978f0a152025-06-17 08:26:25363 completed_non_immediate_prefetches_.front();
Alison Gale770f3fc2024-04-27 00:39:58364 // TODO(crbug.com/40064525): We should also be checking if the prefetch is
Adithya Srinivasan6054e132023-05-18 17:38:39365 // currently being used to serve a navigation. In that scenario, evicting
366 // doesn't make sense.
Adithya Srinivasand5e37cb2023-07-05 14:45:23367 return std::make_tuple(true, oldest_prefetch);
Adithya Srinivasanf393dd02023-05-16 20:26:16368 }
369}
370
Adithya Srinivasand476f4f82023-06-20 15:55:13371void PrefetchDocumentManager::SetPrefetchDestructionCallback(
372 PrefetchDestructionCallback callback) {
373 prefetch_destruction_callback_ = std::move(callback);
374}
375
376void PrefetchDocumentManager::PrefetchWillBeDestroyed(
377 PrefetchContainer* prefetch) {
378 prefetch_destruction_callback_.Run(prefetch->GetURL());
Adithya Srinivasan9d1b6fa2024-08-29 15:04:35379
380 std::vector<base::WeakPtr<PrefetchContainer>>& completed_prefetches =
Takashi Nakayama9eb7988f2025-06-25 06:14:00381 IsImmediateSpeculationEagerness(
Hiroshige Hayashizakif55280f62025-08-19 17:23:20382 prefetch->request().prefetch_type().GetEagerness())
Takashi Nakayama978f0a152025-06-17 08:26:25383 ? completed_immediate_prefetches_
384 : completed_non_immediate_prefetches_;
Peter Kasting1557e5f2025-01-28 01:14:08385 auto it = std::ranges::find(completed_prefetches, prefetch->key(),
386 [&](const auto& p) { return p->key(); });
Adithya Srinivasan9d1b6fa2024-08-29 15:04:35387 if (it != completed_prefetches.end()) {
388 completed_prefetches.erase(it);
Adithya Srinivasan6bdb9bcbf2023-06-23 21:28:46389 }
Adithya Srinivasand1c68ba2023-05-30 19:54:25390}
391
Max Curran6c2835ea2022-03-07 19:52:38392DOCUMENT_USER_DATA_KEY_IMPL(PrefetchDocumentManager);
393
394} // namespace content