Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [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 | #ifndef CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_ |
| 6 | #define CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_ |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 7 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 8 | #include <optional> |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 9 | #include <utility> |
Victor Hugo Vianna Silva | 0069272 | 2025-03-18 19:51:48 | [diff] [blame] | 10 | #include <variant> |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 11 | |
Ali Hijazi | 3162891 | 2023-06-05 18:13:41 | [diff] [blame] | 12 | #include "base/memory/raw_ref.h" |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 13 | #include "base/memory/weak_ptr.h" |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 14 | #include "base/observer_list.h" |
| 15 | #include "base/observer_list_types.h" |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 16 | #include "base/time/time.h" |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 17 | #include "content/browser/devtools/network_service_devtools_observer.h" |
elabadysayed | f7d6b00f | 2025-02-05 11:27:00 | [diff] [blame] | 18 | #include "content/browser/preloading/prefetch/prefetch_params.h" |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 19 | #include "content/browser/preloading/prefetch/prefetch_probe_result.h" |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 20 | #include "content/browser/preloading/prefetch/prefetch_status.h" |
Hiroshige Hayashizaki | c853c030 | 2023-09-13 08:51:07 | [diff] [blame] | 21 | #include "content/browser/preloading/prefetch/prefetch_streaming_url_loader_common_types.h" |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 22 | #include "content/browser/preloading/prefetch/prefetch_type.h" |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 23 | #include "content/browser/preloading/preload_pipeline_info_impl.h" |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 24 | #include "content/browser/preloading/speculation_rules/speculation_rules_tags.h" |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 25 | #include "content/common/content_export.h" |
| 26 | #include "content/public/browser/global_routing_id.h" |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 27 | #include "content/public/browser/prefetch_priority.h" |
Wayne Jackson Jr. | b22d53b2 | 2024-11-15 11:40:06 | [diff] [blame] | 28 | #include "content/public/browser/prefetch_request_status_listener.h" |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 29 | #include "content/public/browser/preload_pipeline_info.h" |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 30 | #include "content/public/browser/preloading.h" |
Hiroshige Hayashizaki | a00e4c8 | 2023-10-31 20:20:17 | [diff] [blame] | 31 | #include "content/public/browser/preloading_data.h" |
Liviu Tinta | 68a4580 | 2023-04-05 18:32:20 | [diff] [blame] | 32 | #include "net/http/http_no_vary_search_data.h" |
Wayne Jackson Jr. | 1b732247 | 2024-10-29 13:08:51 | [diff] [blame] | 33 | #include "net/http/http_request_headers.h" |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 34 | #include "services/metrics/public/cpp/ukm_source_id.h" |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 35 | #include "third_party/blink/public/common/tokens/tokens.h" |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 36 | #include "url/gurl.h" |
| 37 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 38 | namespace network { |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 39 | namespace mojom { |
| 40 | class CookieManager; |
| 41 | } // namespace mojom |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 42 | } // namespace network |
| 43 | |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 44 | namespace content { |
| 45 | |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 46 | class BrowserContext; |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 47 | class PrefetchCookieListener; |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 48 | class PrefetchDocumentManager; |
| 49 | class PrefetchNetworkContext; |
Hiroshige Hayashizaki | c853c030 | 2023-09-13 08:51:07 | [diff] [blame] | 50 | class PrefetchResponseReader; |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 51 | class PrefetchService; |
Hiroshige Hayashizaki | 386c502 | 2025-08-12 14:43:37 | [diff] [blame] | 52 | class PrefetchServingHandle; |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 53 | class PrefetchServingPageMetricsContainer; |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 54 | class PrefetchSingleRedirectHop; |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 55 | class PrefetchStreamingURLLoader; |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 56 | class PreloadingAttempt; |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 57 | class ProxyLookupClientImpl; |
Hiroshige Hayashizaki | 2cbf67b9 | 2023-10-23 17:40:07 | [diff] [blame] | 58 | class RenderFrameHost; |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 59 | class RenderFrameHostImpl; |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 60 | enum class PrefetchPotentialCandidateServingResult; |
Hiroshige Hayashizaki | b3ff61d | 2025-08-12 06:28:08 | [diff] [blame] | 61 | enum class PrefetchServableState; |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 62 | |
William Liu | ef93473 | 2022-11-02 22:46:29 | [diff] [blame] | 63 | // 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. |
| 68 | struct PrefetchResponseSizes { |
| 69 | int64_t encoded_data_length; |
| 70 | int64_t encoded_body_length; |
| 71 | int64_t decoded_body_length; |
| 72 | }; |
| 73 | |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 74 | // This class contains the state for a request to prefetch a specific URL. |
Hiroshige Hayashizaki | 73e4289 | 2023-06-26 16:48:48 | [diff] [blame] | 75 | // |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 76 | // 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 Hayashizaki | 73e4289 | 2023-06-26 16:48:48 | [diff] [blame] | 82 | // |
| 83 | // For example: |
| 84 | // |
| 85 | // |PrefetchStreamingURLLoader A-----| |PrefetchStreamingURLLoader B ---------| |
| 86 | // HandleRedirect - HandleRedirect - HandleRedirect - ReceiveResponse-Finish |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 87 | // |S.RedirectHop0-| |S.RedirectHop1-| |S.RedirectHop2-| |S.RedirectHop3------| |
Hiroshige Hayashizaki | 73e4289 | 2023-06-26 16:48:48 | [diff] [blame] | 88 | // |
| 89 | // While prefetching (see methods named like "ForCurrentPrefetch" or |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 90 | // "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 Hayashizaki | 73e4289 | 2023-06-26 16:48:48 | [diff] [blame] | 94 | // |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 95 | // 1. A new `PrefetchSingleRedirectHop` and thus a new |
Hiroshige Hayashizaki | 73e4289 | 2023-06-26 16:48:48 | [diff] [blame] | 96 | // `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 |
kenoss | 0c7bbc7 | 2024-07-24 08:52:40 | [diff] [blame] | 107 | // - `PrefetchService::OnGotEligibilityForRedirect()` [redirect]. |
Hiroshige Hayashizaki | 73e4289 | 2023-06-26 16:48:48 | [diff] [blame] | 108 | // A new `PrefetchStreamingURLLoader` is also created if needed in |
| 109 | // `PrefetchService::MakePrefetchRequest()`. |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 110 | class CONTENT_EXPORT PrefetchContainer { |
| 111 | public: |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 112 | // Ctor used for renderer-initiated prefetch. |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 113 | PrefetchContainer( |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 114 | RenderFrameHostImpl& referring_render_frame_host, |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 115 | const blink::DocumentToken& referring_document_token, |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 116 | const GURL& url, |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 117 | const PrefetchType& prefetch_type, |
Kevin McNee | e6ca089 | 2022-09-28 15:36:22 | [diff] [blame] | 118 | const blink::mojom::Referrer& referrer, |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 119 | std::optional<SpeculationRulesTags> speculation_rules_tags, |
Rulong Chen(陈汝龙) | bf12169c | 2024-12-16 05:38:16 | [diff] [blame] | 120 | std::optional<net::HttpNoVarySearchData> no_vary_search_hint, |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 121 | std::optional<PrefetchPriority> priority, |
Hiroshige Hayashizaki | a00e4c8 | 2023-10-31 20:20:17 | [diff] [blame] | 122 | base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager, |
kenoss | 3bd73b8 | 2024-10-10 20:33:49 | [diff] [blame] | 123 | scoped_refptr<PreloadPipelineInfo> preload_pipeline_info, |
Taiyo Mizuhashi | 0192d3f | 2024-02-15 05:09:43 | [diff] [blame] | 124 | base::WeakPtr<PreloadingAttempt> attempt = nullptr); |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 125 | |
| 126 | // Ctor used for browser-initiated prefetch. |
| 127 | // We can pass the referring origin of prefetches via `referring_origin` if |
Taiyo Mizuhashi | 9dfeb63 | 2024-10-24 08:44:20 | [diff] [blame] | 128 | // necessary. |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 129 | PrefetchContainer( |
| 130 | WebContents& referring_web_contents, |
| 131 | const GURL& url, |
| 132 | const PrefetchType& prefetch_type, |
Taiyo Mizuhashi | 49959d0 | 2025-04-22 16:07:54 | [diff] [blame] | 133 | const std::string& embedder_histogram_suffix, |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 134 | const blink::mojom::Referrer& referrer, |
| 135 | const std::optional<url::Origin>& referring_origin, |
Rulong Chen(陈汝龙) | bf12169c | 2024-12-16 05:38:16 | [diff] [blame] | 136 | std::optional<net::HttpNoVarySearchData> no_vary_search_hint, |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 137 | std::optional<PrefetchPriority> priority, |
kenoss | a1af66f1 | 2025-03-07 06:10:55 | [diff] [blame] | 138 | scoped_refptr<PreloadPipelineInfo> preload_pipeline_info, |
Taiyo Mizuhashi | 26f86c6b3 | 2024-10-02 03:58:46 | [diff] [blame] | 139 | base::WeakPtr<PreloadingAttempt> attempt = nullptr, |
| 140 | std::optional<PreloadingHoldbackStatus> holdback_status_override = |
kenoss | 6938554c | 2025-06-10 10:18:17 | [diff] [blame] | 141 | std::nullopt, |
| 142 | std::optional<base::TimeDelta> ttl = std::nullopt); |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 143 | |
Wayne Jackson Jr. | 5b1dc04 | 2024-09-09 12:53:10 | [diff] [blame] | 144 | // Ctor used for browser-initiated prefetch that doesn't depend on web |
| 145 | // contents. We can pass the referring origin of prefetches via |
Taiyo Mizuhashi | 9dfeb63 | 2024-10-24 08:44:20 | [diff] [blame] | 146 | // `referrer_origin` if necessary. |
Wayne Jackson Jr. | 5b1dc04 | 2024-09-09 12:53:10 | [diff] [blame] | 147 | PrefetchContainer( |
| 148 | BrowserContext* browser_context, |
| 149 | const GURL& url, |
| 150 | const PrefetchType& prefetch_type, |
Taiyo Mizuhashi | 49959d0 | 2025-04-22 16:07:54 | [diff] [blame] | 151 | const std::string& embedder_histogram_suffix, |
Wayne Jackson Jr. | 5b1dc04 | 2024-09-09 12:53:10 | [diff] [blame] | 152 | const blink::mojom::Referrer& referrer, |
| 153 | bool javascript_enabled, |
| 154 | const std::optional<url::Origin>& referring_origin, |
Rulong Chen(陈汝龙) | bf12169c | 2024-12-16 05:38:16 | [diff] [blame] | 155 | std::optional<net::HttpNoVarySearchData> no_vary_search_hint, |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 156 | std::optional<PrefetchPriority> priority, |
Wayne Jackson Jr. | 03a15fa6 | 2024-09-16 14:42:15 | [diff] [blame] | 157 | base::WeakPtr<PreloadingAttempt> attempt = nullptr, |
Wayne Jackson Jr. | 1b732247 | 2024-10-29 13:08:51 | [diff] [blame] | 158 | const net::HttpRequestHeaders& additional_headers = {}, |
Wayne Jackson Jr. | b22d53b2 | 2024-11-15 11:40:06 | [diff] [blame] | 159 | std::unique_ptr<PrefetchRequestStatusListener> request_status_listener = |
elabadysayed | f7d6b00f | 2025-02-05 11:27:00 | [diff] [blame] | 160 | nullptr, |
kenoss | 70bfbfe | 2025-06-10 08:04:42 | [diff] [blame] | 161 | base::TimeDelta ttl = PrefetchContainerDefaultTtlInPrefetchService(), |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 162 | bool should_append_variations_header = true, |
| 163 | bool should_disable_block_until_head_timeout = false); |
Wayne Jackson Jr. | 5b1dc04 | 2024-09-09 12:53:10 | [diff] [blame] | 164 | |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 165 | ~PrefetchContainer(); |
| 166 | |
| 167 | PrefetchContainer(const PrefetchContainer&) = delete; |
| 168 | PrefetchContainer& operator=(const PrefetchContainer&) = delete; |
| 169 | |
kenoss | 39741f51 | 2024-09-05 02:20:37 | [diff] [blame] | 170 | // 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 |
kenoss | 4d95166 | 2025-08-13 18:11:40 | [diff] [blame] | 189 | // embedder is used. See crbug.com/40942681. |
kenoss | 39741f51 | 2024-09-05 02:20:37 | [diff] [blame] | 190 | // |
| 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 Ueno | 34c7c6915 | 2023-11-16 04:42:42 | [diff] [blame] | 195 | class CONTENT_EXPORT Key { |
Kouhei Ueno | 45b00ef2 | 2023-11-10 02:22:58 | [diff] [blame] | 196 | public: |
| 197 | Key() = delete; |
kenoss | 39741f51 | 2024-09-05 02:20:37 | [diff] [blame] | 198 | Key(net::NetworkIsolationKey nik, GURL url); |
| 199 | Key(std::optional<blink::DocumentToken> referring_document_token, GURL url); |
Kouhei Ueno | 34c7c6915 | 2023-11-16 04:42:42 | [diff] [blame] | 200 | ~Key(); |
| 201 | |
kenoss | 4dc06866 | 2024-10-04 05:03:50 | [diff] [blame] | 202 | // Movable and copyable. |
| 203 | Key(Key&& other); |
| 204 | Key& operator=(Key&& other); |
| 205 | Key(const Key& other); |
| 206 | Key& operator=(const Key& other); |
Kouhei Ueno | 45b00ef2 | 2023-11-10 02:22:58 | [diff] [blame] | 207 | |
| 208 | bool operator==(const Key& rhs) const = default; |
| 209 | bool operator<(const Key& rhs) const { |
Kouhei Ueno | 34c7c6915 | 2023-11-16 04:42:42 | [diff] [blame] | 210 | 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 Ueno | 45b00ef2 | 2023-11-10 02:22:58 | [diff] [blame] | 214 | } |
kenoss | 39741f51 | 2024-09-05 02:20:37 | [diff] [blame] | 215 | return url_ < rhs.url_; |
Kouhei Ueno | 45b00ef2 | 2023-11-10 02:22:58 | [diff] [blame] | 216 | } |
| 217 | |
kenoss | 39741f51 | 2024-09-05 02:20:37 | [diff] [blame] | 218 | const GURL& url() const { return url_; } |
Kouhei Ueno | 45b00ef2 | 2023-11-10 02:22:58 | [diff] [blame] | 219 | |
Kouhei Ueno | ebacf89 | 2023-11-14 03:41:43 | [diff] [blame] | 220 | Key WithNewUrl(const GURL& new_url) const { |
Victor Hugo Vianna Silva | 0069272 | 2025-03-18 19:51:48 | [diff] [blame] | 221 | return std::visit([&](const auto& e) { return Key(e, new_url); }, |
| 222 | referring_document_token_or_nik_); |
Kouhei Ueno | ebacf89 | 2023-11-14 03:41:43 | [diff] [blame] | 223 | } |
| 224 | |
| 225 | bool NonUrlPartIsSame(const Key& other) const { |
Kouhei Ueno | 34c7c6915 | 2023-11-16 04:42:42 | [diff] [blame] | 226 | return referring_document_token_or_nik_ == |
| 227 | other.referring_document_token_or_nik_; |
Kouhei Ueno | ebacf89 | 2023-11-14 03:41:43 | [diff] [blame] | 228 | } |
| 229 | |
Kouhei Ueno | 45b00ef2 | 2023-11-10 02:22:58 | [diff] [blame] | 230 | private: |
| 231 | friend CONTENT_EXPORT std::ostream& operator<<(std::ostream& ostream, |
| 232 | const Key& prefetch_key); |
| 233 | |
Victor Hugo Vianna Silva | 0069272 | 2025-03-18 19:51:48 | [diff] [blame] | 234 | std::variant<std::optional<blink::DocumentToken>, net::NetworkIsolationKey> |
Kouhei Ueno | 34c7c6915 | 2023-11-16 04:42:42 | [diff] [blame] | 235 | referring_document_token_or_nik_; |
kenoss | 4dc06866 | 2024-10-04 05:03:50 | [diff] [blame] | 236 | GURL url_; |
Kouhei Ueno | 45b00ef2 | 2023-11-10 02:22:58 | [diff] [blame] | 237 | }; |
| 238 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 239 | // 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 Hayashizaki | 6a103bad | 2025-07-11 02:15:32 | [diff] [blame] | 244 | // `PrefetchMatchResolver` and some other prefetch-internal classes. |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 245 | 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; |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 252 | // Called when initial eligibility is got. |
| 253 | virtual void OnGotInitialEligibility(PrefetchContainer& prefetch_container, |
| 254 | PreloadingEligibility eligibility) = 0; |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 255 | // 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; |
kenoss | b4e57f7 | 2025-06-16 08:28:40 | [diff] [blame] | 259 | // Called when load of prefetch completed or failed. |
| 260 | virtual void OnPrefetchCompletedOrFailed( |
Hiroshige Hayashizaki | 6a103bad | 2025-07-11 02:15:32 | [diff] [blame] | 261 | PrefetchContainer& prefetch_container, |
kenoss | b4e57f7 | 2025-06-16 08:28:40 | [diff] [blame] | 262 | const network::URLLoaderCompletionStatus& completion_status, |
| 263 | const std::optional<int>& response_code) = 0; |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 264 | }; |
| 265 | |
| 266 | void OnWillBeDestroyed(); |
| 267 | |
kenoss | af6e0ae | 2024-09-05 03:06:50 | [diff] [blame] | 268 | const Key& key() const { return key_; } |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 269 | |
Rakina Zata Amni | 39d8e7e | 2022-10-20 18:18:30 | [diff] [blame] | 270 | // The ID of the RenderFrameHost that triggered the prefetch. |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 271 | const GlobalRenderFrameHostId& GetReferringRenderFrameHostId() const { |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 272 | return referring_render_frame_host_id_; |
| 273 | } |
Kevin McNee | 06824c7 | 2024-02-06 18:59:52 | [diff] [blame] | 274 | bool HasSameReferringURLForMetrics(const PrefetchContainer& other) const; |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 275 | |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 276 | // The initial URL that was requested to be prefetched. |
kenoss | 39741f51 | 2024-09-05 02:20:37 | [diff] [blame] | 277 | const GURL& GetURL() const { return key_.url(); } |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 278 | |
Jeremy Roman | 45c89d01 | 2023-08-30 21:22:02 | [diff] [blame] | 279 | // 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 Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 285 | // 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 Lin | 9b73037 | 2025-03-28 05:50:45 | [diff] [blame] | 289 | // Returns the serialized string of speculation rules tags. |
| 290 | std::optional<std::string> GetSpeculationRulesTagsHeaderString() { |
| 291 | return speculation_rules_tags_->ConvertStringToHeaderString(); |
| 292 | } |
| 293 | |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 294 | // The type of this prefetch. Controls how the prefetch is handled. |
| 295 | const PrefetchType& GetPrefetchType() const { return prefetch_type_; } |
| 296 | |
Taiyo Mizuhashi | dd5dfdf | 2024-03-11 17:04:10 | [diff] [blame] | 297 | // 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 Mizuhashi | 2155946 | 2024-02-22 00:07:56 | [diff] [blame] | 302 | // The origin and that initiates the prefetch request. |
Taiyo Mizuhashi | 9dfeb63 | 2024-10-24 08:44:20 | [diff] [blame] | 303 | const std::optional<url::Origin> GetReferringOrigin() const { |
| 304 | return referring_origin_; |
| 305 | } |
Taiyo Mizuhashi | 2155946 | 2024-02-22 00:07:56 | [diff] [blame] | 306 | |
Hiroshige Hayashizaki | b8c4bf60 | 2023-05-26 01:34:58 | [diff] [blame] | 307 | // Whether or not an isolated network context is required to the next |
| 308 | // prefetch. |
| 309 | bool IsIsolatedNetworkContextRequiredForCurrentPrefetch() const; |
Max Curran | 4870096 | 2023-05-15 18:35:52 | [diff] [blame] | 310 | |
| 311 | // Whether or not an isolated network context is required for the previous |
| 312 | // redirect hop of the given url. |
Hiroshige Hayashizaki | b8c4bf60 | 2023-05-26 01:34:58 | [diff] [blame] | 313 | bool IsIsolatedNetworkContextRequiredForPreviousRedirectHop() const; |
| 314 | |
Hiroshige Hayashizaki | 73e4289 | 2023-06-26 16:48:48 | [diff] [blame] | 315 | base::WeakPtr<PrefetchResponseReader> GetResponseReaderForCurrentPrefetch(); |
| 316 | |
Max Curran | c013750 | 2023-05-02 18:06:22 | [diff] [blame] | 317 | // 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 Roman | 45c89d01 | 2023-08-30 21:22:02 | [diff] [blame] | 321 | const network::ResourceRequest* GetResourceRequest() const { |
| 322 | return resource_request_.get(); |
| 323 | } |
| 324 | void MakeResourceRequest(const net::HttpRequestHeaders& additional_headers); |
| 325 | |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 326 | // Updates |referrer_| after a redirect. |
| 327 | void UpdateReferrer( |
| 328 | const GURL& new_referrer_url, |
| 329 | const network::mojom::ReferrerPolicy& new_referrer_policy); |
| 330 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 331 | const std::optional<net::HttpNoVarySearchData>& GetNoVarySearchHint() const { |
Liviu Tinta | 953bde88 | 2023-05-05 13:21:35 | [diff] [blame] | 332 | return no_vary_search_hint_; |
Liviu Tinta | 68a4580 | 2023-04-05 18:32:20 | [diff] [blame] | 333 | } |
| 334 | |
Alan Cutter | 5525a85 | 2022-10-07 03:53:31 | [diff] [blame] | 335 | base::WeakPtr<PrefetchContainer> GetWeakPtr() { |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 336 | return weak_method_factory_.GetWeakPtr(); |
| 337 | } |
| 338 | |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 339 | // The status of the current prefetch. Note that |HasPrefetchStatus| will be |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 340 | // initially false until |SetPrefetchStatus| is called. |SetPrefetchStatus| |
Taiyo Mizuhashi | c3f14f4 | 2024-08-28 00:16:50 | [diff] [blame] | 341 | // also sets |attempt_| PreloadingTriggeringOutcome and |
| 342 | // PreloadingFailureReason. It is only safe to call after |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 343 | // `OnEligibilityCheckComplete`. |
| 344 | void SetPrefetchStatus(PrefetchStatus prefetch_status); |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 345 | bool HasPrefetchStatus() const { return prefetch_status_.has_value(); } |
| 346 | PrefetchStatus GetPrefetchStatus() const; |
| 347 | |
Taiyo Mizuhashi | 26f86c6b3 | 2024-10-02 03:58:46 | [diff] [blame] | 348 | // 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 Hayashizaki | 4ce0f429 | 2023-11-07 19:24:58 | [diff] [blame] | 359 | // 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 Hayashizaki | 6b7035c0 | 2025-07-18 21:06:32 | [diff] [blame] | 380 | // Not heldback: |
Hiroshige Hayashizaki | 4ce0f429 | 2023-11-07 19:24:58 | [diff] [blame] | 381 | // |
Hiroshige Hayashizaki | 6b7035c0 | 2025-07-18 21:06:32 | [diff] [blame] | 382 | // On these states, refer to `PrefetchResponseReader`s for detailed |
Hiroshige Hayashizaki | 4ce0f429 | 2023-11-07 19:24:58 | [diff] [blame] | 383 | // prefetching state and servability. |
| 384 | // |
Hiroshige Hayashizaki | 6b7035c0 | 2025-07-18 21:06:32 | [diff] [blame] | 385 | // - `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 Hayashizaki | 4ce0f429 | 2023-11-07 19:24:58 | [diff] [blame] | 405 | // 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 Hayashizaki | 6b7035c0 | 2025-07-18 21:06:32 | [diff] [blame] | 413 | kDeterminedHead, |
| 414 | kCompletedOrFailed, |
Hiroshige Hayashizaki | 4ce0f429 | 2023-11-07 19:24:58 | [diff] [blame] | 415 | |
| 416 | // [Final state] Heldback due to `PreloadingAttempt::ShouldHoldback()`. |
| 417 | kFailedHeldback, |
| 418 | }; |
| 419 | void SetLoadState(LoadState prefetch_status); |
| 420 | LoadState GetLoadState() const; |
| 421 | |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 422 | // 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 | |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 428 | // Called when it is added to `PrefetchService::owned_prefetches_`. |
| 429 | void OnAddedToPrefetchService(); |
| 430 | |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 431 | // Whether or not the prefetch was determined to be eligibile. |
Hiroshige Hayashizaki | 939c5ed4 | 2023-11-01 03:29:21 | [diff] [blame] | 432 | void OnEligibilityCheckComplete(PreloadingEligibility eligibility); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 433 | |
| 434 | // Adds a the new URL to |redirect_chain_|. |
Jeremy Roman | 45c89d01 | 2023-08-30 21:22:02 | [diff] [blame] | 435 | void AddRedirectHop(const net::RedirectInfo& redirect_info); |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 436 | |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 437 | // The length of the redirect chain for this prefetch. |
| 438 | size_t GetRedirectChainSize() const { return redirect_chain_.size(); } |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 439 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 440 | // 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 Mizuhashi | 9dfeb63 | 2024-10-24 08:44:20 | [diff] [blame] | 445 | // 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 Roman | e561b41 | 2024-02-15 18:31:34 | [diff] [blame] | 449 | // 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 Hayashizaki | eec97ed1 | 2023-05-26 06:38:32 | [diff] [blame] | 455 | // Allows for |PrefetchCookieListener|s to be reigsitered for |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 456 | // `GetCurrentSingleRedirectHopToPrefetch()`. |
Hiroshige Hayashizaki | eec97ed1 | 2023-05-26 06:38:32 | [diff] [blame] | 457 | void RegisterCookieListener(network::mojom::CookieManager* cookie_manager); |
Taiyo Mizuhashi | 8b5ddcc | 2025-02-21 22:12:12 | [diff] [blame] | 458 | void PauseAllCookieListeners(); |
| 459 | void ResumeAllCookieListeners(); |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 460 | |
Hiroshige Hayashizaki | d44edd4e | 2025-08-12 07:35:46 | [diff] [blame] | 461 | // 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 Hayashizaki | b8c4bf60 | 2023-05-26 01:34:58 | [diff] [blame] | 466 | // The network context used to make network requests for the next prefetch. |
Kouhei Ueno | 4442db9 | 2023-11-13 06:38:13 | [diff] [blame] | 467 | PrefetchNetworkContext* GetOrCreateNetworkContextForCurrentPrefetch(); |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 468 | |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 469 | // Closes idle connections for all elements in |network_contexts_|. |
| 470 | void CloseIdleConnections(); |
| 471 | |
Hiroshige Hayashizaki | 638018f | 2023-09-12 17:05:45 | [diff] [blame] | 472 | // Set the currently prefetching |PrefetchStreamingURLLoader|. |
| 473 | void SetStreamingURLLoader( |
| 474 | base::WeakPtr<PrefetchStreamingURLLoader> streaming_loader); |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 475 | |
Hiroshige Hayashizaki | 638018f | 2023-09-12 17:05:45 | [diff] [blame] | 476 | // Returns the URL loader being used for prefetching the current redirect hop. |
Hiroshige Hayashizaki | 334d0fa | 2023-08-16 23:33:27 | [diff] [blame] | 477 | // This method should be used during prefetching and shouldn't be called for |
| 478 | // serving purpose. |
Taiyo Mizuhashi | 08c47d1 | 2025-03-05 23:46:07 | [diff] [blame] | 479 | base::WeakPtr<PrefetchStreamingURLLoader> GetStreamingURLLoader() const; |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 480 | |
Hiroshige Hayashizaki | 5c50ec5 | 2023-09-13 00:35:49 | [diff] [blame] | 481 | bool IsStreamingURLLoaderDeletionScheduledForTesting() const; |
| 482 | |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 483 | // Returns the PrefetchResponseReader of the prefetched non-redirect response |
| 484 | // if already received its head. Ruturns nullptr otherwise. |
Hiroshige Hayashizaki | 334d0fa | 2023-08-16 23:33:27 | [diff] [blame] | 485 | const PrefetchResponseReader* GetNonRedirectResponseReader() const; |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 486 | // Returns the head of the prefetched non-redirect response if already |
| 487 | // received. Ruturns nullptr otherwise. |
| 488 | const network::mojom::URLResponseHead* GetNonRedirectHead() const; |
Hiroshige Hayashizaki | 334d0fa | 2023-08-16 23:33:27 | [diff] [blame] | 489 | |
Hiroshige Hayashizaki | 638018f | 2023-09-12 17:05:45 | [diff] [blame] | 490 | // 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 Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 496 | // TODO(crbug.com/40064891): For callsites outside the destructor, remove the |
Hiroshige Hayashizaki | 638018f | 2023-09-12 17:05:45 | [diff] [blame] | 497 | // 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 Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 501 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 502 | // The |PrefetchDocumentManager| that requested |this|. |
| 503 | PrefetchDocumentManager* GetPrefetchDocumentManager() const; |
| 504 | |
Max Curran | e044494 | 2022-09-06 23:55:23 | [diff] [blame] | 505 | // 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 Hayashizaki | c0b6aea | 2023-10-17 21:56:43 | [diff] [blame] | 508 | bool HasPrefetchBeenConsideredToServe() const; |
Max Curran | e044494 | 2022-09-06 23:55:23 | [diff] [blame] | 509 | |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 510 | // Called when |PrefetchService::OnPrefetchComplete| is called for the |
| 511 | // prefetch. This happens when |loader_| fully downloads the requested |
| 512 | // resource. |
Hiroshige Hayashizaki | 77083bc8 | 2023-11-28 06:04:17 | [diff] [blame] | 513 | void OnPrefetchComplete( |
| 514 | const network::URLLoaderCompletionStatus& completion_status); |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 515 | |
Hiroshige Hayashizaki | 8f74d22b | 2023-09-28 04:48:08 | [diff] [blame] | 516 | // 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 Hayashizaki | b3ff61d | 2025-08-12 06:28:08 | [diff] [blame] | 519 | PrefetchServableState GetServableState( |
| 520 | base::TimeDelta cacheable_duration) const; |
Max Curran | 6b93426f | 2022-05-03 00:55:52 | [diff] [blame] | 521 | |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 522 | // Starts blocking `PrefetchMatchResolver` until non-redirect response header |
| 523 | // is determined or timeouted. `on_maybe_determined_head_callback` will be |
| 524 | // called when |
kenoss | 5a5ad980 | 2024-06-28 10:29:11 | [diff] [blame] | 525 | // |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 526 | // - `PrefetchStreamingURLLoader` succeeded/failed to fetch non-redirect |
| 527 | // response header. |
kenoss | 5a5ad980 | 2024-06-28 10:29:11 | [diff] [blame] | 528 | // - The argument `timeout` is positive and timeouted. |
| 529 | // - `PrefetchContainer` dtor if `kPrefetchUnblockOnCancel` enabled. |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 530 | 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. |
kenoss | 5a5ad980 | 2024-06-28 10:29:11 | [diff] [blame] | 535 | // |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 536 | // This method must be called at most once in the lifecycle of |
| 537 | // `PrefetchContainer`. |
kenoss | 8fb8285 | 2025-03-11 02:20:42 | [diff] [blame] | 538 | void OnDeterminedHead(); |
kenoss | f7b4d60d | 2024-07-16 15:15:08 | [diff] [blame] | 539 | // Unblocks waiting `PrefetchMatchResolver`. |
| 540 | // |
| 541 | // This method can be called multiple times. |
| 542 | void UnblockPrefetchMatchResolver(); |
Liviu Tinta | d97a6a3 | 2022-12-08 23:28:40 | [diff] [blame] | 543 | |
elabadysayed | f7d6b00f | 2025-02-05 11:27:00 | [diff] [blame] | 544 | void StartTimeoutTimerIfNeeded(base::OnceClosure on_timeout_callback); |
Hiroshige Hayashizaki | d2161a2e | 2023-10-23 16:22:50 | [diff] [blame] | 545 | |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 546 | // 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 Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 549 | std::optional<base::TimeDelta> GetPrefetchHeaderLatency() const { |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 550 | return header_latency_; |
| 551 | } |
| 552 | |
Max Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 553 | // 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 Mizuhashi | 9395b7c8 | 2024-05-16 20:30:26 | [diff] [blame] | 558 | // Returns request id to be used by DevTools and test utilities. |
Iman Saboori | 65c356d | 2022-07-15 14:47:47 | [diff] [blame] | 559 | const std::string& RequestId() const { return request_id_; } |
| 560 | |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 561 | bool HasPreloadingAttempt() { return !!attempt_; } |
Simon Pelchat | 9ed3e99 | 2023-02-17 01:16:16 | [diff] [blame] | 562 | base::WeakPtr<PreloadingAttempt> preloading_attempt() { return attempt_; } |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 563 | |
Hiroshige Hayashizaki | 64802cf1 | 2025-01-16 23:18:46 | [diff] [blame] | 564 | // 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 Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 584 | void DisablePrecogLoggingForTest() { attempt_ = nullptr; } |
| 585 | |
Hiroshige Hayashizaki | 29e14dd | 2025-03-14 16:03:07 | [diff] [blame] | 586 | // 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 Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 592 | const std::optional<net::HttpNoVarySearchData>& GetNoVarySearchData() const { |
Hiroshige Hayashizaki | 47a8363 | 2023-06-16 18:09:22 | [diff] [blame] | 593 | return no_vary_search_data_; |
| 594 | } |
Hiroshige Hayashizaki | 2cbf67b9 | 2023-10-23 17:40:07 | [diff] [blame] | 595 | // Sets `no_vary_search_data_` from `GetHead()`. Exposed for tests. |
Taiyo Mizuhashi | 9a1ab988 | 2024-11-28 08:29:08 | [diff] [blame] | 596 | void MaybeSetNoVarySearchData(); |
Hiroshige Hayashizaki | 47a8363 | 2023-06-16 18:09:22 | [diff] [blame] | 597 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 598 | // 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 |
kenoss | 3dfd9079 | 2025-03-11 01:13:46 | [diff] [blame] | 604 | // of redirect chain. `PrefetchMatchResolver` propagates it to other waiting |
| 605 | // prefetches as they share domain. |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 606 | // - When `PrefetchURLLoaderInterceptor::MaybeCreateLoader()` handles |
| 607 | // redirects in the serving prefetch. |
kenoss | 8fb8285 | 2025-03-11 02:20:42 | [diff] [blame] | 608 | void OnDetectedCookiesChange( |
kenoss | b1c65dbc | 2024-12-13 08:23:49 | [diff] [blame] | 609 | std::optional<bool> |
| 610 | is_unblock_for_cookies_changed_triggered_by_this_prefetch_container); |
Hiroshige Hayashizaki | a51f624be | 2023-10-24 16:29:57 | [diff] [blame] | 611 | |
Wayne Jackson Jr. | 03a15fa6 | 2024-09-16 14:42:15 | [diff] [blame] | 612 | // Called when the prefetch request is started (i.e. the URL loader is created |
| 613 | // & started). |
| 614 | void OnPrefetchStarted(); |
| 615 | |
Hiroshige Hayashizaki | 386c502 | 2025-08-12 14:43:37 | [diff] [blame] | 616 | PrefetchServingHandle CreateServingHandle(); |
Hiroshige Hayashizaki | 6a99ee9 | 2023-05-30 19:54:37 | [diff] [blame] | 617 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 618 | void AddObserver(Observer* observer); |
| 619 | void RemoveObserver(Observer* observer); |
| 620 | |
kenoss | da3d13b | 2024-08-15 16:31:19 | [diff] [blame] | 621 | bool IsExactMatch(const GURL& url) const; |
| 622 | bool IsNoVarySearchHeaderMatch(const GURL& url) const; |
kenoss | b9b4063 | 2024-10-01 15:43:24 | [diff] [blame] | 623 | // 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; |
kenoss | da3d13b | 2024-08-15 16:31:19 | [diff] [blame] | 629 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 630 | // Records metrics when serving result is determined. |
| 631 | // |
| 632 | // This is eventually called once for every `PrefetchContainer` put in |
kenoss | 3dfd9079 | 2025-03-11 01:13:46 | [diff] [blame] | 633 | // `PrefetchMatchResolver::candidates_`, i.e. those potentially matching |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 634 | // and expected to become servable at the head of |
kenoss | 3dfd9079 | 2025-03-11 01:13:46 | [diff] [blame] | 635 | // `PrefetchMatchResolver::FindPrefetch()`. |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 636 | // |
| 637 | // This can be called multiple times, because this can be called for multiple |
kenoss | 3dfd9079 | 2025-03-11 01:13:46 | [diff] [blame] | 638 | // `PrefetchMatchResolver`s. |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 639 | 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); |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 645 | |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 646 | // 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 Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 680 | // Handles loader related events. Currently used for DevTools and metrics. |
kenoss | 1ce36df59 | 2024-12-03 01:04:35 | [diff] [blame] | 681 | 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 | |
kenoss | 6c5fb09 | 2024-07-05 05:42:14 | [diff] [blame] | 690 | bool is_in_dtor() const { return is_in_dtor_; } |
| 691 | |
Hiroshige Hayashizaki | 0830e18 | 2025-03-14 02:03:06 | [diff] [blame] | 692 | void OnServiceWorkerStateDetermined( |
| 693 | PrefetchServiceWorkerState service_worker_state); |
| 694 | PrefetchServiceWorkerState service_worker_state() const { |
| 695 | return service_worker_state_; |
| 696 | } |
| 697 | |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 698 | bool ShouldDisableBlockUntilHeadTimeout() const { |
| 699 | return should_disable_block_until_head_timeout_; |
| 700 | } |
| 701 | |
Taiyo Mizuhashi | 53da92d | 2025-06-23 08:56:15 | [diff] [blame] | 702 | std::optional<PrefetchPriority> GetPrefetchPriority() const { |
| 703 | return priority_; |
| 704 | } |
| 705 | |
Hiroshige Hayashizaki | 386c502 | 2025-08-12 14:43:37 | [diff] [blame] | 706 | // 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 Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 716 | protected: |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 717 | // Updates metrics based on the result of the prefetch request. |
| 718 | void UpdatePrefetchRequestMetrics( |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 719 | const network::mojom::URLResponseHead* head); |
| 720 | |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 721 | private: |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 722 | PrefetchContainer( |
| 723 | const GlobalRenderFrameHostId& referring_render_frame_host_id, |
Taiyo Mizuhashi | 9dfeb63 | 2024-10-24 08:44:20 | [diff] [blame] | 724 | const std::optional<url::Origin>& referring_origin, |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 725 | const std::optional<size_t>& referring_url_hash, |
| 726 | const PrefetchContainer::Key& key, |
| 727 | const PrefetchType& prefetch_type, |
Taiyo Mizuhashi | 49959d0 | 2025-04-22 16:07:54 | [diff] [blame] | 728 | const std::optional<std::string>& embedder_histogram_suffix, |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 729 | const blink::mojom::Referrer& referrer, |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 730 | std::optional<SpeculationRulesTags> speculation_rules_tags, |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 731 | 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, |
kenoss | 3bd73b8 | 2024-10-10 20:33:49 | [diff] [blame] | 735 | scoped_refptr<PreloadPipelineInfo> preload_pipeline_info, |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 736 | base::WeakPtr<PreloadingAttempt> attempt, |
Taiyo Mizuhashi | 26f86c6b3 | 2024-10-02 03:58:46 | [diff] [blame] | 737 | std::optional<PreloadingHoldbackStatus> holdback_status_override, |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 738 | std::optional<base::UnguessableToken> initiator_devtools_navigation_token, |
Wayne Jackson Jr. | 1b732247 | 2024-10-29 13:08:51 | [diff] [blame] | 739 | const net::HttpRequestHeaders& additional_headers, |
Wayne Jackson Jr. | b22d53b2 | 2024-11-15 11:40:06 | [diff] [blame] | 740 | std::unique_ptr<PrefetchRequestStatusListener> request_status_listener, |
elabadysayed | f7d6b00f | 2025-02-05 11:27:00 | [diff] [blame] | 741 | bool is_javascript_enabled, |
kenoss | 70bfbfe | 2025-06-10 08:04:42 | [diff] [blame] | 742 | base::TimeDelta ttl, |
Taiyo Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 743 | bool should_append_variations_header, |
Taiyo Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 744 | bool should_disable_block_until_head_timeout, |
| 745 | std::optional<PrefetchPriority> priority); |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 746 | |
Robert Lin | 92f3617e | 2023-05-20 10:14:49 | [diff] [blame] | 747 | // Update |prefetch_status_| and report prefetch status to |
| 748 | // DevTools without updating TriggeringOutcome. |
| 749 | void SetPrefetchStatusWithoutUpdatingTriggeringOutcome( |
| 750 | PrefetchStatus prefetch_status); |
| 751 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 752 | // Updates `attempt_`'s outcome and failure reason based on |
| 753 | // `new_prefetch_status`. |
Taiyo Mizuhashi | 070baec | 2025-03-28 15:37:00 | [diff] [blame] | 754 | // 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 Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 756 | void SetTriggeringOutcomeAndFailureReasonFromStatus( |
| 757 | PrefetchStatus new_prefetch_status); |
| 758 | |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 759 | // Add client hints headers to a request bound for |origin|. |
| 760 | void AddClientHintsHeaders(const url::Origin& origin, |
| 761 | net::HttpRequestHeaders* request_headers); |
Liviu Tinta | 2e1ffe2 | 2024-06-21 21:01:33 | [diff] [blame] | 762 | // Add X-Client-Data request header to a request. |
| 763 | void AddXClientDataHeader(network::ResourceRequest& request); |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 764 | |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 765 | // 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 Hayashizaki | 8ce7d8d | 2023-05-26 00:16:32 | [diff] [blame] | 770 | |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 771 | // 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 Hayashizaki | 8ce7d8d | 2023-05-26 00:16:32 | [diff] [blame] | 776 | |
kenoss | 5df53e05 | 2024-06-17 06:59:52 | [diff] [blame] | 777 | // 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. | 00e3e8b | 2024-09-25 12:35:56 | [diff] [blame] | 780 | // 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 Hayashizaki | 03a5905 | 2025-08-12 14:44:23 | [diff] [blame] | 785 | std::string GetMetricsSuffix() const; |
| 786 | |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 787 | // 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 Mizuhashi | 98061e2 | 2025-07-12 05:26:54 | [diff] [blame] | 793 | // Records UMAs tracking some certain durations during prefetch addition to |
| 794 | // prefetch completion (e.g. `Prefetch.PrefetchContainer.AddedTo*`). |
| 795 | void RecordPrefetchDurationHistogram(); |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 796 | // Records `Prefetch.PrefetchMatchingBlockedNavigationWithPrefetch.*` UMAs. |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 797 | void RecordPrefetchMatchingBlockedNavigationHistogram(bool blocked_until_head, |
| 798 | bool is_nav_prerender); |
Taiyo Mizuhashi | a009caf | 2025-08-05 07:34:22 | [diff] [blame] | 799 | // Records `Prefetch.PrefetchContainer.ServedCount`. |
| 800 | void RecordPrefetchContainerServedCountHistogram(); |
| 801 | |
Taiyo Mizuhashi | 43066071f | 2025-04-25 23:40:22 | [diff] [blame] | 802 | // Records `Prefetch.BlockUntilHeadDuration.*` UMAs. |
| 803 | void RecordBlockUntilHeadDurationHistogram( |
| 804 | const std::optional<base::TimeDelta>& blocked_duration, |
kenoss | 4bdf2d8 | 2025-05-27 01:58:45 | [diff] [blame] | 805 | bool served, |
| 806 | bool is_nav_prerender); |
Taiyo Mizuhashi | 09f571f | 2025-08-04 16:05:54 | [diff] [blame] | 807 | // Records |
| 808 | // `Prefetch.PrefetchPotentialCandidateServingResult.PerMatchingCandidate.*` |
| 809 | // UMAs. |
| 810 | void RecordPrefetchPotentialCandidateServingResultHistogram( |
| 811 | PrefetchPotentialCandidateServingResult matching_result); |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 812 | |
Hiroshige Hayashizaki | db5f196 | 2025-07-14 22:38:20 | [diff] [blame] | 813 | // 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 Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 819 | // The ID of the RenderFrameHost/Document that triggered the prefetch. |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 820 | // This will be empty when browser-initiated prefetch. |
Hiroshige Hayashizaki | 2df4529 | 2023-10-10 22:59:03 | [diff] [blame] | 821 | const GlobalRenderFrameHostId referring_render_frame_host_id_; |
Taiyo Mizuhashi | 2155946 | 2024-02-22 00:07:56 | [diff] [blame] | 822 | |
Hiroshige Hayashizaki | 0830e18 | 2025-03-14 02:03:06 | [diff] [blame] | 823 | PrefetchServiceWorkerState service_worker_state_ = |
| 824 | PrefetchServiceWorkerState::kAllowed; |
| 825 | |
Taiyo Mizuhashi | 2155946 | 2024-02-22 00:07:56 | [diff] [blame] | 826 | // The origin and URL that initiates the prefetch request. |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 827 | // For renderer-initiated prefetch, this is calculated by referring |
| 828 | // RenderFrameHost's LastCommittedOrigin. For browser-initiated prefetch, this |
Taiyo Mizuhashi | 9dfeb63 | 2024-10-24 08:44:20 | [diff] [blame] | 829 | // is sometimes explicitly passed via ctor. |
| 830 | const std::optional<url::Origin> referring_origin_; |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 831 | // Used by metrics for equality checks, only works for renderer-initiated |
| 832 | // triggers. |
| 833 | const std::optional<size_t> referring_url_hash_; |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 834 | |
Kouhei Ueno | 8ce5445 | 2023-11-21 03:58:02 | [diff] [blame] | 835 | // The key used to match this PrefetchContainer, including the URL that was |
| 836 | // requested to prefetch. |
| 837 | const PrefetchContainer::Key key_; |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 838 | |
| 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 Mizuhashi | 49959d0 | 2025-04-22 16:07:54 | [diff] [blame] | 846 | // 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 McNee | e6ca089 | 2022-09-28 15:36:22 | [diff] [blame] | 851 | // The referrer to use for the request. |
Devlin Cronin | 7f318c1 | 2023-06-09 00:57:01 | [diff] [blame] | 852 | blink::mojom::Referrer referrer_; |
Kevin McNee | e6ca089 | 2022-09-28 15:36:22 | [diff] [blame] | 853 | |
Jeremy Roman | 45c89d01 | 2023-08-30 21:22:02 | [diff] [blame] | 854 | // 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 Hayashizaki | 47a8363 | 2023-06-16 18:09:22 | [diff] [blame] | 859 | // The No-Vary-Search response data, parsed from the actual response header |
| 860 | // (`GetHead()`). |
Hiroshige Hayashizaki | 2cbf67b9 | 2023-10-23 17:40:07 | [diff] [blame] | 861 | // 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 Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 863 | std::optional<net::HttpNoVarySearchData> no_vary_search_data_; |
Hiroshige Hayashizaki | 47a8363 | 2023-06-16 18:09:22 | [diff] [blame] | 864 | |
| 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 Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 867 | const std::optional<net::HttpNoVarySearchData> no_vary_search_hint_; |
Liviu Tinta | 68a4580 | 2023-04-05 18:32:20 | [diff] [blame] | 868 | |
HuanPo Lin | 740620b | 2025-03-21 12:37:26 | [diff] [blame] | 869 | // 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 Mizuhashi | fc6afd6c | 2024-01-26 06:53:07 | [diff] [blame] | 875 | // The |PrefetchDocumentManager| that requested |this|. |
Taiyo Mizuhashi | 1b23ca6 | 2024-03-28 22:07:37 | [diff] [blame] | 876 | // This will be nullptr when the prefetch is initiated by browser. |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 877 | base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager_; |
| 878 | |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 879 | // The |BrowserContext| in which this is being run. |
| 880 | base::WeakPtr<BrowserContext> browser_context_; |
| 881 | |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 882 | // The current status, if any, of the prefetch. |
Alison Gale | 81f4f2c7 | 2024-04-22 19:33:31 | [diff] [blame] | 883 | // TODO(crbug.com/40075414): Use `load_state_` instead for non-metrics |
| 884 | // purpose. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 885 | std::optional<PrefetchStatus> prefetch_status_; |
Adithya Srinivasan | 4d3dad0 | 2024-10-17 18:06:59 | [diff] [blame] | 886 | bool prefetch_status_recorded_to_uma_ = false; |
Max Curran | 146bf44 | 2022-03-28 23:22:14 | [diff] [blame] | 887 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 888 | // 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 Hayashizaki | 4ce0f429 | 2023-11-07 19:24:58 | [diff] [blame] | 893 | // The current status of the prefetch. |
| 894 | LoadState load_state_ = LoadState::kNotStarted; |
| 895 | |
Max Curran | 5d4da4b4 | 2023-03-10 23:41:46 | [diff] [blame] | 896 | // Looks up the proxy settings in the default network context all URLs in |
| 897 | // |redirect_chain_|. |
Max Curran | cc1ab0c | 2022-09-12 22:03:11 | [diff] [blame] | 898 | std::unique_ptr<ProxyLookupClientImpl> proxy_lookup_client_; |
| 899 | |
Max Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 900 | // 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 Ueno | 8ce5445 | 2023-11-21 03:58:02 | [diff] [blame] | 904 | // The redirect chain resulting from prefetching |GetURL()|. |
Hiroshige Hayashizaki | 87a4393 | 2025-08-12 06:57:25 | [diff] [blame] | 905 | std::vector<std::unique_ptr<PrefetchSingleRedirectHop>> redirect_chain_; |
Max Curran | c4445fc | 2022-06-02 18:43:43 | [diff] [blame] | 906 | |
Max Curran | a84311e | 2023-05-16 20:40:25 | [diff] [blame] | 907 | // 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 Curran | 18a6f2b | 2022-05-02 23:13:24 | [diff] [blame] | 911 | |
Hiroshige Hayashizaki | 638018f | 2023-09-12 17:05:45 | [diff] [blame] | 912 | // 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 Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 920 | |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 921 | ukm::SourceId ukm_source_id_; |
| 922 | |
Taiyo Mizuhashi | 00cf58ad | 2024-11-15 02:12:13 | [diff] [blame] | 923 | // The amount of time it took for the headers to be received. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 924 | std::optional<base::TimeDelta> header_latency_; |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 925 | |
Taiyo Mizuhashi | a009caf | 2025-08-05 07:34:22 | [diff] [blame] | 926 | // 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 Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 929 | |
| 930 | // The result of probe when checked on navigation. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 931 | std::optional<PrefetchProbeResult> probe_result_; |
Max Curran | 210cffa | 2022-09-06 22:24:31 | [diff] [blame] | 932 | |
Jeremy Roman | e561b41 | 2024-02-15 18:31:34 | [diff] [blame] | 933 | // 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 Curran | 892ca542 | 2022-12-12 20:55:34 | [diff] [blame] | 938 | // Reference to metrics related to the page that considered using this |
| 939 | // prefetch. |
| 940 | base::WeakPtr<PrefetchServingPageMetricsContainer> |
| 941 | serving_page_metrics_container_; |
| 942 | |
Taiyo Mizuhashi | 9395b7c8 | 2024-05-16 20:30:26 | [diff] [blame] | 943 | // Request identifier used by DevTools and test utilities. |
Iman Saboori | 65c356d | 2022-07-15 14:47:47 | [diff] [blame] | 944 | std::string request_id_; |
| 945 | |
kenoss | 4858a80 | 2024-10-11 06:50:56 | [diff] [blame] | 946 | // 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_`. |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 967 | scoped_refptr<PreloadPipelineInfoImpl> preload_pipeline_info_; |
| 968 | std::vector<scoped_refptr<PreloadPipelineInfoImpl>> |
kenoss | 4858a80 | 2024-10-11 06:50:56 | [diff] [blame] | 969 | inherited_preload_pipeline_infos_; |
kenoss | 3bd73b8 | 2024-10-10 20:33:49 | [diff] [blame] | 970 | |
William Liu | 7708905 | 2022-12-15 18:53:35 | [diff] [blame] | 971 | // `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 Mizuhashi | 26f86c6b3 | 2024-10-02 03:58:46 | [diff] [blame] | 979 | // 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 Lin | a5f5ca7 | 2023-03-23 02:44:48 | [diff] [blame] | 985 | // A DevTools token used to identify initiator document if the prefetch is |
| 986 | // triggered by SpeculationRules. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 987 | std::optional<base::UnguessableToken> initiator_devtools_navigation_token_ = |
| 988 | std::nullopt; |
Robert Lin | a5f5ca7 | 2023-03-23 02:44:48 | [diff] [blame] | 989 | |
Max Curran | 983f21a5 | 2023-03-23 23:52:58 | [diff] [blame] | 990 | // The time at which |PrefetchService| started blocking until the head of |
| 991 | // |this| was received. |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 992 | std::optional<base::TimeTicks> blocked_until_head_start_time_; |
Max Curran | 983f21a5 | 2023-03-23 23:52:58 | [diff] [blame] | 993 | |
Max Curran | e6679ca | 2023-06-06 19:01:39 | [diff] [blame] | 994 | // 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. | 1b732247 | 2024-10-29 13:08:51 | [diff] [blame] | 998 | // 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. | b22d53b2 | 2024-11-15 11:40:06 | [diff] [blame] | 1003 | // Listener of prefetch request. Currently used for WebView initiated |
| 1004 | // prefetch. |
| 1005 | std::unique_ptr<PrefetchRequestStatusListener> request_status_listener_; |
Wayne Jackson Jr. | 03a15fa6 | 2024-09-16 14:42:15 | [diff] [blame] | 1006 | |
Hiroshige Hayashizaki | d2161a2e | 2023-10-23 16:22:50 | [diff] [blame] | 1007 | std::unique_ptr<base::OneShotTimer> timeout_timer_; |
| 1008 | |
Jeremy Roman | 586b5ec | 2024-02-13 15:14:40 | [diff] [blame] | 1009 | // 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 | |
kenoss | 6c5fb09 | 2024-07-05 05:42:14 | [diff] [blame] | 1015 | // True iff the destructor was called. |
| 1016 | bool is_in_dtor_ = false; |
| 1017 | |
kenoss | f6fbd565 | 2024-09-04 00:40:28 | [diff] [blame] | 1018 | base::ObserverList<Observer> observers_; |
| 1019 | |
kenoss | b68c9e8 | 2024-10-10 10:11:15 | [diff] [blame] | 1020 | bool is_likely_ahead_of_prerender_ = false; |
| 1021 | |
elabadysayed | f7d6b00f | 2025-02-05 11:27:00 | [diff] [blame] | 1022 | // 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()`. |
kenoss | 70bfbfe | 2025-06-10 08:04:42 | [diff] [blame] | 1025 | base::TimeDelta ttl_; |
elabadysayed | f7d6b00f | 2025-02-05 11:27:00 | [diff] [blame] | 1026 | |
elabadysayed | 90651cc | 2025-03-28 00:23:22 | [diff] [blame] | 1027 | // 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 Mizuhashi | cd08a8f | 2025-06-10 17:27:32 | [diff] [blame] | 1033 | // 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 Mizuhashi | d7c85699 | 2025-06-23 08:56:02 | [diff] [blame] | 1038 | // An optimization hint indicating how quickly this prefetch should be |
| 1039 | // available. |
| 1040 | const std::optional<PrefetchPriority> priority_ = std::nullopt; |
| 1041 | |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 1042 | // 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 Mizuhashi | 98ecb38 | 2025-06-03 15:24:55 | [diff] [blame] | 1049 | std::optional<base::TimeTicks> time_url_request_started_; |
kenoss | eab3c42 | 2025-04-03 12:50:19 | [diff] [blame] | 1050 | std::optional<base::TimeTicks> time_header_determined_successfully_; |
| 1051 | std::optional<base::TimeTicks> time_prefetch_completed_successfully_; |
| 1052 | |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 1053 | base::WeakPtrFactory<PrefetchContainer> weak_method_factory_{this}; |
| 1054 | }; |
| 1055 | |
Hiroshige Hayashizaki | 3876eee | 2023-03-27 04:42:04 | [diff] [blame] | 1056 | // For debug logs. |
| 1057 | CONTENT_EXPORT std::ostream& operator<<( |
| 1058 | std::ostream& ostream, |
| 1059 | const PrefetchContainer& prefetch_container); |
| 1060 | |
Hiroshige Hayashizaki | 4d53c80 | 2023-09-28 05:36:40 | [diff] [blame] | 1061 | CONTENT_EXPORT std::ostream& operator<<( |
| 1062 | std::ostream& ostream, |
Hiroshige Hayashizaki | f7f16b8 | 2023-10-10 01:57:47 | [diff] [blame] | 1063 | const PrefetchContainer::Key& prefetch_key); |
| 1064 | |
Kouhei Ueno | 929ee8e1 | 2024-07-05 03:09:56 | [diff] [blame] | 1065 | CONTENT_EXPORT std::ostream& operator<<(std::ostream& ostream, |
| 1066 | PrefetchContainer::LoadState state); |
| 1067 | |
Max Curran | 646fb64 | 2022-03-16 00:44:09 | [diff] [blame] | 1068 | } // namespace content |
| 1069 | |
Sreeja Kamishetty | f66553a | 2022-07-14 17:41:27 | [diff] [blame] | 1070 | #endif // CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_ |