Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 5 | #include "content/browser/preloading/prefetch/prefetch_document_manager.h" |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 6 | |
Kevin McNee | e6ca089 | 2022-09-28 15:36:22 | [diff] [blame] | 7 | #include <tuple> |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 8 | |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 9 | #include "base/containers/contains.h" |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 10 | #include "content/browser/browser_context_impl.h" |
Kevin McNee | 7ca2e85 | 2024-04-30 02:38:31 | [diff] [blame] | 11 | #include "content/browser/preloading/prefetch/no_vary_search_helper.h" |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 12 | #include "content/browser/preloading/prefetch/prefetch_container.h" |
Hiroshige Hayashizaki | 22be5e4c | 2025-03-07 21:39:59 | [diff] [blame] | 13 | #include "content/browser/preloading/prefetch/prefetch_handle_impl.h" |
Iman Saboori | d74fb3c | 2022-07-21 15:34:38 | [diff] [blame] | 14 | #include "content/browser/preloading/prefetch/prefetch_params.h" |
Hiroshige Hayashizaki | f55280f6 | 2025-08-19 17:23:20 | [diff] [blame] | 15 | #include "content/browser/preloading/prefetch/prefetch_request.h" |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 16 | #include "content/browser/preloading/prefetch/prefetch_service.h" |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 17 | #include "content/browser/preloading/preload_pipeline_info_impl.h" |
Taiyo Mizuhashi | 0192d3f | 2024-02-15 05:09:43 | [diff] [blame] | 18 | #include "content/browser/preloading/preloading.h" |
| 19 | #include "content/browser/preloading/preloading_attempt_impl.h" |
Hiroshige Hayashizaki | a00e4c8 | 2023-10-31 20:20:17 | [diff] [blame] | 20 | #include "content/browser/preloading/preloading_data_impl.h" |
Kouhei Ueno | c5c2ea20 | 2023-11-14 08:58:58 | [diff] [blame] | 21 | #include "content/browser/preloading/preloading_trigger_type_impl.h" |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 22 | #include "content/browser/preloading/speculation_rules/speculation_rules_tags.h" |
Takashi Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 23 | #include "content/browser/preloading/speculation_rules/speculation_rules_util.h" |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 24 | #include "content/browser/renderer_host/render_frame_host_impl.h" |
Jeremy Roman | 7308f28 | 2024-02-01 03:13:29 | [diff] [blame] | 25 | #include "content/public/browser/content_browser_client.h" |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 26 | #include "content/public/browser/prefetch_metrics.h" |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 27 | #include "content/public/browser/render_frame_host.h" |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 28 | #include "content/public/browser/web_contents.h" |
Jeremy Roman | 7308f28 | 2024-02-01 03:13:29 | [diff] [blame] | 29 | #include "content/public/common/content_client.h" |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 30 | #include "net/http/http_no_vary_search_data.h" |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 31 | #include "services/network/public/mojom/no_vary_search.mojom.h" |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 32 | |
| 33 | namespace content { |
| 34 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 35 | namespace { |
| 36 | static PrefetchService* g_prefetch_service_for_testing = nullptr; |
Liviu Tinta | d608e01 | 2023-05-10 19:16:41 | [diff] [blame] | 37 | |
Hiroki Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 38 | struct 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 Srinivasan | 3bdb5ce | 2023-06-05 13:22:12 | [diff] [blame] | 57 | } |
| 58 | |
Hiroki Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 59 | 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 Srinivasan | 3bdb5ce | 2023-06-05 13:22:12 | [diff] [blame] | 65 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 66 | } // namespace |
| 67 | |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 68 | PrefetchDocumentManager::PrefetchDocumentManager(RenderFrameHost* rfh) |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 69 | : DocumentUserData(rfh), |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 70 | document_token_( |
| 71 | static_cast<RenderFrameHostImpl*>(rfh)->GetDocumentToken()), |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 72 | prefetch_destruction_callback_(base::DoNothing()) {} |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 73 | |
Max Curran | e044494 | 2022-09-06 23:55:23 | [diff] [blame] | 74 | PrefetchDocumentManager::~PrefetchDocumentManager() { |
Max Curran | e044494 | 2022-09-06 23:55:23 | [diff] [blame] | 75 | PrefetchService* prefetch_service = GetPrefetchService(); |
| 76 | if (!prefetch_service) |
| 77 | return; |
| 78 | |
Hiroshige Hayashizaki | 7a34d018 | 2023-11-07 20:54:34 | [diff] [blame] | 79 | // Invalidate weak pointers to `this` a little earlier to avoid callbacks to |
Taiyo Mizuhashi | 94ce74f | 2025-01-28 04:20:14 | [diff] [blame] | 80 | // `this` (especially `PrefetchWillBeDestroyed()`) during |
| 81 | // `MayReleasePrefetch()` below. |
Hiroshige Hayashizaki | 7a34d018 | 2023-11-07 20:54:34 | [diff] [blame] | 82 | weak_method_factory_.InvalidateWeakPtrs(); |
Max Curran | e044494 | 2022-09-06 23:55:23 | [diff] [blame] | 83 | } |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 84 | |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 85 | // static |
| 86 | PrefetchDocumentManager* 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 Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 96 | // TODO(crbug.com/40615943): clean this up once RenderDocument ships. |
Hiroshige Hayashizaki | 6a2bc75 | 2023-10-31 19:08:11 | [diff] [blame] | 97 | if (prefetch_document_manager->document_token_ == document_token) { |
| 98 | return prefetch_document_manager; |
| 99 | } |
| 100 | } |
| 101 | } |
| 102 | return nullptr; |
| 103 | } |
| 104 | |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 105 | void PrefetchDocumentManager::ProcessCandidates( |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 106 | std::vector<blink::mojom::SpeculationCandidatePtr>& candidates) { |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 107 | // Filter out candidates that can be handled by |PrefetchService| and |
| 108 | // determine the type of prefetch required. |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 109 | // TODO(crbug.com/40215782): Once this code becomes enabled by default |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 110 | // 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 Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 113 | std::vector<PrefetchUrlParams> prefetches; |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 114 | |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 115 | // 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 Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 119 | 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 Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 124 | } |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 125 | } |
| 126 | base::flat_set<GURL> url_set(std::move(urls_from_candidates)); |
Hiroshige Hayashizaki | 22be5e4c | 2025-03-07 21:39:59 | [diff] [blame] | 127 | std::vector<std::pair<GURL, PreloadingType>> prefetches_to_evict; |
kenoss | f7d06314 | 2024-10-10 08:34:28 | [diff] [blame] | 128 | 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 Hayashizaki | 22be5e4c | 2025-03-07 21:39:59 | [diff] [blame] | 138 | 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 Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 143 | } |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 144 | } |
Hiroshige Hayashizaki | 22be5e4c | 2025-03-07 21:39:59 | [diff] [blame] | 145 | for (const auto& all_prefetches_key : prefetches_to_evict) { |
| 146 | all_prefetches_.erase(all_prefetches_key); |
Adithya Srinivasan | b6048349 | 2023-06-14 21:22:14 | [diff] [blame] | 147 | } |
| 148 | |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 149 | auto should_process_entry = |
| 150 | [&](const blink::mojom::SpeculationCandidatePtr& candidate) { |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 151 | // This code doesn't not support speculation candidates with the action |
| 152 | // of |blink::mojom::SpeculationAction::kPrefetchWithSubresources|. See |
| 153 | // https://crbug.com/1296309. |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 154 | if (candidate->action != blink::mojom::SpeculationAction::kPrefetch) { |
| 155 | return false; |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 156 | } |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 157 | |
Hiroki Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 158 | prefetches.emplace_back(candidate); |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 159 | return true; |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 160 | }; |
| 161 | |
Andrew Rayskiy | f6599036 | 2024-02-27 18:43:24 | [diff] [blame] | 162 | std::erase_if(candidates, should_process_entry); |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 163 | |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 164 | for (auto& [prefetch_url, prefetch_type, referrer, no_vary_search_hint, |
| 165 | tags] : prefetches) { |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 166 | // Immediate candidates are enacted by the same predictor that creates them. |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 167 | const PreloadingPredictor enacting_predictor = |
| 168 | GetPredictorForPreloadingTriggerType(prefetch_type.trigger_type()); |
kenoss | 8644f6bf | 2025-02-10 05:51:44 | [diff] [blame] | 169 | PrefetchUrl(prefetch_url, prefetch_type, enacting_predictor, referrer, |
Hiroki Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 170 | std::move(tags), no_vary_search_hint, |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 171 | PreloadPipelineInfo::Create( |
kenoss | 8644f6bf | 2025-02-10 05:51:44 | [diff] [blame] | 172 | /*planned_max_preloading_type=*/PreloadingType::kPrefetch)); |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 173 | } |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 174 | |
| 175 | if (PrefetchService* prefetch_service = GetPrefetchService()) { |
| 176 | prefetch_service->OnCandidatesUpdated(); |
| 177 | } |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 178 | } |
| 179 | |
Adithya Srinivasan | 3bdb5ce | 2023-06-05 13:22:12 | [diff] [blame] | 180 | bool PrefetchDocumentManager::MaybePrefetch( |
| 181 | blink::mojom::SpeculationCandidatePtr candidate, |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 182 | const PreloadingPredictor& enacting_predictor) { |
Adithya Srinivasan | 3bdb5ce | 2023-06-05 13:22:12 | [diff] [blame] | 183 | if (candidate->action != blink::mojom::SpeculationAction::kPrefetch) { |
| 184 | return false; |
| 185 | } |
| 186 | |
Hiroki Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 187 | 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, |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 191 | PreloadPipelineInfo::Create( |
kenoss | 8644f6bf | 2025-02-10 05:51:44 | [diff] [blame] | 192 | /*planned_max_preloading_type=*/PreloadingType::kPrefetch)); |
Adithya Srinivasan | 3bdb5ce | 2023-06-05 13:22:12 | [diff] [blame] | 193 | return true; |
| 194 | } |
| 195 | |
kenoss | 9d57ee7b | 2024-06-03 01:36:43 | [diff] [blame] | 196 | void PrefetchDocumentManager::PrefetchAheadOfPrerender( |
kenoss | 3bd73b8 | 2024-10-10 20:33:49 | [diff] [blame] | 197 | scoped_refptr<PreloadPipelineInfo> preload_pipeline_info, |
kenoss | 9d57ee7b | 2024-06-03 01:36:43 | [diff] [blame] | 198 | blink::mojom::SpeculationCandidatePtr candidate, |
| 199 | const PreloadingPredictor& enacting_predictor) { |
Hiroki Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 200 | 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)); |
kenoss | 9d57ee7b | 2024-06-03 01:36:43 | [diff] [blame] | 204 | } |
| 205 | |
Iman Saboori | 65c356d | 2022-07-15 14:47:47 | [diff] [blame] | 206 | void PrefetchDocumentManager::PrefetchUrl( |
| 207 | const GURL& url, |
| 208 | const PrefetchType& prefetch_type, |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 209 | const PreloadingPredictor& enacting_predictor, |
Kevin McNee | e6ca089 | 2022-09-28 15:36:22 | [diff] [blame] | 210 | const blink::mojom::Referrer& referrer, |
Hiroki Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 211 | std::optional<SpeculationRulesTags> speculation_rules_tags, |
Rulong Chen(陈汝龙) | bf12169c | 2024-12-16 05:38:16 | [diff] [blame] | 212 | const network::mojom::NoVarySearchPtr& mojo_no_vary_search_hint, |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 213 | scoped_refptr<PreloadPipelineInfo> preload_pipeline_info) { |
kenoss | f7d06314 | 2024-10-10 08:34:28 | [diff] [blame] | 214 | const std::pair<GURL, PreloadingType> all_prefetches_key = |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 215 | std::make_pair(url, PreloadPipelineInfoImpl::From(*preload_pipeline_info) |
| 216 | .planned_max_preloading_type()); |
kenoss | f7d06314 | 2024-10-10 08:34:28 | [diff] [blame] | 217 | |
| 218 | // Skip prefetches that have already been requested. |
| 219 | auto prefetch_container_iter = all_prefetches_.find(all_prefetches_key); |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 220 | if (prefetch_container_iter != all_prefetches_.end() && |
Hiroshige Hayashizaki | 22be5e4c | 2025-03-07 21:39:59 | [diff] [blame] | 221 | static_cast<PrefetchHandleImpl*>(prefetch_container_iter->second.get()) |
| 222 | ->IsAlive()) { |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 223 | return; |
| 224 | } |
| 225 | |
Jeremy Roman | 7308f28 | 2024-02-01 03:13:29 | [diff] [blame] | 226 | // 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(陈汝龙) | bf12169c | 2024-12-16 05:38:16 | [diff] [blame] | 232 | 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 Tinta | 68a4580 | 2023-04-05 18:32:20 | [diff] [blame] | 236 | } |
Hiroshige Hayashizaki | a00e4c8 | 2023-10-31 20:20:17 | [diff] [blame] | 237 | PrefetchService* prefetch_service = GetPrefetchService(); |
Hiroshige Hayashizaki | 7a34d018 | 2023-11-07 20:54:34 | [diff] [blame] | 238 | if (!prefetch_service) { |
| 239 | return; |
| 240 | } |
| 241 | |
Taiyo Mizuhashi | 0192d3f | 2024-02-15 05:09:43 | [diff] [blame] | 242 | auto* web_contents = WebContents::FromRenderFrameHost(&render_frame_host()); |
| 243 | auto* preloading_data = |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 244 | PreloadingDataImpl::GetOrCreateForWebContents(web_contents); |
Taiyo Mizuhashi | 0192d3f | 2024-02-15 05:09:43 | [diff] [blame] | 245 | |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 246 | const PreloadingPredictor creating_predictor = |
| 247 | GetPredictorForPreloadingTriggerType(prefetch_type.trigger_type()); |
Taiyo Mizuhashi | 0192d3f | 2024-02-15 05:09:43 | [diff] [blame] | 248 | PreloadingURLMatchCallback matcher = |
| 249 | PreloadingDataImpl::GetPrefetchServiceMatcher( |
Hiroshige Hayashizaki | c625e81 | 2025-08-19 18:42:35 | [diff] [blame] | 250 | *prefetch_service, PrefetchKey(document_token_, url)); |
Taiyo Mizuhashi | 0192d3f | 2024-02-15 05:09:43 | [diff] [blame] | 251 | |
| 252 | auto* attempt = |
| 253 | static_cast<PreloadingAttemptImpl*>(preloading_data->AddPreloadingAttempt( |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 254 | creating_predictor, enacting_predictor, PreloadingType::kPrefetch, |
kenoss | 8644f6bf | 2025-02-10 05:51:44 | [diff] [blame] | 255 | std::move(matcher), |
Taiyo Mizuhashi | 0192d3f | 2024-02-15 05:09:43 | [diff] [blame] | 256 | web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId())); |
| 257 | |
| 258 | attempt->SetSpeculationEagerness(prefetch_type.GetEagerness()); |
Takashi Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 259 | CHECK(!IsImmediateSpeculationEagerness(prefetch_type.GetEagerness()) || |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 260 | creating_predictor == enacting_predictor); |
Taiyo Mizuhashi | 0192d3f | 2024-02-15 05:09:43 | [diff] [blame] | 261 | |
| 262 | // `PreloadingPrediction` is added in `PreloadingDecider`. |
| 263 | |
Iman Saboori | 65c356d | 2022-07-15 14:47:47 | [diff] [blame] | 264 | auto container = std::make_unique<PrefetchContainer>( |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 265 | static_cast<RenderFrameHostImpl&>(render_frame_host()), document_token_, |
Hiroki Nakagawa | c33034f | 2025-03-31 07:39:30 | [diff] [blame] | 266 | url, prefetch_type, referrer, std::move(speculation_rules_tags), |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 267 | std::move(no_vary_search_hint), /*priority=*/std::nullopt, |
| 268 | weak_method_factory_.GetWeakPtr(), std::move(preload_pipeline_info), |
| 269 | attempt->GetWeakPtr()); |
Hiroshige Hayashizaki | 3876eee | 2023-03-27 04:42:04 | [diff] [blame] | 270 | DVLOG(1) << *container << ": created"; |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 271 | |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 272 | referring_page_metrics_.prefetch_attempted_count++; |
| 273 | |
Hiroshige Hayashizaki | 22be5e4c | 2025-03-07 21:39:59 | [diff] [blame] | 274 | all_prefetches_[all_prefetches_key] = |
| 275 | prefetch_service->AddPrefetchContainerWithHandle(std::move(container)); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 276 | } |
| 277 | |
Iman Saboori | ab85b13 | 2022-11-15 22:17:23 | [diff] [blame] | 278 | bool PrefetchDocumentManager::IsPrefetchAttemptFailedOrDiscarded( |
| 279 | const GURL& url) { |
Hiroshige Hayashizaki | a129d91c | 2025-03-05 22:28:12 | [diff] [blame] | 280 | PrefetchService* prefetch_service = GetPrefetchService(); |
| 281 | if (!prefetch_service) { |
Iman Saboori | ab85b13 | 2022-11-15 22:17:23 | [diff] [blame] | 282 | return true; |
Iman Saboori | ab85b13 | 2022-11-15 22:17:23 | [diff] [blame] | 283 | } |
Hiroshige Hayashizaki | a129d91c | 2025-03-05 22:28:12 | [diff] [blame] | 284 | |
| 285 | return prefetch_service->IsPrefetchAttemptFailedOrDiscardedInternal( |
| 286 | base::PassKey<PrefetchDocumentManager>(), |
Hiroshige Hayashizaki | c625e81 | 2025-08-19 18:42:35 | [diff] [blame] | 287 | PrefetchKey(document_token_, url)); |
Iman Saboori | ab85b13 | 2022-11-15 22:17:23 | [diff] [blame] | 288 | } |
| 289 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 290 | // static |
| 291 | void PrefetchDocumentManager::SetPrefetchServiceForTesting( |
| 292 | PrefetchService* prefetch_service) { |
| 293 | g_prefetch_service_for_testing = prefetch_service; |
| 294 | } |
| 295 | |
kenoss | 087ae23 | 2024-12-10 05:06:04 | [diff] [blame] | 296 | void PrefetchDocumentManager::ResetPrefetchAheadOfPrerenderIfExist( |
| 297 | const GURL& url) { |
Lingqi Chi | 844e05d4 | 2025-07-23 02:50:50 | [diff] [blame] | 298 | // TODO(https://crbug.com/428500219): Update the logic for |
| 299 | // prerender-until-script. |
kenoss | 087ae23 | 2024-12-10 05:06:04 | [diff] [blame] | 300 | auto it = |
| 301 | all_prefetches_.find(std::make_pair(url, PreloadingType::kPrerender)); |
| 302 | if (it == all_prefetches_.end()) { |
| 303 | return; |
| 304 | } |
| 305 | |
Hiroshige Hayashizaki | 22be5e4c | 2025-03-07 21:39:59 | [diff] [blame] | 306 | static_cast<PrefetchHandleImpl*>(it->second.get()) |
| 307 | ->SetPrefetchStatusOnReleaseStartedPrefetch( |
kenoss | 087ae23 | 2024-12-10 05:06:04 | [diff] [blame] | 308 | PrefetchStatus::kPrefetchEvictedAfterCandidateRemoved); |
kenoss | 087ae23 | 2024-12-10 05:06:04 | [diff] [blame] | 309 | all_prefetches_.erase(it); |
| 310 | } |
| 311 | |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 312 | PrefetchService* 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 Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 323 | void PrefetchDocumentManager::OnEligibilityCheckComplete(bool is_eligible) { |
| 324 | if (is_eligible) |
| 325 | referring_page_metrics_.prefetch_eligible_count++; |
| 326 | } |
| 327 | |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 328 | void PrefetchDocumentManager::OnPrefetchSuccessful( |
| 329 | PrefetchContainer* prefetch) { |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 330 | referring_page_metrics_.prefetch_successful_count++; |
Takashi Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 331 | if (IsImmediateSpeculationEagerness( |
Hiroshige Hayashizaki | f55280f6 | 2025-08-19 17:23:20 | [diff] [blame] | 332 | prefetch->request().prefetch_type().GetEagerness())) { |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 333 | completed_immediate_prefetches_.push_back(prefetch->GetWeakPtr()); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 334 | } else { |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 335 | completed_non_immediate_prefetches_.push_back(prefetch->GetWeakPtr()); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 336 | } |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 337 | } |
| 338 | |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 339 | std::tuple<bool, base::WeakPtr<PrefetchContainer>> |
| 340 | PrefetchDocumentManager::CanPrefetchNow(PrefetchContainer* prefetch) { |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 341 | 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 Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 349 | if (IsImmediateSpeculationEagerness( |
Hiroshige Hayashizaki | f55280f6 | 2025-08-19 17:23:20 | [diff] [blame] | 350 | prefetch->request().prefetch_type().GetEagerness())) { |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 351 | return std::make_tuple(completed_immediate_prefetches_.size() < |
| 352 | kMaxNumberOfImmediatePrefetchesPerPage, |
| 353 | nullptr); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 354 | } else { |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 355 | if (completed_non_immediate_prefetches_.size() < |
| 356 | kMaxNumberOfNonImmediatePrefetchesPerPage) { |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 357 | return std::make_tuple(true, nullptr); |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 358 | } |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 359 | // We are at capacity, and now need to evict the oldest non-immediate |
| 360 | // prefetch to make space for a new one. |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 361 | DCHECK(GetPrefetchService()); |
| 362 | base::WeakPtr<PrefetchContainer> oldest_prefetch = |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 363 | completed_non_immediate_prefetches_.front(); |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 364 | // TODO(crbug.com/40064525): We should also be checking if the prefetch is |
Adithya Srinivasan | 6054e13 | 2023-05-18 17:38:39 | [diff] [blame] | 365 | // currently being used to serve a navigation. In that scenario, evicting |
| 366 | // doesn't make sense. |
Adithya Srinivasan | d5e37cb | 2023-07-05 14:45:23 | [diff] [blame] | 367 | return std::make_tuple(true, oldest_prefetch); |
Adithya Srinivasan | f393dd0 | 2023-05-16 20:26:16 | [diff] [blame] | 368 | } |
| 369 | } |
| 370 | |
Adithya Srinivasan | d476f4f8 | 2023-06-20 15:55:13 | [diff] [blame] | 371 | void PrefetchDocumentManager::SetPrefetchDestructionCallback( |
| 372 | PrefetchDestructionCallback callback) { |
| 373 | prefetch_destruction_callback_ = std::move(callback); |
| 374 | } |
| 375 | |
| 376 | void PrefetchDocumentManager::PrefetchWillBeDestroyed( |
| 377 | PrefetchContainer* prefetch) { |
| 378 | prefetch_destruction_callback_.Run(prefetch->GetURL()); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 379 | |
| 380 | std::vector<base::WeakPtr<PrefetchContainer>>& completed_prefetches = |
Takashi Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 381 | IsImmediateSpeculationEagerness( |
Hiroshige Hayashizaki | f55280f6 | 2025-08-19 17:23:20 | [diff] [blame] | 382 | prefetch->request().prefetch_type().GetEagerness()) |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 383 | ? completed_immediate_prefetches_ |
| 384 | : completed_non_immediate_prefetches_; |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 385 | auto it = std::ranges::find(completed_prefetches, prefetch->key(), |
| 386 | [&](const auto& p) { return p->key(); }); |
Adithya Srinivasan | 9d1b6fa | 2024-08-29 15:04:35 | [diff] [blame] | 387 | if (it != completed_prefetches.end()) { |
| 388 | completed_prefetches.erase(it); |
Adithya Srinivasan | 6bdb9bcbf | 2023-06-23 21:28:46 | [diff] [blame] | 389 | } |
Adithya Srinivasan | d1c68ba | 2023-05-30 19:54:25 | [diff] [blame] | 390 | } |
| 391 | |
Max Curran | 6c2835ea | 2022-03-07 19:52:38 | [diff] [blame] | 392 | DOCUMENT_USER_DATA_KEY_IMPL(PrefetchDocumentManager); |
| 393 | |
| 394 | } // namespace content |