blob: e26cb0ec616e9e7ad14633c0a9fe8d3410d7dcf4 [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#ifndef CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_
6#define CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_
Max Curran646fb642022-03-16 00:44:097
Arthur Sonzognic686e8f2024-01-11 08:36:378#include <optional>
Max Curran646fb642022-03-16 00:44:099#include <utility>
Victor Hugo Vianna Silva00692722025-03-18 19:51:4810#include <variant>
Max Curran646fb642022-03-16 00:44:0911
Ali Hijazi31628912023-06-05 18:13:4112#include "base/memory/raw_ref.h"
Max Curran646fb642022-03-16 00:44:0913#include "base/memory/weak_ptr.h"
kenossf6fbd5652024-09-04 00:40:2814#include "base/observer_list.h"
15#include "base/observer_list_types.h"
Max Curranc4445fc2022-06-02 18:43:4316#include "base/time/time.h"
kenoss1ce36df592024-12-03 01:04:3517#include "content/browser/devtools/network_service_devtools_observer.h"
elabadysayedf7d6b00f2025-02-05 11:27:0018#include "content/browser/preloading/prefetch/prefetch_params.h"
Max Curran210cffa2022-09-06 22:24:3119#include "content/browser/preloading/prefetch/prefetch_probe_result.h"
Sreeja Kamishettyf66553a2022-07-14 17:41:2720#include "content/browser/preloading/prefetch/prefetch_status.h"
Hiroshige Hayashizakic853c0302023-09-13 08:51:0721#include "content/browser/preloading/prefetch/prefetch_streaming_url_loader_common_types.h"
Sreeja Kamishettyf66553a2022-07-14 17:41:2722#include "content/browser/preloading/prefetch/prefetch_type.h"
kenossc3f9a2c2025-03-06 15:35:5123#include "content/browser/preloading/preload_pipeline_info_impl.h"
HuanPo Lin740620b2025-03-21 12:37:2624#include "content/browser/preloading/speculation_rules/speculation_rules_tags.h"
Max Curran646fb642022-03-16 00:44:0925#include "content/common/content_export.h"
26#include "content/public/browser/global_routing_id.h"
Taiyo Mizuhashid7c856992025-06-23 08:56:0227#include "content/public/browser/prefetch_priority.h"
Wayne Jackson Jr.b22d53b22024-11-15 11:40:0628#include "content/public/browser/prefetch_request_status_listener.h"
kenossc3f9a2c2025-03-06 15:35:5129#include "content/public/browser/preload_pipeline_info.h"
Hiroshige Hayashizaki939c5ed42023-11-01 03:29:2130#include "content/public/browser/preloading.h"
Hiroshige Hayashizakia00e4c82023-10-31 20:20:1731#include "content/public/browser/preloading_data.h"
Liviu Tinta68a45802023-04-05 18:32:2032#include "net/http/http_no_vary_search_data.h"
Wayne Jackson Jr.1b7322472024-10-29 13:08:5133#include "net/http/http_request_headers.h"
Max Curran210cffa2022-09-06 22:24:3134#include "services/metrics/public/cpp/ukm_source_id.h"
Hiroshige Hayashizaki2df45292023-10-10 22:59:0335#include "third_party/blink/public/common/tokens/tokens.h"
Max Curran646fb642022-03-16 00:44:0936#include "url/gurl.h"
37
Max Curran18a6f2b2022-05-02 23:13:2438namespace network {
Max Curranc4445fc2022-06-02 18:43:4339namespace mojom {
40class CookieManager;
41} // namespace mojom
Max Curran18a6f2b2022-05-02 23:13:2442} // namespace network
43
Max Curran646fb642022-03-16 00:44:0944namespace content {
45
Jeremy Roman586b5ec2024-02-13 15:14:4046class BrowserContext;
Max Curranc4445fc2022-06-02 18:43:4347class PrefetchCookieListener;
Max Curran18a6f2b2022-05-02 23:13:2448class PrefetchDocumentManager;
49class PrefetchNetworkContext;
Hiroshige Hayashizakic853c0302023-09-13 08:51:0750class PrefetchResponseReader;
Max Curranc4445fc2022-06-02 18:43:4351class PrefetchService;
Hiroshige Hayashizaki386c5022025-08-12 14:43:3752class PrefetchServingHandle;
Max Curran892ca5422022-12-12 20:55:3453class PrefetchServingPageMetricsContainer;
Hiroshige Hayashizaki87a43932025-08-12 06:57:2554class PrefetchSingleRedirectHop;
Max Curran892ca5422022-12-12 20:55:3455class PrefetchStreamingURLLoader;
William Liu77089052022-12-15 18:53:3556class PreloadingAttempt;
Max Currancc1ab0c2022-09-12 22:03:1157class ProxyLookupClientImpl;
Hiroshige Hayashizaki2cbf67b92023-10-23 17:40:0758class RenderFrameHost;
Kevin McNee06824c72024-02-06 18:59:5259class RenderFrameHostImpl;
Taiyo Mizuhashi09f571f2025-08-04 16:05:5460enum class PrefetchPotentialCandidateServingResult;
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:0861enum class PrefetchServableState;
Max Curran18a6f2b2022-05-02 23:13:2462
William Liuef934732022-11-02 22:46:2963// Holds the relevant size information of the prefetched response. The struct is
64// installed onto `PrefetchContainer`, and gets passed into
65// `PrefetchFromStringURLLoader` to notify the associated `URLLoaderClient` of
66// the actual size of the response, as `PrefetchFromStringURLLoader` is not
67// aware of the prefetched request.
68struct PrefetchResponseSizes {
69 int64_t encoded_data_length;
70 int64_t encoded_body_length;
71 int64_t decoded_body_length;
72};
73
Max Curran646fb642022-03-16 00:44:0974// This class contains the state for a request to prefetch a specific URL.
Hiroshige Hayashizaki73e42892023-06-26 16:48:4875//
Hiroshige Hayashizaki87a43932025-08-12 06:57:2576// A `PrefetchContainer` can have multiple
77// `PrefetchSingleRedirectHop`s and `PrefetchStreamingURLLoader`s to
78// support redirects. Each `PrefetchSingleRedirectHop` in
79// `redirect_chain_` corresponds to a single redirect hop, while a single
80// `PrefetchStreamingURLLoader` can receive multiple redirect hops unless
81// network context switching is needed.
Hiroshige Hayashizaki73e42892023-06-26 16:48:4882//
83// For example:
84//
85// |PrefetchStreamingURLLoader A-----| |PrefetchStreamingURLLoader B ---------|
86// HandleRedirect - HandleRedirect - HandleRedirect - ReceiveResponse-Finish
Hiroshige Hayashizaki87a43932025-08-12 06:57:2587// |S.RedirectHop0-| |S.RedirectHop1-| |S.RedirectHop2-| |S.RedirectHop3------|
Hiroshige Hayashizaki73e42892023-06-26 16:48:4888//
89// While prefetching (see methods named like "ForCurrentPrefetch" or
Hiroshige Hayashizaki87a43932025-08-12 06:57:2590// "ToPrefetch"), `PrefetchSingleRedirectHop`es and
91// `PrefetchStreamingURLLoader`s (among other members) are added and filled. The
92// steps for creating these objects and associating with each other span
93// multiple classes/methods:
Hiroshige Hayashizaki73e42892023-06-26 16:48:4894//
Hiroshige Hayashizaki87a43932025-08-12 06:57:2595// 1. A new `PrefetchSingleRedirectHop` and thus a new
Hiroshige Hayashizaki73e42892023-06-26 16:48:4896// `PrefetchResponseReader` is created and added to `redirect_chain_`.
97// This is done either in:
98// - `PrefetchContainer` constructor [for an initial request], or
99// - `AddRedirectHop()` [for a redirect].
100//
101// 2. The new `PrefetchResponseReader` (created at Step 1, referenced as
102// `GetResponseReaderForCurrentPrefetch()`) is associated with the
103// `PrefetchStreamingURLLoader` to be used.
104// This is done either in (see the indirect call sites of
105// `PrefetchStreamingURLLoader::SetResponseReader()`):
106// - `PrefetchService::StartSinglePrefetch()` [initial request] or
kenoss0c7bbc72024-07-24 08:52:40107// - `PrefetchService::OnGotEligibilityForRedirect()` [redirect].
Hiroshige Hayashizaki73e42892023-06-26 16:48:48108// A new `PrefetchStreamingURLLoader` is also created if needed in
109// `PrefetchService::MakePrefetchRequest()`.
Max Curran646fb642022-03-16 00:44:09110class CONTENT_EXPORT PrefetchContainer {
111 public:
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37112 // Ctor used for renderer-initiated prefetch.
Max Curran646fb642022-03-16 00:44:09113 PrefetchContainer(
Kevin McNee06824c72024-02-06 18:59:52114 RenderFrameHostImpl& referring_render_frame_host,
Hiroshige Hayashizaki2df45292023-10-10 22:59:03115 const blink::DocumentToken& referring_document_token,
Max Curran646fb642022-03-16 00:44:09116 const GURL& url,
Max Curran18a6f2b2022-05-02 23:13:24117 const PrefetchType& prefetch_type,
Kevin McNeee6ca0892022-09-28 15:36:22118 const blink::mojom::Referrer& referrer,
HuanPo Lin740620b2025-03-21 12:37:26119 std::optional<SpeculationRulesTags> speculation_rules_tags,
Rulong Chen(陈汝龙)bf12169c2024-12-16 05:38:16120 std::optional<net::HttpNoVarySearchData> no_vary_search_hint,
Taiyo Mizuhashid7c856992025-06-23 08:56:02121 std::optional<PrefetchPriority> priority,
Hiroshige Hayashizakia00e4c82023-10-31 20:20:17122 base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager,
kenoss3bd73b82024-10-10 20:33:49123 scoped_refptr<PreloadPipelineInfo> preload_pipeline_info,
Taiyo Mizuhashi0192d3f2024-02-15 05:09:43124 base::WeakPtr<PreloadingAttempt> attempt = nullptr);
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37125
126 // Ctor used for browser-initiated prefetch.
127 // We can pass the referring origin of prefetches via `referring_origin` if
Taiyo Mizuhashi9dfeb632024-10-24 08:44:20128 // necessary.
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37129 PrefetchContainer(
130 WebContents& referring_web_contents,
131 const GURL& url,
132 const PrefetchType& prefetch_type,
Taiyo Mizuhashi49959d02025-04-22 16:07:54133 const std::string& embedder_histogram_suffix,
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37134 const blink::mojom::Referrer& referrer,
135 const std::optional<url::Origin>& referring_origin,
Rulong Chen(陈汝龙)bf12169c2024-12-16 05:38:16136 std::optional<net::HttpNoVarySearchData> no_vary_search_hint,
Taiyo Mizuhashid7c856992025-06-23 08:56:02137 std::optional<PrefetchPriority> priority,
kenossa1af66f12025-03-07 06:10:55138 scoped_refptr<PreloadPipelineInfo> preload_pipeline_info,
Taiyo Mizuhashi26f86c6b32024-10-02 03:58:46139 base::WeakPtr<PreloadingAttempt> attempt = nullptr,
140 std::optional<PreloadingHoldbackStatus> holdback_status_override =
kenoss6938554c2025-06-10 10:18:17141 std::nullopt,
142 std::optional<base::TimeDelta> ttl = std::nullopt);
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37143
Wayne Jackson Jr.5b1dc042024-09-09 12:53:10144 // Ctor used for browser-initiated prefetch that doesn't depend on web
145 // contents. We can pass the referring origin of prefetches via
Taiyo Mizuhashi9dfeb632024-10-24 08:44:20146 // `referrer_origin` if necessary.
Wayne Jackson Jr.5b1dc042024-09-09 12:53:10147 PrefetchContainer(
148 BrowserContext* browser_context,
149 const GURL& url,
150 const PrefetchType& prefetch_type,
Taiyo Mizuhashi49959d02025-04-22 16:07:54151 const std::string& embedder_histogram_suffix,
Wayne Jackson Jr.5b1dc042024-09-09 12:53:10152 const blink::mojom::Referrer& referrer,
153 bool javascript_enabled,
154 const std::optional<url::Origin>& referring_origin,
Rulong Chen(陈汝龙)bf12169c2024-12-16 05:38:16155 std::optional<net::HttpNoVarySearchData> no_vary_search_hint,
Taiyo Mizuhashid7c856992025-06-23 08:56:02156 std::optional<PrefetchPriority> priority,
Wayne Jackson Jr.03a15fa62024-09-16 14:42:15157 base::WeakPtr<PreloadingAttempt> attempt = nullptr,
Wayne Jackson Jr.1b7322472024-10-29 13:08:51158 const net::HttpRequestHeaders& additional_headers = {},
Wayne Jackson Jr.b22d53b22024-11-15 11:40:06159 std::unique_ptr<PrefetchRequestStatusListener> request_status_listener =
elabadysayedf7d6b00f2025-02-05 11:27:00160 nullptr,
kenoss70bfbfe2025-06-10 08:04:42161 base::TimeDelta ttl = PrefetchContainerDefaultTtlInPrefetchService(),
Taiyo Mizuhashicd08a8f2025-06-10 17:27:32162 bool should_append_variations_header = true,
163 bool should_disable_block_until_head_timeout = false);
Wayne Jackson Jr.5b1dc042024-09-09 12:53:10164
Max Curran646fb642022-03-16 00:44:09165 ~PrefetchContainer();
166
167 PrefetchContainer(const PrefetchContainer&) = delete;
168 PrefetchContainer& operator=(const PrefetchContainer&) = delete;
169
kenoss39741f512024-09-05 02:20:37170 // Key for managing and matching prefetches.
171 //
172 // This key can either represent
173 //
174 // - the key of a prefetch (typically named `prefetch_key`, and its URL is the
175 // URL of the prefetched main resource); or
176 // - the key of a navigation (typically named `navigated_key`, and its URL is
177 // the navigation request URL).
178 //
179 // TODO(crbug.com/364751887): This distinction is not perfect. Enforce it as
180 // much as possible.
181 //
182 // For prefetch, non URL part is given as the following:
183 //
184 // - If the prefetch is renderer-initiated, `DocumentToken` of the initiating
185 // document is used.
186 // - If the prefetch is browser-initiated, `std::nullopt` (for
187 // `referring_document_token`) is used.
188 // - If the prefetch is embedder-initiated, `net::NetworkIsolationKey` of the
kenoss4d951662025-08-13 18:11:40189 // embedder is used. See crbug.com/40942681.
kenoss39741f512024-09-05 02:20:37190 //
191 // For navigation, `std::optional<DocumentToken>` of the initiating document
192 // of the navigation is used.
193 //
194 // See also the doc on crbug.com/40946257 for more context.
Kouhei Ueno34c7c69152023-11-16 04:42:42195 class CONTENT_EXPORT Key {
Kouhei Ueno45b00ef22023-11-10 02:22:58196 public:
197 Key() = delete;
kenoss39741f512024-09-05 02:20:37198 Key(net::NetworkIsolationKey nik, GURL url);
199 Key(std::optional<blink::DocumentToken> referring_document_token, GURL url);
Kouhei Ueno34c7c69152023-11-16 04:42:42200 ~Key();
201
kenoss4dc068662024-10-04 05:03:50202 // Movable and copyable.
203 Key(Key&& other);
204 Key& operator=(Key&& other);
205 Key(const Key& other);
206 Key& operator=(const Key& other);
Kouhei Ueno45b00ef22023-11-10 02:22:58207
208 bool operator==(const Key& rhs) const = default;
209 bool operator<(const Key& rhs) const {
Kouhei Ueno34c7c69152023-11-16 04:42:42210 if (referring_document_token_or_nik_ !=
211 rhs.referring_document_token_or_nik_) {
212 return referring_document_token_or_nik_ <
213 rhs.referring_document_token_or_nik_;
Kouhei Ueno45b00ef22023-11-10 02:22:58214 }
kenoss39741f512024-09-05 02:20:37215 return url_ < rhs.url_;
Kouhei Ueno45b00ef22023-11-10 02:22:58216 }
217
kenoss39741f512024-09-05 02:20:37218 const GURL& url() const { return url_; }
Kouhei Ueno45b00ef22023-11-10 02:22:58219
Kouhei Uenoebacf892023-11-14 03:41:43220 Key WithNewUrl(const GURL& new_url) const {
Victor Hugo Vianna Silva00692722025-03-18 19:51:48221 return std::visit([&](const auto& e) { return Key(e, new_url); },
222 referring_document_token_or_nik_);
Kouhei Uenoebacf892023-11-14 03:41:43223 }
224
225 bool NonUrlPartIsSame(const Key& other) const {
Kouhei Ueno34c7c69152023-11-16 04:42:42226 return referring_document_token_or_nik_ ==
227 other.referring_document_token_or_nik_;
Kouhei Uenoebacf892023-11-14 03:41:43228 }
229
Kouhei Ueno45b00ef22023-11-10 02:22:58230 private:
231 friend CONTENT_EXPORT std::ostream& operator<<(std::ostream& ostream,
232 const Key& prefetch_key);
233
Victor Hugo Vianna Silva00692722025-03-18 19:51:48234 std::variant<std::optional<blink::DocumentToken>, net::NetworkIsolationKey>
Kouhei Ueno34c7c69152023-11-16 04:42:42235 referring_document_token_or_nik_;
kenoss4dc068662024-10-04 05:03:50236 GURL url_;
Kouhei Ueno45b00ef22023-11-10 02:22:58237 };
238
kenossf6fbd5652024-09-04 00:40:28239 // Observer interface to listen to lifecycle events of `PrefetchContainer`.
240 //
241 // Each callback is called at most once in the lifecycle of a container.
242 //
243 // Be careful about using this. This is designed only for
Hiroshige Hayashizaki6a103bad2025-07-11 02:15:32244 // `PrefetchMatchResolver` and some other prefetch-internal classes.
kenossf6fbd5652024-09-04 00:40:28245 class Observer : public base::CheckedObserver {
246 public:
247 // Called at the head of dtor.
248 //
249 // TODO(crbug.com/356314759): Update the description to "Called just
250 // before dtor is called."
251 virtual void OnWillBeDestroyed(PrefetchContainer& prefetch_container) = 0;
kenossb68c9e82024-10-10 10:11:15252 // Called when initial eligibility is got.
253 virtual void OnGotInitialEligibility(PrefetchContainer& prefetch_container,
254 PreloadingEligibility eligibility) = 0;
kenossf6fbd5652024-09-04 00:40:28255 // Called if non-redirect header of prefetch response is determined, i.e.
256 // successfully received or fetch requests including redirects failed.
257 // Callers can check success/failure by `GetNonRedirectHead()`.
258 virtual void OnDeterminedHead(PrefetchContainer& prefetch_container) = 0;
kenossb4e57f72025-06-16 08:28:40259 // Called when load of prefetch completed or failed.
260 virtual void OnPrefetchCompletedOrFailed(
Hiroshige Hayashizaki6a103bad2025-07-11 02:15:32261 PrefetchContainer& prefetch_container,
kenossb4e57f72025-06-16 08:28:40262 const network::URLLoaderCompletionStatus& completion_status,
263 const std::optional<int>& response_code) = 0;
kenossf6fbd5652024-09-04 00:40:28264 };
265
266 void OnWillBeDestroyed();
267
kenossaf6e0ae2024-09-05 03:06:50268 const Key& key() const { return key_; }
Max Curran646fb642022-03-16 00:44:09269
Rakina Zata Amni39d8e7e2022-10-20 18:18:30270 // The ID of the RenderFrameHost that triggered the prefetch.
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37271 const GlobalRenderFrameHostId& GetReferringRenderFrameHostId() const {
Max Curran646fb642022-03-16 00:44:09272 return referring_render_frame_host_id_;
273 }
Kevin McNee06824c72024-02-06 18:59:52274 bool HasSameReferringURLForMetrics(const PrefetchContainer& other) const;
Max Curran646fb642022-03-16 00:44:09275
Max Curran5d4da4b42023-03-10 23:41:46276 // The initial URL that was requested to be prefetched.
kenoss39741f512024-09-05 02:20:37277 const GURL& GetURL() const { return key_.url(); }
Max Curran646fb642022-03-16 00:44:09278
Jeremy Roman45c89d012023-08-30 21:22:02279 // The current URL being fetched.
280 GURL GetCurrentURL() const;
281
282 // The previous URL, if this has been redirected. Invalid to call otherwise.
283 GURL GetPreviousURL() const;
284
HuanPo Lin740620b2025-03-21 12:37:26285 // Returns whether the tags of the speculation rules that triggered this
286 // prefetch exists.
287 bool HasSpeculationRulesTags() { return speculation_rules_tags_.has_value(); }
288
HuanPo Lin9b730372025-03-28 05:50:45289 // Returns the serialized string of speculation rules tags.
290 std::optional<std::string> GetSpeculationRulesTagsHeaderString() {
291 return speculation_rules_tags_->ConvertStringToHeaderString();
292 }
293
Max Curran646fb642022-03-16 00:44:09294 // The type of this prefetch. Controls how the prefetch is handled.
295 const PrefetchType& GetPrefetchType() const { return prefetch_type_; }
296
Taiyo Mizuhashidd5dfdf2024-03-11 17:04:10297 // Whether this prefetch is initiated by renderer processes.
298 // Currently this is equivalent to whether the trigger type is Speculation
299 // Rules or not.
300 bool IsRendererInitiated() const;
301
Taiyo Mizuhashi21559462024-02-22 00:07:56302 // The origin and that initiates the prefetch request.
Taiyo Mizuhashi9dfeb632024-10-24 08:44:20303 const std::optional<url::Origin> GetReferringOrigin() const {
304 return referring_origin_;
305 }
Taiyo Mizuhashi21559462024-02-22 00:07:56306
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:58307 // Whether or not an isolated network context is required to the next
308 // prefetch.
309 bool IsIsolatedNetworkContextRequiredForCurrentPrefetch() const;
Max Curran48700962023-05-15 18:35:52310
311 // Whether or not an isolated network context is required for the previous
312 // redirect hop of the given url.
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:58313 bool IsIsolatedNetworkContextRequiredForPreviousRedirectHop() const;
314
Hiroshige Hayashizaki73e42892023-06-26 16:48:48315 base::WeakPtr<PrefetchResponseReader> GetResponseReaderForCurrentPrefetch();
316
Max Curranc0137502023-05-02 18:06:22317 // Whether or not the prefetch proxy would be required to fetch the given url
318 // based on |prefetch_type_|.
319 bool IsProxyRequiredForURL(const GURL& url) const;
320
Jeremy Roman45c89d012023-08-30 21:22:02321 const network::ResourceRequest* GetResourceRequest() const {
322 return resource_request_.get();
323 }
324 void MakeResourceRequest(const net::HttpRequestHeaders& additional_headers);
325
Devlin Cronin7f318c12023-06-09 00:57:01326 // Updates |referrer_| after a redirect.
327 void UpdateReferrer(
328 const GURL& new_referrer_url,
329 const network::mojom::ReferrerPolicy& new_referrer_policy);
330
Arthur Sonzognic686e8f2024-01-11 08:36:37331 const std::optional<net::HttpNoVarySearchData>& GetNoVarySearchHint() const {
Liviu Tinta953bde882023-05-05 13:21:35332 return no_vary_search_hint_;
Liviu Tinta68a45802023-04-05 18:32:20333 }
334
Alan Cutter5525a852022-10-07 03:53:31335 base::WeakPtr<PrefetchContainer> GetWeakPtr() {
Max Curran646fb642022-03-16 00:44:09336 return weak_method_factory_.GetWeakPtr();
337 }
338
Max Curran146bf442022-03-28 23:22:14339 // The status of the current prefetch. Note that |HasPrefetchStatus| will be
William Liu77089052022-12-15 18:53:35340 // initially false until |SetPrefetchStatus| is called. |SetPrefetchStatus|
Taiyo Mizuhashic3f14f42024-08-28 00:16:50341 // also sets |attempt_| PreloadingTriggeringOutcome and
342 // PreloadingFailureReason. It is only safe to call after
William Liu77089052022-12-15 18:53:35343 // `OnEligibilityCheckComplete`.
344 void SetPrefetchStatus(PrefetchStatus prefetch_status);
Max Curran146bf442022-03-28 23:22:14345 bool HasPrefetchStatus() const { return prefetch_status_.has_value(); }
346 PrefetchStatus GetPrefetchStatus() const;
347
Taiyo Mizuhashi26f86c6b32024-10-02 03:58:46348 // These are intended to be called on
349 // PrefetchService::CheckAndSetPrefetchHoldbackStatus() to set this overridden
350 // prefetch status to `attempt_`.
351 bool HasOverriddenHoldbackStatus() const {
352 return holdback_status_override_.has_value();
353 }
354 PreloadingHoldbackStatus GetOverriddenHoldbackStatus() const {
355 CHECK(holdback_status_override_);
356 return holdback_status_override_.value();
357 }
358
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58359 // The state enum of the current prefetch, to replace `PrefetchStatus`.
360 // https://crbug.com/1494771
361 // Design doc for PrefetchContainer state transitions:
362 // https://docs.google.com/document/d/1dK4mAVoRrgTVTGdewthI_hA8AHirgXW8k6BmpK9gnBE/edit?usp=sharing
363 enum class LoadState {
364 // --- Phase 1. [Initial state]
365 kNotStarted,
366
367 // --- Phase 2. The eligibility check for the initial request has completed
368 // and `PreloadingAttempt::SetEligibility()` has been called.
369
370 // Found eligible.
371 kEligible,
372
373 // [Final state] Found ineligible. `redirect_chain_[0].eligibility_`
374 // contains the reason for being ineligible.
375 kFailedIneligible,
376
377 // --- Phase 3. PrefetchService::StartSinglePrefetch() has been called and
378 // the holdback check has completed.
379
Hiroshige Hayashizaki6b7035c02025-07-18 21:06:32380 // Not heldback:
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58381 //
Hiroshige Hayashizaki6b7035c02025-07-18 21:06:32382 // On these states, refer to `PrefetchResponseReader`s for detailed
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58383 // prefetching state and servability.
384 //
Hiroshige Hayashizaki6b7035c02025-07-18 21:06:32385 // - `kStarted`: Prefetch is started.
386 // - `kDeterminedHead`: `PrefetchContainer::OnDeterminedHead()` is called.
387 // `Observer::OnDeterminedHead()` is called after transitioning to this
388 // state.
389 // - [Final state] `kCompletedOrFailed`:
390 // `PrefetchContainer::OnPrefetchComplete()` is called.
391 // `Observer::OnPrefetchCompletedOrFailed()` is called after transitioning
392 // to this state.
393 //
394 // Currently the distinction between these three states is introduced for
395 // CHECK()ing the calling order of `OnDeterminedHead()` and
396 // `OnPrefetchComplete()` (for https://crbug.com/400761083) and shouldn't be
397 // used for
398 // other purposes (i.e. these three enum values should behave in the same
399 // way).
400 //
401 // TODO(https://crbug.com/432518638): Make more strict association with
402 // `PrefetchContainer::LoadState` and `PrefetchResponseReader::LoadState`
403 // and verify it by adding CHECK()s.
404 //
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58405 // Also, refer to `attempt_` for triggering outcome and failure reasons for
406 // metrics.
407 // `PreloadingAttempt::SetFailureReason()` can be only called on this state.
408 // Note that these states of `attempt_` don't directly affect
409 // `PrefetchResponseReader`'s servability.
410 // (e.g. `PrefetchResponseReader::GetServableState()` can be still
411 // `kServable` even if `attempt_` has a failure).
412 kStarted,
Hiroshige Hayashizaki6b7035c02025-07-18 21:06:32413 kDeterminedHead,
414 kCompletedOrFailed,
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58415
416 // [Final state] Heldback due to `PreloadingAttempt::ShouldHoldback()`.
417 kFailedHeldback,
418 };
419 void SetLoadState(LoadState prefetch_status);
420 LoadState GetLoadState() const;
421
Max Currancc1ab0c2022-09-12 22:03:11422 // Controls ownership of the |ProxyLookupClientImpl| used during the
423 // eligibility check.
424 void TakeProxyLookupClient(
425 std::unique_ptr<ProxyLookupClientImpl> proxy_lookup_client);
426 std::unique_ptr<ProxyLookupClientImpl> ReleaseProxyLookupClient();
427
kenosseab3c422025-04-03 12:50:19428 // Called when it is added to `PrefetchService::owned_prefetches_`.
429 void OnAddedToPrefetchService();
430
William Liu77089052022-12-15 18:53:35431 // Whether or not the prefetch was determined to be eligibile.
Hiroshige Hayashizaki939c5ed42023-11-01 03:29:21432 void OnEligibilityCheckComplete(PreloadingEligibility eligibility);
Max Curran5d4da4b42023-03-10 23:41:46433
434 // Adds a the new URL to |redirect_chain_|.
Jeremy Roman45c89d012023-08-30 21:22:02435 void AddRedirectHop(const net::RedirectInfo& redirect_info);
Max Curran5d4da4b42023-03-10 23:41:46436
Max Curran5d4da4b42023-03-10 23:41:46437 // The length of the redirect chain for this prefetch.
438 size_t GetRedirectChainSize() const { return redirect_chain_.size(); }
Max Curran210cffa2022-09-06 22:24:31439
Max Curran18a6f2b2022-05-02 23:13:24440 // Whether this prefetch is a decoy. Decoy prefetches will not store the
441 // response, and not serve any prefetched resources.
442 void SetIsDecoy(bool is_decoy) { is_decoy_ = is_decoy; }
443 bool IsDecoy() const { return is_decoy_; }
444
Taiyo Mizuhashi9dfeb632024-10-24 08:44:20445 // Whether the prefetch request is cross-site/cross-origin for given origin.
446 bool IsCrossSiteRequest(const url::Origin& origin) const;
447 bool IsCrossOriginRequest(const url::Origin& origin) const;
448
Jeremy Romane561b412024-02-15 18:31:34449 // Whether this prefetch is potentially contaminated by cross-site state.
450 // If so, it may need special handling for privacy.
451 // See https://crbug.com/1439246.
452 bool IsCrossSiteContaminated() const { return is_cross_site_contaminated_; }
453 void MarkCrossSiteContaminated();
454
Hiroshige Hayashizakieec97ed12023-05-26 06:38:32455 // Allows for |PrefetchCookieListener|s to be reigsitered for
Hiroshige Hayashizaki87a43932025-08-12 06:57:25456 // `GetCurrentSingleRedirectHopToPrefetch()`.
Hiroshige Hayashizakieec97ed12023-05-26 06:38:32457 void RegisterCookieListener(network::mojom::CookieManager* cookie_manager);
Taiyo Mizuhashi8b5ddcc2025-02-21 22:12:12458 void PauseAllCookieListeners();
459 void ResumeAllCookieListeners();
Max Curranc4445fc2022-06-02 18:43:43460
Hiroshige Hayashizakid44edd4e2025-08-12 07:35:46461 // The network context used to make network requests, copy cookies, etc. for
462 // the given `is_isolated_network_context_required`.
463 PrefetchNetworkContext* GetNetworkContext(
464 bool is_isolated_network_context_required) const;
465
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:58466 // The network context used to make network requests for the next prefetch.
Kouhei Ueno4442db92023-11-13 06:38:13467 PrefetchNetworkContext* GetOrCreateNetworkContextForCurrentPrefetch();
Max Curran18a6f2b2022-05-02 23:13:24468
Max Currana84311e2023-05-16 20:40:25469 // Closes idle connections for all elements in |network_contexts_|.
470 void CloseIdleConnections();
471
Hiroshige Hayashizaki638018f2023-09-12 17:05:45472 // Set the currently prefetching |PrefetchStreamingURLLoader|.
473 void SetStreamingURLLoader(
474 base::WeakPtr<PrefetchStreamingURLLoader> streaming_loader);
Max Currana84311e2023-05-16 20:40:25475
Hiroshige Hayashizaki638018f2023-09-12 17:05:45476 // Returns the URL loader being used for prefetching the current redirect hop.
Hiroshige Hayashizaki334d0fa2023-08-16 23:33:27477 // This method should be used during prefetching and shouldn't be called for
478 // serving purpose.
Taiyo Mizuhashi08c47d12025-03-05 23:46:07479 base::WeakPtr<PrefetchStreamingURLLoader> GetStreamingURLLoader() const;
Max Currana84311e2023-05-16 20:40:25480
Hiroshige Hayashizaki5c50ec52023-09-13 00:35:49481 bool IsStreamingURLLoaderDeletionScheduledForTesting() const;
482
kenossf7b4d60d2024-07-16 15:15:08483 // Returns the PrefetchResponseReader of the prefetched non-redirect response
484 // if already received its head. Ruturns nullptr otherwise.
Hiroshige Hayashizaki334d0fa2023-08-16 23:33:27485 const PrefetchResponseReader* GetNonRedirectResponseReader() const;
kenossf7b4d60d2024-07-16 15:15:08486 // Returns the head of the prefetched non-redirect response if already
487 // received. Ruturns nullptr otherwise.
488 const network::mojom::URLResponseHead* GetNonRedirectHead() const;
Hiroshige Hayashizaki334d0fa2023-08-16 23:33:27489
Hiroshige Hayashizaki638018f2023-09-12 17:05:45490 // Clears |streaming_loader_| and cancels its loading, if any of its
491 // corresponding `PrefetchResponseReader` does NOT start serving. Currently
492 // this itself doesn't mark `this` as failed and thus can leave `this`
493 // stalled. Therefore, call this method only if `this` can be no longer used
494 // for serving, e.g. on the destructor or when
495 // `HaveDefaultContextCookiesChanged()` is true.
Alison Gale770f3fc2024-04-27 00:39:58496 // TODO(crbug.com/40064891): For callsites outside the destructor, remove the
Hiroshige Hayashizaki638018f2023-09-12 17:05:45497 // call or mark `this` as failed, because the current behavior (== existing
498 // behavior, previously as `ResetAllStreamingURLLoaders()`) might potentially
499 // cause issues when there are multiple navigations using `this` concurrently.
500 void CancelStreamingURLLoaderIfNotServing();
Max Curran892ca5422022-12-12 20:55:34501
Max Curran18a6f2b2022-05-02 23:13:24502 // The |PrefetchDocumentManager| that requested |this|.
503 PrefetchDocumentManager* GetPrefetchDocumentManager() const;
504
Max Currane0444942022-09-06 23:55:23505 // Returns whether or not this prefetch has been considered to serve for a
506 // navigation in the past. If it has, then it shouldn't be used for any future
507 // navigations.
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:43508 bool HasPrefetchBeenConsideredToServe() const;
Max Currane0444942022-09-06 23:55:23509
Max Curran210cffa2022-09-06 22:24:31510 // Called when |PrefetchService::OnPrefetchComplete| is called for the
511 // prefetch. This happens when |loader_| fully downloads the requested
512 // resource.
Hiroshige Hayashizaki77083bc82023-11-28 06:04:17513 void OnPrefetchComplete(
514 const network::URLLoaderCompletionStatus& completion_status);
Max Curran210cffa2022-09-06 22:24:31515
Hiroshige Hayashizaki8f74d22b2023-09-28 04:48:08516 // Note: Even if this returns `kServable`, `CreateRequestHandler()` can still
517 // fail (returning null handler) due to final checks. See also the comment for
518 // `PrefetchResponseReader::CreateRequestHandler()`.
Hiroshige Hayashizakib3ff61d2025-08-12 06:28:08519 PrefetchServableState GetServableState(
520 base::TimeDelta cacheable_duration) const;
Max Curran6b93426f2022-05-03 00:55:52521
kenossf7b4d60d2024-07-16 15:15:08522 // Starts blocking `PrefetchMatchResolver` until non-redirect response header
523 // is determined or timeouted. `on_maybe_determined_head_callback` will be
524 // called when
kenoss5a5ad9802024-06-28 10:29:11525 //
kenossf7b4d60d2024-07-16 15:15:08526 // - `PrefetchStreamingURLLoader` succeeded/failed to fetch non-redirect
527 // response header.
kenoss5a5ad9802024-06-28 10:29:11528 // - The argument `timeout` is positive and timeouted.
529 // - `PrefetchContainer` dtor if `kPrefetchUnblockOnCancel` enabled.
kenossf7b4d60d2024-07-16 15:15:08530 void StartBlockUntilHead(base::OnceCallback<void(PrefetchContainer&)>
531 on_maybe_determined_head_callback,
532 base::TimeDelta timeout);
533 // Called when non-redirect response header is determined, i.e.
534 // `GetNonRedirectHead()` becomes immutable.
kenoss5a5ad9802024-06-28 10:29:11535 //
kenossf7b4d60d2024-07-16 15:15:08536 // This method must be called at most once in the lifecycle of
537 // `PrefetchContainer`.
kenoss8fb82852025-03-11 02:20:42538 void OnDeterminedHead();
kenossf7b4d60d2024-07-16 15:15:08539 // Unblocks waiting `PrefetchMatchResolver`.
540 //
541 // This method can be called multiple times.
542 void UnblockPrefetchMatchResolver();
Liviu Tintad97a6a32022-12-08 23:28:40543
elabadysayedf7d6b00f2025-02-05 11:27:00544 void StartTimeoutTimerIfNeeded(base::OnceClosure on_timeout_callback);
Hiroshige Hayashizakid2161a2e2023-10-23 16:22:50545
Max Curran210cffa2022-09-06 22:24:31546 // Returns the time between the prefetch request was sent and the time the
547 // response headers were received. Not set if the prefetch request hasn't been
548 // sent or the response headers haven't arrived.
Arthur Sonzognic686e8f2024-01-11 08:36:37549 std::optional<base::TimeDelta> GetPrefetchHeaderLatency() const {
Max Curran210cffa2022-09-06 22:24:31550 return header_latency_;
551 }
552
Max Curran892ca5422022-12-12 20:55:34553 // Allow for the serving page to metrics when changes to the prefetch occur.
554 void SetServingPageMetrics(base::WeakPtr<PrefetchServingPageMetricsContainer>
555 serving_page_metrics_container);
556 void UpdateServingPageMetrics();
557
Taiyo Mizuhashi9395b7c82024-05-16 20:30:26558 // Returns request id to be used by DevTools and test utilities.
Iman Saboori65c356d2022-07-15 14:47:47559 const std::string& RequestId() const { return request_id_; }
560
William Liu77089052022-12-15 18:53:35561 bool HasPreloadingAttempt() { return !!attempt_; }
Simon Pelchat9ed3e992023-02-17 01:16:16562 base::WeakPtr<PreloadingAttempt> preloading_attempt() { return attempt_; }
William Liu77089052022-12-15 18:53:35563
Hiroshige Hayashizaki64802cf12025-01-16 23:18:46564 // Simulates state transitions for:
565 // - Passing eligibility check successfully (`LoadState::kEligible`),
566 // - About to start prefetching (`LoadState::kStarted`), and
567 // - Completion of prefetching.
568 // For correct transitions, the methods should be called in the following
569 // order (note that the `Simulate*()` methods here doesn't simulate the
570 // loader):
571 // - `SimulatePrefetchEligibleForTest()`
572 // - `SimulatePrefetchStartedForTest()`
573 // - `SetStreamingURLLoader()`
574 // - `SimulatePrefetchCompletedForTest()`
575 void SimulatePrefetchEligibleForTest();
576 void SimulatePrefetchStartedForTest();
577 void SimulatePrefetchCompletedForTest();
578
579 // Simulates a prefetch container that failed at the eligibility check
580 // (`LoadState::FailedIneligible`).
581 void SimulatePrefetchFailedIneligibleForTest(
582 PreloadingEligibility eligibility);
583
William Liu77089052022-12-15 18:53:35584 void DisablePrecogLoggingForTest() { attempt_ = nullptr; }
585
Hiroshige Hayashizaki29e14dd2025-03-14 16:03:07586 // Set a callback for waiting for prefetch completion in tests.
587 using PrefetchResponseCompletedCallbackForTesting =
588 base::RepeatingCallback<void(base::WeakPtr<PrefetchContainer>)>;
589 static void SetPrefetchResponseCompletedCallbackForTesting(
590 PrefetchResponseCompletedCallbackForTesting callback);
591
Arthur Sonzognic686e8f2024-01-11 08:36:37592 const std::optional<net::HttpNoVarySearchData>& GetNoVarySearchData() const {
Hiroshige Hayashizaki47a83632023-06-16 18:09:22593 return no_vary_search_data_;
594 }
Hiroshige Hayashizaki2cbf67b92023-10-23 17:40:07595 // Sets `no_vary_search_data_` from `GetHead()`. Exposed for tests.
Taiyo Mizuhashi9a1ab9882024-11-28 08:29:08596 void MaybeSetNoVarySearchData();
Hiroshige Hayashizaki47a83632023-06-16 18:09:22597
kenossf6fbd5652024-09-04 00:40:28598 // Called upon detecting a change to cookies within the redirect chain.
599 //
600 // Note that there are two paths:
601 //
602 // - Roughly speaking, when non-redirect header received and
603 // `PrefetchService`/`PrefetchContainer` detected cookies change of the head
kenoss3dfd90792025-03-11 01:13:46604 // of redirect chain. `PrefetchMatchResolver` propagates it to other waiting
605 // prefetches as they share domain.
kenossf6fbd5652024-09-04 00:40:28606 // - When `PrefetchURLLoaderInterceptor::MaybeCreateLoader()` handles
607 // redirects in the serving prefetch.
kenoss8fb82852025-03-11 02:20:42608 void OnDetectedCookiesChange(
kenossb1c65dbc2024-12-13 08:23:49609 std::optional<bool>
610 is_unblock_for_cookies_changed_triggered_by_this_prefetch_container);
Hiroshige Hayashizakia51f624be2023-10-24 16:29:57611
Wayne Jackson Jr.03a15fa62024-09-16 14:42:15612 // Called when the prefetch request is started (i.e. the URL loader is created
613 // & started).
614 void OnPrefetchStarted();
615
Hiroshige Hayashizaki386c5022025-08-12 14:43:37616 PrefetchServingHandle CreateServingHandle();
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37617
kenossf6fbd5652024-09-04 00:40:28618 void AddObserver(Observer* observer);
619 void RemoveObserver(Observer* observer);
620
kenossda3d13b2024-08-15 16:31:19621 bool IsExactMatch(const GURL& url) const;
622 bool IsNoVarySearchHeaderMatch(const GURL& url) const;
kenossb9b40632024-10-01 15:43:24623 // Checks that the URL matches to the NoVarySearch hint with a precondition.
624 //
625 // The precondition is that a non redirect header is not received, as
626 // NoVarySearch hint is a mechanism to wait prefetches that is expected to
627 // receive NoVarySearch header.
628 bool ShouldWaitForNoVarySearchHeader(const GURL& url) const;
kenossda3d13b2024-08-15 16:31:19629
kenossf6fbd5652024-09-04 00:40:28630 // Records metrics when serving result is determined.
631 //
632 // This is eventually called once for every `PrefetchContainer` put in
kenoss3dfd90792025-03-11 01:13:46633 // `PrefetchMatchResolver::candidates_`, i.e. those potentially matching
kenossf6fbd5652024-09-04 00:40:28634 // and expected to become servable at the head of
kenoss3dfd90792025-03-11 01:13:46635 // `PrefetchMatchResolver::FindPrefetch()`.
kenossf6fbd5652024-09-04 00:40:28636 //
637 // This can be called multiple times, because this can be called for multiple
kenoss3dfd90792025-03-11 01:13:46638 // `PrefetchMatchResolver`s.
Taiyo Mizuhashi09f571f2025-08-04 16:05:54639 void OnUnregisterCandidate(
640 const GURL& navigated_url,
641 bool is_served,
642 PrefetchPotentialCandidateServingResult matching_result,
643 bool is_nav_prerender,
644 std::optional<base::TimeDelta> blocked_duration);
kenossf6fbd5652024-09-04 00:40:28645
kenossb68c9e82024-10-10 10:11:15646 // TODO(crbug.com/372186548): Revisit the semantics of
647 // `IsLikelyAheadOfPrerender()`.
648 //
649 // Returns true iff this prefetch was triggered for ahead of prerender or was
650 // migrated with such ones.
651 //
652 // Currently, we (`PrerendererImpl`) start a prefetch ahead of prerender just
653 // before starting a prerender and make them race 1. to reduce fetch request
654 // even if prerender failed and fell back to normal navigation, 2. to buy time
655 // for renderer process initialization of prerender.
656 //
657 // This flag is to indicate it's likely there is a such concurrent-ish
658 // prerender request that wants to claim this prefetch even if it is not
659 // started to avoid duplicated network requests, and thus if this is true, we
660 // go through `kBlockUntilHeadUntilEligibilityGot` code path.
661 //
662 // - This flag is set if `max_preloading_type` is `PreloadingType::kPrerender`
663 // on `PrefetchContainer::ctor`.
664 // - This flag is updated with prefetch migration `MigrateNewlyAdded()`: If we
665 // replace existing `PrefetchContainer` with such prerender-initiated
666 // `PrefetchContainer` with the same `PrefetchContainer::Key`, then we also
667 // transitively set the flag for the existing `PrefetchContainer` as well,
668 // because we'll still anticipate the prerendering request to hit the
669 // existing `PrefetchContainer` as it has the same key.
670 bool IsLikelyAheadOfPrerender() const {
671 return is_likely_ahead_of_prerender_;
672 }
673 // TODO(crbug.com/372186548): Revisit for right naming.
674 //
675 // Migrate newly added `PrefetchContainer` into this as keys are conflicted.
676 //
677 // See also `PrefetchService::AddPrefetchContainerWithoutStartingPrefetch()`.
678 void MigrateNewlyAdded(std::unique_ptr<PrefetchContainer> added);
679
Taiyo Mizuhashi98ecb382025-06-03 15:24:55680 // Handles loader related events. Currently used for DevTools and metrics.
kenoss1ce36df592024-12-03 01:04:35681 void NotifyPrefetchRequestWillBeSent(
682 const network::mojom::URLResponseHeadPtr* redirect_head);
683 void NotifyPrefetchResponseReceived(
684 const network::mojom::URLResponseHead& head);
685 void NotifyPrefetchRequestComplete(
686 const network::URLLoaderCompletionStatus& completion_status);
687 std::optional<mojo::PendingRemote<network::mojom::DevToolsObserver>>
688 MakeSelfOwnedNetworkServiceDevToolsObserver();
689
kenoss6c5fb092024-07-05 05:42:14690 bool is_in_dtor() const { return is_in_dtor_; }
691
Hiroshige Hayashizaki0830e182025-03-14 02:03:06692 void OnServiceWorkerStateDetermined(
693 PrefetchServiceWorkerState service_worker_state);
694 PrefetchServiceWorkerState service_worker_state() const {
695 return service_worker_state_;
696 }
697
Taiyo Mizuhashicd08a8f2025-06-10 17:27:32698 bool ShouldDisableBlockUntilHeadTimeout() const {
699 return should_disable_block_until_head_timeout_;
700 }
701
Taiyo Mizuhashi53da92d2025-06-23 08:56:15702 std::optional<PrefetchPriority> GetPrefetchPriority() const {
703 return priority_;
704 }
705
Hiroshige Hayashizaki386c5022025-08-12 14:43:37706 // Methods only exposed for `PrefetchServingHandle`.
707 const std::vector<std::unique_ptr<PrefetchSingleRedirectHop>>& redirect_chain(
708 base::PassKey<PrefetchServingHandle>) const;
709 void SetProbeResult(base::PassKey<PrefetchServingHandle>,
710 PrefetchProbeResult probe_result);
711 static std::optional<PreloadingTriggeringOutcome>
712 TriggeringOutcomeFromStatusForServingHandle(
713 base::PassKey<PrefetchServingHandle>,
714 PrefetchStatus prefetch_status);
715
Max Curran210cffa2022-09-06 22:24:31716 protected:
Max Curran210cffa2022-09-06 22:24:31717 // Updates metrics based on the result of the prefetch request.
718 void UpdatePrefetchRequestMetrics(
Max Curran210cffa2022-09-06 22:24:31719 const network::mojom::URLResponseHead* head);
720
Max Curran646fb642022-03-16 00:44:09721 private:
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37722 PrefetchContainer(
723 const GlobalRenderFrameHostId& referring_render_frame_host_id,
Taiyo Mizuhashi9dfeb632024-10-24 08:44:20724 const std::optional<url::Origin>& referring_origin,
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37725 const std::optional<size_t>& referring_url_hash,
726 const PrefetchContainer::Key& key,
727 const PrefetchType& prefetch_type,
Taiyo Mizuhashi49959d02025-04-22 16:07:54728 const std::optional<std::string>& embedder_histogram_suffix,
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37729 const blink::mojom::Referrer& referrer,
HuanPo Lin740620b2025-03-21 12:37:26730 std::optional<SpeculationRulesTags> speculation_rules_tags,
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37731 std::optional<net::HttpNoVarySearchData> no_vary_search_hint,
732 base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager,
733 base::WeakPtr<BrowserContext> browser_context,
734 ukm::SourceId ukm_source_id,
kenoss3bd73b82024-10-10 20:33:49735 scoped_refptr<PreloadPipelineInfo> preload_pipeline_info,
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37736 base::WeakPtr<PreloadingAttempt> attempt,
Taiyo Mizuhashi26f86c6b32024-10-02 03:58:46737 std::optional<PreloadingHoldbackStatus> holdback_status_override,
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37738 std::optional<base::UnguessableToken> initiator_devtools_navigation_token,
Wayne Jackson Jr.1b7322472024-10-29 13:08:51739 const net::HttpRequestHeaders& additional_headers,
Wayne Jackson Jr.b22d53b22024-11-15 11:40:06740 std::unique_ptr<PrefetchRequestStatusListener> request_status_listener,
elabadysayedf7d6b00f2025-02-05 11:27:00741 bool is_javascript_enabled,
kenoss70bfbfe2025-06-10 08:04:42742 base::TimeDelta ttl,
Taiyo Mizuhashicd08a8f2025-06-10 17:27:32743 bool should_append_variations_header,
Taiyo Mizuhashid7c856992025-06-23 08:56:02744 bool should_disable_block_until_head_timeout,
745 std::optional<PrefetchPriority> priority);
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37746
Robert Lin92f3617e2023-05-20 10:14:49747 // Update |prefetch_status_| and report prefetch status to
748 // DevTools without updating TriggeringOutcome.
749 void SetPrefetchStatusWithoutUpdatingTriggeringOutcome(
750 PrefetchStatus prefetch_status);
751
Adithya Srinivasan4d3dad02024-10-17 18:06:59752 // Updates `attempt_`'s outcome and failure reason based on
753 // `new_prefetch_status`.
Taiyo Mizuhashi070baec2025-03-28 15:37:00754 // This should only be called after the prefetch is started, because
755 // `attempt_` is degined to record the outcome or failure of started triggers.
Adithya Srinivasan4d3dad02024-10-17 18:06:59756 void SetTriggeringOutcomeAndFailureReasonFromStatus(
757 PrefetchStatus new_prefetch_status);
758
Jeremy Roman586b5ec2024-02-13 15:14:40759 // Add client hints headers to a request bound for |origin|.
760 void AddClientHintsHeaders(const url::Origin& origin,
761 net::HttpRequestHeaders* request_headers);
Liviu Tinta2e1ffe22024-06-21 21:01:33762 // Add X-Client-Data request header to a request.
763 void AddXClientDataHeader(network::ResourceRequest& request);
Jeremy Roman586b5ec2024-02-13 15:14:40764
Hiroshige Hayashizaki87a43932025-08-12 06:57:25765 // Returns the `PrefetchSingleRedirectHop` to be prefetched next.
766 // This is the last element in `redirect_chain_`, because, during prefetching
767 // from the network, we push back `PrefetchSingleRedirectHop`s to
768 // `redirect_chain_` and access the latest redirect hop.
769 PrefetchSingleRedirectHop& GetCurrentSingleRedirectHopToPrefetch() const;
Hiroshige Hayashizaki8ce7d8d2023-05-26 00:16:32770
Hiroshige Hayashizaki87a43932025-08-12 06:57:25771 // Returns the `PrefetchSingleRedirectHop` for the redirect leg
772 // before `GetCurrentSingleRedirectHopToPrefetch()`. This must be called only
773 // if `this` has redirect(s).
774 const PrefetchSingleRedirectHop& GetPreviousSingleRedirectHopToPrefetch()
775 const;
Hiroshige Hayashizaki8ce7d8d2023-05-26 00:16:32776
kenoss5df53e052024-06-17 06:59:52777 // Returns "Sec-Purpose" header value for a prefetch request to `request_url`.
778 const char* GetSecPurposeHeaderValue(const GURL& request_url) const;
779
Wayne Jackson Jr.00e3e8b2024-09-25 12:35:56780 // Called when a prefetch request could not be started because of eligibility
781 // reasons. Should only be called for the initial prefetch request and not
782 // redirects.
783 void OnInitialPrefetchFailedIneligible(PreloadingEligibility eligibility);
784
Hiroshige Hayashizaki03a59052025-08-12 14:44:23785 std::string GetMetricsSuffix() const;
786
Adithya Srinivasan4d3dad02024-10-17 18:06:59787 // Record `prefetch_status` to UMA if it hasn't already been recorded for this
788 // container.
789 // Note: We use a parameter instead of just `prefetch_status_` as it may not
790 // be updated to the latest value when this method is called.
791 void MaybeRecordPrefetchStatusToUMA(PrefetchStatus prefetch_status);
792
Taiyo Mizuhashi98061e22025-07-12 05:26:54793 // Records UMAs tracking some certain durations during prefetch addition to
794 // prefetch completion (e.g. `Prefetch.PrefetchContainer.AddedTo*`).
795 void RecordPrefetchDurationHistogram();
Taiyo Mizuhashi43066071f2025-04-25 23:40:22796 // Records `Prefetch.PrefetchMatchingBlockedNavigationWithPrefetch.*` UMAs.
kenoss4bdf2d82025-05-27 01:58:45797 void RecordPrefetchMatchingBlockedNavigationHistogram(bool blocked_until_head,
798 bool is_nav_prerender);
Taiyo Mizuhashia009caf2025-08-05 07:34:22799 // Records `Prefetch.PrefetchContainer.ServedCount`.
800 void RecordPrefetchContainerServedCountHistogram();
801
Taiyo Mizuhashi43066071f2025-04-25 23:40:22802 // Records `Prefetch.BlockUntilHeadDuration.*` UMAs.
803 void RecordBlockUntilHeadDurationHistogram(
804 const std::optional<base::TimeDelta>& blocked_duration,
kenoss4bdf2d82025-05-27 01:58:45805 bool served,
806 bool is_nav_prerender);
Taiyo Mizuhashi09f571f2025-08-04 16:05:54807 // Records
808 // `Prefetch.PrefetchPotentialCandidateServingResult.PerMatchingCandidate.*`
809 // UMAs.
810 void RecordPrefetchPotentialCandidateServingResultHistogram(
811 PrefetchPotentialCandidateServingResult matching_result);
kenosseab3c422025-04-03 12:50:19812
Hiroshige Hayashizakidb5f1962025-07-14 22:38:20813 // Should be called only from `OnPrefetchComplete()`, so that
814 // `OnPrefetchCompletedOrFailed()` is always called after
815 // `OnPrefetchCompleteInternal()`.
816 void OnPrefetchCompleteInternal(
817 const network::URLLoaderCompletionStatus& completion_status);
818
Hiroshige Hayashizaki2df45292023-10-10 22:59:03819 // The ID of the RenderFrameHost/Document that triggered the prefetch.
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37820 // This will be empty when browser-initiated prefetch.
Hiroshige Hayashizaki2df45292023-10-10 22:59:03821 const GlobalRenderFrameHostId referring_render_frame_host_id_;
Taiyo Mizuhashi21559462024-02-22 00:07:56822
Hiroshige Hayashizaki0830e182025-03-14 02:03:06823 PrefetchServiceWorkerState service_worker_state_ =
824 PrefetchServiceWorkerState::kAllowed;
825
Taiyo Mizuhashi21559462024-02-22 00:07:56826 // The origin and URL that initiates the prefetch request.
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37827 // For renderer-initiated prefetch, this is calculated by referring
828 // RenderFrameHost's LastCommittedOrigin. For browser-initiated prefetch, this
Taiyo Mizuhashi9dfeb632024-10-24 08:44:20829 // is sometimes explicitly passed via ctor.
830 const std::optional<url::Origin> referring_origin_;
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37831 // Used by metrics for equality checks, only works for renderer-initiated
832 // triggers.
833 const std::optional<size_t> referring_url_hash_;
Max Curran646fb642022-03-16 00:44:09834
Kouhei Ueno8ce54452023-11-21 03:58:02835 // The key used to match this PrefetchContainer, including the URL that was
836 // requested to prefetch.
837 const PrefetchContainer::Key key_;
Max Curran646fb642022-03-16 00:44:09838
839 // The type of this prefetch. This controls some specific details about how
840 // the prefetch is handled, including whether an isolated network context or
841 // the default network context is used to perform the prefetch, whether or
842 // not the preftch proxy is used, and whether or not subresources are
843 // prefetched.
844 PrefetchType prefetch_type_;
845
Taiyo Mizuhashi49959d02025-04-22 16:07:54846 // The suffix string of embedder triggers used for generating histogram
847 // recorded per trigger. This should be nullopt unless `prefetch_type_`'s
848 // `PreloadingTriggerType` is `PreloadingTriggerType::kEmbedder`.
849 const std::optional<std::string> embedder_histogram_suffix_;
850
Kevin McNeee6ca0892022-09-28 15:36:22851 // The referrer to use for the request.
Devlin Cronin7f318c12023-06-09 00:57:01852 blink::mojom::Referrer referrer_;
Kevin McNeee6ca0892022-09-28 15:36:22853
Jeremy Roman45c89d012023-08-30 21:22:02854 // Information about the current prefetch request. Updated when a redirect is
855 // encountered, whether or not the direct can be processed by the same URL
856 // loader or requires the instantiation of a new loader.
857 std::unique_ptr<network::ResourceRequest> resource_request_;
858
Hiroshige Hayashizaki47a83632023-06-16 18:09:22859 // The No-Vary-Search response data, parsed from the actual response header
860 // (`GetHead()`).
Hiroshige Hayashizaki2cbf67b92023-10-23 17:40:07861 // Unless this is set, `no_vary_search` helpers don't perform No-Vary-Search
862 // matching for `this`, even if `GetHead()` has No-Vary-Search headers.
Arthur Sonzognic686e8f2024-01-11 08:36:37863 std::optional<net::HttpNoVarySearchData> no_vary_search_data_;
Hiroshige Hayashizaki47a83632023-06-16 18:09:22864
865 // The No-Vary-Search hint of the prefetch, which is specified by the
866 // speculation rules and can be different from actual `no_vary_search_data_`.
Arthur Sonzognic686e8f2024-01-11 08:36:37867 const std::optional<net::HttpNoVarySearchData> no_vary_search_hint_;
Liviu Tinta68a45802023-04-05 18:32:20868
HuanPo Lin740620b2025-03-21 12:37:26869 // The tags of the speculation rules that triggered this prefetch, and this
870 // field is non-null if and only if this is created by SpeculationRules
871 // prefech. These are assumed to have been validated by the time this is
872 // constructed.
873 std::optional<SpeculationRulesTags> speculation_rules_tags_;
874
Taiyo Mizuhashifc6afd6c2024-01-26 06:53:07875 // The |PrefetchDocumentManager| that requested |this|.
Taiyo Mizuhashi1b23ca62024-03-28 22:07:37876 // This will be nullptr when the prefetch is initiated by browser.
Max Curran18a6f2b2022-05-02 23:13:24877 base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager_;
878
Jeremy Roman586b5ec2024-02-13 15:14:40879 // The |BrowserContext| in which this is being run.
880 base::WeakPtr<BrowserContext> browser_context_;
881
Max Curran146bf442022-03-28 23:22:14882 // The current status, if any, of the prefetch.
Alison Gale81f4f2c72024-04-22 19:33:31883 // TODO(crbug.com/40075414): Use `load_state_` instead for non-metrics
884 // purpose.
Arthur Sonzognic686e8f2024-01-11 08:36:37885 std::optional<PrefetchStatus> prefetch_status_;
Adithya Srinivasan4d3dad02024-10-17 18:06:59886 bool prefetch_status_recorded_to_uma_ = false;
Max Curran146bf442022-03-28 23:22:14887
kenossf6fbd5652024-09-04 00:40:28888 // True iff `PrefetchStatus` was set to `kPrefetchNotUsedCookiesChanged` once.
889 //
890 // TODO(crbug.com/40075414): Remove this.
891 bool on_detected_cookies_change_called_ = false;
892
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58893 // The current status of the prefetch.
894 LoadState load_state_ = LoadState::kNotStarted;
895
Max Curran5d4da4b42023-03-10 23:41:46896 // Looks up the proxy settings in the default network context all URLs in
897 // |redirect_chain_|.
Max Currancc1ab0c2022-09-12 22:03:11898 std::unique_ptr<ProxyLookupClientImpl> proxy_lookup_client_;
899
Max Curran18a6f2b2022-05-02 23:13:24900 // Whether this prefetch is a decoy or not. If the prefetch is a decoy then
901 // any prefetched resources will not be served.
902 bool is_decoy_ = false;
903
Kouhei Ueno8ce54452023-11-21 03:58:02904 // The redirect chain resulting from prefetching |GetURL()|.
Hiroshige Hayashizaki87a43932025-08-12 06:57:25905 std::vector<std::unique_ptr<PrefetchSingleRedirectHop>> redirect_chain_;
Max Curranc4445fc2022-06-02 18:43:43906
Max Currana84311e2023-05-16 20:40:25907 // The network contexts used for this prefetch. They key corresponds to the
908 // |is_isolated_network_context_required| param of the
909 // |PrefetchNetworkContext|.
910 std::map<bool, std::unique_ptr<PrefetchNetworkContext>> network_contexts_;
Max Curran18a6f2b2022-05-02 23:13:24911
Hiroshige Hayashizaki638018f2023-09-12 17:05:45912 // The currently prefetching streaming URL loader, prefetching the last
913 // element of `redirect_chain_`. Multiple streaming URL loaders can be used in
914 // the event a redirect causes a change in the network context, but here only
915 // one (=last) `PrefetchStreamingURLLoader` is kept here, because when
916 // switching the network context and `PrefetchStreamingURLLoader`s, the old
917 // `PrefetchStreamingURLLoader` is scheduled for deletion and then the new
918 // `PrefetchStreamingURLLoader` is set here.
919 base::WeakPtr<PrefetchStreamingURLLoader> streaming_loader_;
Max Curran892ca5422022-12-12 20:55:34920
Max Curran210cffa2022-09-06 22:24:31921 ukm::SourceId ukm_source_id_;
922
Taiyo Mizuhashi00cf58ad2024-11-15 02:12:13923 // The amount of time it took for the headers to be received.
Arthur Sonzognic686e8f2024-01-11 08:36:37924 std::optional<base::TimeDelta> header_latency_;
Max Curran210cffa2022-09-06 22:24:31925
Taiyo Mizuhashia009caf2025-08-05 07:34:22926 // Counts how many times this container has been served to the navigation.
927 // Only used for the metrics.
928 base::ClampedNumeric<uint32_t> served_count_ = 0;
Max Curran210cffa2022-09-06 22:24:31929
930 // The result of probe when checked on navigation.
Arthur Sonzognic686e8f2024-01-11 08:36:37931 std::optional<PrefetchProbeResult> probe_result_;
Max Curran210cffa2022-09-06 22:24:31932
Jeremy Romane561b412024-02-15 18:31:34933 // If set, this prefetch's timing might be affected by cross-site state, so
934 // further processing may need to affect how the response is processed to make
935 // inferences about this logic less practical.
936 bool is_cross_site_contaminated_ = false;
937
Max Curran892ca5422022-12-12 20:55:34938 // Reference to metrics related to the page that considered using this
939 // prefetch.
940 base::WeakPtr<PrefetchServingPageMetricsContainer>
941 serving_page_metrics_container_;
942
Taiyo Mizuhashi9395b7c82024-05-16 20:30:26943 // Request identifier used by DevTools and test utilities.
Iman Saboori65c356d2022-07-15 14:47:47944 std::string request_id_;
945
kenoss4858a802024-10-11 06:50:56946 // Information of preload pipeline that this prefetch belongs/is related to.
947 //
948 // If a prerender triggers a prefetch ahead of prerender, it needs to get to
949 // know information of the prefetch, e.g eligibility, to judge to abort
950 // prerender when prefetch failed. Unfortunately we can't pass the information
951 // at the prefetch matching process, as prefetch may fail before it and other
952 // `NavigationLoaderInterceptor` e.g. one of service worker can intercept.
953 //
954 // So, we pass such information via pipeline infos.
955 //
956 // - `redirect_chain_[0].eligibility_`
957 // - `prefetch_status_`
958 //
959 // The values must be synchronized both when these fields are updated and when
960 // a new pipeline info added to `inherited_preload_pipeline_infos_`.
961 //
962 // A new pipeline info added when another prefetch is migrated into it. See
963 // `MigrateNewlyAdded()`.
964 //
965 // Note that we distinguish the primary one and inherited ones because we send
966 // CDP events with id of `preload_pipeline_info_`.
kenossc3f9a2c2025-03-06 15:35:51967 scoped_refptr<PreloadPipelineInfoImpl> preload_pipeline_info_;
968 std::vector<scoped_refptr<PreloadPipelineInfoImpl>>
kenoss4858a802024-10-11 06:50:56969 inherited_preload_pipeline_infos_;
kenoss3bd73b82024-10-10 20:33:49970
William Liu77089052022-12-15 18:53:35971 // `PreloadingAttempt` is used to track the lifecycle of the preloading event,
972 // and reports various statuses to UKM dashboard. It is initialised along with
973 // `this`, and destroyed when `WCO::DidFinishNavigation` is fired.
974 // `attempt_`'s eligibility is set in `OnEligibilityCheckComplete`, and its
975 // holdback status, triggering outcome and failure reason are set in
976 // `SetPrefetchStatus`.
977 base::WeakPtr<PreloadingAttempt> attempt_;
978
Taiyo Mizuhashi26f86c6b32024-10-02 03:58:46979 // If set, this value is used to override holdback status derived by the
980 // normal process. It is set to `attempt_` on
981 // PrefetchService::CheckAndSetPrefetchHoldbackStatus().
982 std::optional<PreloadingHoldbackStatus> holdback_status_override_ =
983 std::nullopt;
984
Robert Lina5f5ca72023-03-23 02:44:48985 // A DevTools token used to identify initiator document if the prefetch is
986 // triggered by SpeculationRules.
Arthur Sonzognic686e8f2024-01-11 08:36:37987 std::optional<base::UnguessableToken> initiator_devtools_navigation_token_ =
988 std::nullopt;
Robert Lina5f5ca72023-03-23 02:44:48989
Max Curran983f21a52023-03-23 23:52:58990 // The time at which |PrefetchService| started blocking until the head of
991 // |this| was received.
Arthur Sonzognic686e8f2024-01-11 08:36:37992 std::optional<base::TimeTicks> blocked_until_head_start_time_;
Max Curran983f21a52023-03-23 23:52:58993
Max Currane6679ca2023-06-06 19:01:39994 // A timer used to limit the maximum amount of time that a navigation can be
995 // blocked waiting for the head of this prefetch to be received.
996 std::unique_ptr<base::OneShotTimer> block_until_head_timer_;
997
Wayne Jackson Jr.1b7322472024-10-29 13:08:51998 // Additional headers for WebView initiated prefetch.
999 // This must be empty for non-WebView initiated prefetches.
1000 // TODO(crbug.com/369859822): Revisit the semantics if needed.
1001 const net::HttpRequestHeaders additional_headers_;
1002
Wayne Jackson Jr.b22d53b22024-11-15 11:40:061003 // Listener of prefetch request. Currently used for WebView initiated
1004 // prefetch.
1005 std::unique_ptr<PrefetchRequestStatusListener> request_status_listener_;
Wayne Jackson Jr.03a15fa62024-09-16 14:42:151006
Hiroshige Hayashizakid2161a2e2023-10-23 16:22:501007 std::unique_ptr<base::OneShotTimer> timeout_timer_;
1008
Jeremy Roman586b5ec2024-02-13 15:14:401009 // Whether JavaScript is on in this contents (or was, when this prefetch
1010 // started). This affects Client Hints behavior. Per-origin settings are
1011 // handled later, according to
1012 // |ClientHintsControllerDelegate::IsJavaScriptAllowed|.
1013 bool is_javascript_enabled_ = false;
1014
kenoss6c5fb092024-07-05 05:42:141015 // True iff the destructor was called.
1016 bool is_in_dtor_ = false;
1017
kenossf6fbd5652024-09-04 00:40:281018 base::ObserverList<Observer> observers_;
1019
kenossb68c9e82024-10-10 10:11:151020 bool is_likely_ahead_of_prerender_ = false;
1021
elabadysayedf7d6b00f2025-02-05 11:27:001022 // Time-to-live (TTL) for this prefetched data. Currently, this is configured
1023 // for browser-initiated prefetch that doesn't depend on web content.
1024 // Default value is `PrefetchContainerDefaultTtlInPrefetchService()`.
kenoss70bfbfe2025-06-10 08:04:421025 base::TimeDelta ttl_;
elabadysayedf7d6b00f2025-02-05 11:27:001026
elabadysayed90651cc2025-03-28 00:23:221027 // Whether to add the X-Client-Data header with experiment IDs from field
1028 // trials. This will not be applied to redirects. Currently, this is
1029 // configured for browser-initiated prefetch that doesn't depend on web
1030 // content.
1031 const bool should_append_variations_header_ = true;
1032
Taiyo Mizuhashicd08a8f2025-06-10 17:27:321033 // Whether the caller of prefetches requests to disable
1034 // `BlockUntilHeadTimeout`, which is currently calculated by
1035 // `PrefetchBlockUntilHeadTimeout()` as a `prefetch_params`.
1036 const bool should_disable_block_until_head_timeout_ = false;
1037
Taiyo Mizuhashid7c856992025-06-23 08:56:021038 // An optimization hint indicating how quickly this prefetch should be
1039 // available.
1040 const std::optional<PrefetchPriority> priority_ = std::nullopt;
1041
kenosseab3c422025-04-03 12:50:191042 // Timing information for metrics
1043 //
1044 // Constraint: That earlier one is null implies that later one is null.
1045 // E.g. `time_load_start_` is null implies `time_header_complete_` is null.
1046 std::optional<base::TimeTicks> time_added_to_prefetch_service_;
1047 std::optional<base::TimeTicks> time_initial_eligibility_got_;
1048 std::optional<base::TimeTicks> time_prefetch_started_;
Taiyo Mizuhashi98ecb382025-06-03 15:24:551049 std::optional<base::TimeTicks> time_url_request_started_;
kenosseab3c422025-04-03 12:50:191050 std::optional<base::TimeTicks> time_header_determined_successfully_;
1051 std::optional<base::TimeTicks> time_prefetch_completed_successfully_;
1052
Max Curran646fb642022-03-16 00:44:091053 base::WeakPtrFactory<PrefetchContainer> weak_method_factory_{this};
1054};
1055
Hiroshige Hayashizaki3876eee2023-03-27 04:42:041056// For debug logs.
1057CONTENT_EXPORT std::ostream& operator<<(
1058 std::ostream& ostream,
1059 const PrefetchContainer& prefetch_container);
1060
Hiroshige Hayashizaki4d53c802023-09-28 05:36:401061CONTENT_EXPORT std::ostream& operator<<(
1062 std::ostream& ostream,
Hiroshige Hayashizakif7f16b82023-10-10 01:57:471063 const PrefetchContainer::Key& prefetch_key);
1064
Kouhei Ueno929ee8e12024-07-05 03:09:561065CONTENT_EXPORT std::ostream& operator<<(std::ostream& ostream,
1066 PrefetchContainer::LoadState state);
1067
Max Curran646fb642022-03-16 00:44:091068} // namespace content
1069
Sreeja Kamishettyf66553a2022-07-14 17:41:271070#endif // CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_