blob: 7a02b3c3a9b666c77a8f2c5e79a7439019f719ff [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>
10
Ali Hijazi31628912023-06-05 18:13:4111#include "base/memory/raw_ref.h"
Max Curran646fb642022-03-16 00:44:0912#include "base/memory/weak_ptr.h"
Max Curranc4445fc2022-06-02 18:43:4313#include "base/time/time.h"
Max Curran210cffa2022-09-06 22:24:3114#include "content/browser/preloading/prefetch/prefetch_probe_result.h"
Sreeja Kamishettyf66553a2022-07-14 17:41:2715#include "content/browser/preloading/prefetch/prefetch_status.h"
Hiroshige Hayashizakic853c0302023-09-13 08:51:0716#include "content/browser/preloading/prefetch/prefetch_streaming_url_loader_common_types.h"
Sreeja Kamishettyf66553a2022-07-14 17:41:2717#include "content/browser/preloading/prefetch/prefetch_type.h"
Max Curran14dd7872023-03-20 19:57:3618#include "content/browser/preloading/speculation_host_devtools_observer.h"
Max Curran646fb642022-03-16 00:44:0919#include "content/common/content_export.h"
20#include "content/public/browser/global_routing_id.h"
Hiroshige Hayashizaki939c5ed42023-11-01 03:29:2121#include "content/public/browser/preloading.h"
Hiroshige Hayashizakia00e4c82023-10-31 20:20:1722#include "content/public/browser/preloading_data.h"
Liviu Tinta68a45802023-04-05 18:32:2023#include "net/http/http_no_vary_search_data.h"
Max Curran210cffa2022-09-06 22:24:3124#include "services/metrics/public/cpp/ukm_source_id.h"
Hiroshige Hayashizaki2df45292023-10-10 22:59:0325#include "third_party/blink/public/common/tokens/tokens.h"
Max Curran646fb642022-03-16 00:44:0926#include "url/gurl.h"
27
Max Curran18a6f2b2022-05-02 23:13:2428namespace network {
Max Curranc4445fc2022-06-02 18:43:4329namespace mojom {
30class CookieManager;
31} // namespace mojom
Max Curran18a6f2b2022-05-02 23:13:2432} // namespace network
33
Max Curran646fb642022-03-16 00:44:0934namespace content {
35
Jeremy Roman586b5ec2024-02-13 15:14:4036class BrowserContext;
Max Curranc4445fc2022-06-02 18:43:4337class PrefetchCookieListener;
Max Curran18a6f2b2022-05-02 23:13:2438class PrefetchDocumentManager;
39class PrefetchNetworkContext;
Hiroshige Hayashizakic853c0302023-09-13 08:51:0740class PrefetchResponseReader;
Max Curranc4445fc2022-06-02 18:43:4341class PrefetchService;
Max Curran892ca5422022-12-12 20:55:3442class PrefetchServingPageMetricsContainer;
43class PrefetchStreamingURLLoader;
William Liu77089052022-12-15 18:53:3544class PreloadingAttempt;
Max Currancc1ab0c2022-09-12 22:03:1145class ProxyLookupClientImpl;
Hiroshige Hayashizaki2cbf67b92023-10-23 17:40:0746class RenderFrameHost;
Kevin McNee06824c72024-02-06 18:59:5247class RenderFrameHostImpl;
Max Curran18a6f2b2022-05-02 23:13:2448
William Liuef934732022-11-02 22:46:2949// Holds the relevant size information of the prefetched response. The struct is
50// installed onto `PrefetchContainer`, and gets passed into
51// `PrefetchFromStringURLLoader` to notify the associated `URLLoaderClient` of
52// the actual size of the response, as `PrefetchFromStringURLLoader` is not
53// aware of the prefetched request.
54struct PrefetchResponseSizes {
55 int64_t encoded_data_length;
56 int64_t encoded_body_length;
57 int64_t decoded_body_length;
58};
59
Max Curran646fb642022-03-16 00:44:0960// This class contains the state for a request to prefetch a specific URL.
Hiroshige Hayashizaki73e42892023-06-26 16:48:4861//
62// A `PrefetchContainer` can have multiple `PrefetchContainer::SinglePrefetch`es
63// and `PrefetchStreamingURLLoader`s to support redirects. Each
64// `PrefetchContainer::SinglePrefetch` in `redirect_chain_` corresponds to a
Hiroshige Hayashizaki638018f2023-09-12 17:05:4565// single redirect hop, while a single `PrefetchStreamingURLLoader` can receive
66// multiple redirect hops unless network context switching is needed.
Hiroshige Hayashizaki73e42892023-06-26 16:48:4867//
68// For example:
69//
70// |PrefetchStreamingURLLoader A-----| |PrefetchStreamingURLLoader B ---------|
71// HandleRedirect - HandleRedirect - HandleRedirect - ReceiveResponse-Finish
72// |SinglePrefetch0| |SinglePrefetch1| |SinglePrefetch2| |SinglePrefetch3-----|
73//
74// While prefetching (see methods named like "ForCurrentPrefetch" or
75// "ToPrefetch"), `SinglePrefetch`es and `PrefetchStreamingURLLoader`s (among
76// other members) are added and filled. The steps for creating these objects and
77// associating with each other span multiple classes/methods:
78//
79// 1. A new `PrefetchContainer::SinglePrefetch` and thus a new
80// `PrefetchResponseReader` is created and added to `redirect_chain_`.
81// This is done either in:
82// - `PrefetchContainer` constructor [for an initial request], or
83// - `AddRedirectHop()` [for a redirect].
84//
85// 2. The new `PrefetchResponseReader` (created at Step 1, referenced as
86// `GetResponseReaderForCurrentPrefetch()`) is associated with the
87// `PrefetchStreamingURLLoader` to be used.
88// This is done either in (see the indirect call sites of
89// `PrefetchStreamingURLLoader::SetResponseReader()`):
90// - `PrefetchService::StartSinglePrefetch()` [initial request] or
91// - `PrefetchService::OnGotEligibilityResultForRedirect()` [redirect].
92// A new `PrefetchStreamingURLLoader` is also created if needed in
93// `PrefetchService::MakePrefetchRequest()`.
Max Curran646fb642022-03-16 00:44:0994class CONTENT_EXPORT PrefetchContainer {
95 public:
Hiroshige Hayashizakia00e4c82023-10-31 20:20:1796 // When `matcher` is null (only in unit tests),
97 // `PreloadingData::GetSameURLMatcher` is used.
Max Curran646fb642022-03-16 00:44:0998 PrefetchContainer(
Kevin McNee06824c72024-02-06 18:59:5299 RenderFrameHostImpl& referring_render_frame_host,
Hiroshige Hayashizaki2df45292023-10-10 22:59:03100 const blink::DocumentToken& referring_document_token,
Max Curran646fb642022-03-16 00:44:09101 const GURL& url,
Max Curran18a6f2b2022-05-02 23:13:24102 const PrefetchType& prefetch_type,
Kevin McNeee6ca0892022-09-28 15:36:22103 const blink::mojom::Referrer& referrer,
Arthur Sonzognic686e8f2024-01-11 08:36:37104 std::optional<net::HttpNoVarySearchData> no_vary_search_expected,
Hiroshige Hayashizakia00e4c82023-10-31 20:20:17105 base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager,
Taiyo Mizuhashi0192d3f2024-02-15 05:09:43106 base::WeakPtr<PreloadingAttempt> attempt = nullptr);
Max Curran646fb642022-03-16 00:44:09107 ~PrefetchContainer();
108
109 PrefetchContainer(const PrefetchContainer&) = delete;
110 PrefetchContainer& operator=(const PrefetchContainer&) = delete;
111
112 // Defines the key to uniquely identify a prefetch.
Kouhei Ueno34c7c69152023-11-16 04:42:42113 class CONTENT_EXPORT Key {
Kouhei Ueno45b00ef22023-11-10 02:22:58114 public:
115 Key() = delete;
Kouhei Ueno34c7c69152023-11-16 04:42:42116 Key(net::NetworkIsolationKey nik, GURL prefetch_url);
117 Key(blink::DocumentToken referring_document_token, GURL prefetch_url);
118 ~Key();
119
120 Key(const Key&);
Kouhei Ueno45b00ef22023-11-10 02:22:58121
122 bool operator==(const Key& rhs) const = default;
123 bool operator<(const Key& rhs) const {
Kouhei Ueno34c7c69152023-11-16 04:42:42124 if (referring_document_token_or_nik_ !=
125 rhs.referring_document_token_or_nik_) {
126 return referring_document_token_or_nik_ <
127 rhs.referring_document_token_or_nik_;
Kouhei Ueno45b00ef22023-11-10 02:22:58128 }
129 return prefetch_url_ < rhs.prefetch_url_;
130 }
131
Kouhei Ueno45b00ef22023-11-10 02:22:58132 const GURL& prefetch_url() const { return prefetch_url_; }
133
Kouhei Uenoebacf892023-11-14 03:41:43134 Key WithNewUrl(const GURL& new_url) const {
Kouhei Ueno34c7c69152023-11-16 04:42:42135 return Key(referring_document_token_or_nik_, new_url);
Kouhei Uenoebacf892023-11-14 03:41:43136 }
137
138 bool NonUrlPartIsSame(const Key& other) const {
Kouhei Ueno34c7c69152023-11-16 04:42:42139 return referring_document_token_or_nik_ ==
140 other.referring_document_token_or_nik_;
Kouhei Uenoebacf892023-11-14 03:41:43141 }
142
Kouhei Ueno45b00ef22023-11-10 02:22:58143 private:
Kouhei Ueno34c7c69152023-11-16 04:42:42144 Key(absl::variant<blink::DocumentToken, net::NetworkIsolationKey>
145 referring_document_token_or_nik,
146 GURL prefetch_url);
147
Kouhei Ueno45b00ef22023-11-10 02:22:58148 friend CONTENT_EXPORT std::ostream& operator<<(std::ostream& ostream,
149 const Key& prefetch_key);
150
Kouhei Ueno34c7c69152023-11-16 04:42:42151 const absl::variant<blink::DocumentToken, net::NetworkIsolationKey>
152 referring_document_token_or_nik_;
Kouhei Ueno45b00ef22023-11-10 02:22:58153 const GURL prefetch_url_;
154 };
155
Kouhei Ueno8ce54452023-11-21 03:58:02156 const Key& GetPrefetchContainerKey() const { return key_; }
Max Curran646fb642022-03-16 00:44:09157
Rakina Zata Amni39d8e7e2022-10-20 18:18:30158 // The ID of the RenderFrameHost that triggered the prefetch.
Max Curran646fb642022-03-16 00:44:09159 GlobalRenderFrameHostId GetReferringRenderFrameHostId() const {
160 return referring_render_frame_host_id_;
161 }
Kevin McNee06824c72024-02-06 18:59:52162 bool HasSameReferringURLForMetrics(const PrefetchContainer& other) const;
Max Curran646fb642022-03-16 00:44:09163
Max Curran5d4da4b42023-03-10 23:41:46164 // The initial URL that was requested to be prefetched.
Kouhei Ueno8ce54452023-11-21 03:58:02165 const GURL& GetURL() const { return key_.prefetch_url(); }
Max Curran646fb642022-03-16 00:44:09166
Jeremy Roman45c89d012023-08-30 21:22:02167 // The current URL being fetched.
168 GURL GetCurrentURL() const;
169
170 // The previous URL, if this has been redirected. Invalid to call otherwise.
171 GURL GetPreviousURL() const;
172
Max Curran646fb642022-03-16 00:44:09173 // The type of this prefetch. Controls how the prefetch is handled.
174 const PrefetchType& GetPrefetchType() const { return prefetch_type_; }
175
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:58176 // Whether or not an isolated network context is required to the next
177 // prefetch.
178 bool IsIsolatedNetworkContextRequiredForCurrentPrefetch() const;
Max Curran48700962023-05-15 18:35:52179
180 // Whether or not an isolated network context is required for the previous
181 // redirect hop of the given url.
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:58182 bool IsIsolatedNetworkContextRequiredForPreviousRedirectHop() const;
183
Hiroshige Hayashizaki73e42892023-06-26 16:48:48184 base::WeakPtr<PrefetchResponseReader> GetResponseReaderForCurrentPrefetch();
185
Max Curranc0137502023-05-02 18:06:22186 // Whether or not the prefetch proxy would be required to fetch the given url
187 // based on |prefetch_type_|.
188 bool IsProxyRequiredForURL(const GURL& url) const;
189
Jeremy Roman45c89d012023-08-30 21:22:02190 const network::ResourceRequest* GetResourceRequest() const {
191 return resource_request_.get();
192 }
193 void MakeResourceRequest(const net::HttpRequestHeaders& additional_headers);
194
Devlin Cronin7f318c12023-06-09 00:57:01195 // Updates |referrer_| after a redirect.
196 void UpdateReferrer(
197 const GURL& new_referrer_url,
198 const network::mojom::ReferrerPolicy& new_referrer_policy);
199
Arthur Sonzognic686e8f2024-01-11 08:36:37200 const std::optional<net::HttpNoVarySearchData>& GetNoVarySearchHint() const {
Liviu Tinta953bde882023-05-05 13:21:35201 return no_vary_search_hint_;
Liviu Tinta68a45802023-04-05 18:32:20202 }
203
Alan Cutter5525a852022-10-07 03:53:31204 base::WeakPtr<PrefetchContainer> GetWeakPtr() {
Max Curran646fb642022-03-16 00:44:09205 return weak_method_factory_.GetWeakPtr();
206 }
207
Max Curran146bf442022-03-28 23:22:14208 // The status of the current prefetch. Note that |HasPrefetchStatus| will be
William Liu77089052022-12-15 18:53:35209 // initially false until |SetPrefetchStatus| is called. |SetPrefetchStatus|
210 // also sets |attempt_| PreloadingHoldbackStatus, PreloadingTriggeringOutcome
211 // and PreloadingFailureReason. It is only safe to call after
212 // `OnEligibilityCheckComplete`.
213 void SetPrefetchStatus(PrefetchStatus prefetch_status);
Max Curran146bf442022-03-28 23:22:14214 bool HasPrefetchStatus() const { return prefetch_status_.has_value(); }
215 PrefetchStatus GetPrefetchStatus() const;
216
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58217 // The state enum of the current prefetch, to replace `PrefetchStatus`.
218 // https://crbug.com/1494771
219 // Design doc for PrefetchContainer state transitions:
220 // https://docs.google.com/document/d/1dK4mAVoRrgTVTGdewthI_hA8AHirgXW8k6BmpK9gnBE/edit?usp=sharing
221 enum class LoadState {
222 // --- Phase 1. [Initial state]
223 kNotStarted,
224
225 // --- Phase 2. The eligibility check for the initial request has completed
226 // and `PreloadingAttempt::SetEligibility()` has been called.
227
228 // Found eligible.
229 kEligible,
230
231 // [Final state] Found ineligible. `redirect_chain_[0].eligibility_`
232 // contains the reason for being ineligible.
233 kFailedIneligible,
234
235 // --- Phase 3. PrefetchService::StartSinglePrefetch() has been called and
236 // the holdback check has completed.
237
238 // [Final state] Not heldback.
239 //
240 // On this state, refer to `PrefetchResponseReader`s for detailed
241 // prefetching state and servability.
242 //
243 // Also, refer to `attempt_` for triggering outcome and failure reasons for
244 // metrics.
245 // `PreloadingAttempt::SetFailureReason()` can be only called on this state.
246 // Note that these states of `attempt_` don't directly affect
247 // `PrefetchResponseReader`'s servability.
248 // (e.g. `PrefetchResponseReader::GetServableState()` can be still
249 // `kServable` even if `attempt_` has a failure).
250 kStarted,
251
252 // [Final state] Heldback due to `PreloadingAttempt::ShouldHoldback()`.
253 kFailedHeldback,
254 };
255 void SetLoadState(LoadState prefetch_status);
256 LoadState GetLoadState() const;
257
Max Currancc1ab0c2022-09-12 22:03:11258 // Controls ownership of the |ProxyLookupClientImpl| used during the
259 // eligibility check.
260 void TakeProxyLookupClient(
261 std::unique_ptr<ProxyLookupClientImpl> proxy_lookup_client);
262 std::unique_ptr<ProxyLookupClientImpl> ReleaseProxyLookupClient();
263
William Liu77089052022-12-15 18:53:35264 // Whether or not the prefetch was determined to be eligibile.
Hiroshige Hayashizaki939c5ed42023-11-01 03:29:21265 void OnEligibilityCheckComplete(PreloadingEligibility eligibility);
Max Curran5d4da4b42023-03-10 23:41:46266 bool IsInitialPrefetchEligible() const;
267
268 // Adds a the new URL to |redirect_chain_|.
Jeremy Roman45c89d012023-08-30 21:22:02269 void AddRedirectHop(const net::RedirectInfo& redirect_info);
Max Curran5d4da4b42023-03-10 23:41:46270
Max Curran5d4da4b42023-03-10 23:41:46271 // The length of the redirect chain for this prefetch.
272 size_t GetRedirectChainSize() const { return redirect_chain_.size(); }
Max Curran210cffa2022-09-06 22:24:31273
Max Curran18a6f2b2022-05-02 23:13:24274 // Whether this prefetch is a decoy. Decoy prefetches will not store the
275 // response, and not serve any prefetched resources.
276 void SetIsDecoy(bool is_decoy) { is_decoy_ = is_decoy; }
277 bool IsDecoy() const { return is_decoy_; }
278
Hiroshige Hayashizakieec97ed12023-05-26 06:38:32279 // Allows for |PrefetchCookieListener|s to be reigsitered for
280 // `GetCurrentSinglePrefetchToPrefetch()`.
281 void RegisterCookieListener(network::mojom::CookieManager* cookie_manager);
Max Curran7dbdea4d2023-03-21 23:47:37282 void StopAllCookieListeners();
Max Curranc4445fc2022-06-02 18:43:43283
Hiroshige Hayashizakib8c4bf602023-05-26 01:34:58284 // The network context used to make network requests for the next prefetch.
Kouhei Ueno4442db92023-11-13 06:38:13285 PrefetchNetworkContext* GetOrCreateNetworkContextForCurrentPrefetch();
Max Curran18a6f2b2022-05-02 23:13:24286
Max Currana84311e2023-05-16 20:40:25287 // Closes idle connections for all elements in |network_contexts_|.
288 void CloseIdleConnections();
289
Hiroshige Hayashizaki638018f2023-09-12 17:05:45290 // Set the currently prefetching |PrefetchStreamingURLLoader|.
291 void SetStreamingURLLoader(
292 base::WeakPtr<PrefetchStreamingURLLoader> streaming_loader);
Max Currana84311e2023-05-16 20:40:25293
Hiroshige Hayashizaki638018f2023-09-12 17:05:45294 // Returns the URL loader being used for prefetching the current redirect hop.
Hiroshige Hayashizaki334d0fa2023-08-16 23:33:27295 // This method should be used during prefetching and shouldn't be called for
296 // serving purpose.
Hiroshige Hayashizaki638018f2023-09-12 17:05:45297 const base::WeakPtr<PrefetchStreamingURLLoader>& GetStreamingURLLoader()
298 const;
Max Currana84311e2023-05-16 20:40:25299
Hiroshige Hayashizaki5c50ec52023-09-13 00:35:49300 bool IsStreamingURLLoaderDeletionScheduledForTesting() const;
301
Hiroshige Hayashizaki334d0fa2023-08-16 23:33:27302 // Returns the PrefetchResponseReader corresponding to the last non-redirect
303 // response, if already received its head, or otherwise nullptr.
304 const PrefetchResponseReader* GetNonRedirectResponseReader() const;
305
Hiroshige Hayashizaki638018f2023-09-12 17:05:45306 // Clears |streaming_loader_| and cancels its loading, if any of its
307 // corresponding `PrefetchResponseReader` does NOT start serving. Currently
308 // this itself doesn't mark `this` as failed and thus can leave `this`
309 // stalled. Therefore, call this method only if `this` can be no longer used
310 // for serving, e.g. on the destructor or when
311 // `HaveDefaultContextCookiesChanged()` is true.
312 // TODO(crbug.com/1449360): For callsites outside the destructor, remove the
313 // call or mark `this` as failed, because the current behavior (== existing
314 // behavior, previously as `ResetAllStreamingURLLoaders()`) might potentially
315 // cause issues when there are multiple navigations using `this` concurrently.
316 void CancelStreamingURLLoaderIfNotServing();
Max Curran892ca5422022-12-12 20:55:34317
Max Curran18a6f2b2022-05-02 23:13:24318 // The |PrefetchDocumentManager| that requested |this|.
319 PrefetchDocumentManager* GetPrefetchDocumentManager() const;
320
Max Curran983f21a52023-03-23 23:52:58321 // Called when |PrefetchService::GetPrefetchToServe| and
322 // |PrefetchService::ReturnPrefetchToServe| with |this|.
323 void OnGetPrefetchToServe(bool blocked_until_head);
324 void OnReturnPrefetchToServe(bool served);
Max Curran210cffa2022-09-06 22:24:31325
Max Currane0444942022-09-06 23:55:23326 // Returns whether or not this prefetch has been considered to serve for a
327 // navigation in the past. If it has, then it shouldn't be used for any future
328 // navigations.
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:43329 bool HasPrefetchBeenConsideredToServe() const;
Max Currane0444942022-09-06 23:55:23330
Max Curran210cffa2022-09-06 22:24:31331 // Called when |PrefetchService::OnPrefetchComplete| is called for the
332 // prefetch. This happens when |loader_| fully downloads the requested
333 // resource.
Hiroshige Hayashizaki77083bc82023-11-28 06:04:17334 void OnPrefetchComplete(
335 const network::URLLoaderCompletionStatus& completion_status);
Max Curran210cffa2022-09-06 22:24:31336
Max Currane6679ca2023-06-06 19:01:39337 // Allows for a timer to be used to limit the maximum amount of time that a
338 // navigation can be blocked waiting for the head of this prefetch to be
339 // received.
340 void TakeBlockUntilHeadTimer(
341 std::unique_ptr<base::OneShotTimer> block_until_head_timer);
342 void ResetBlockUntilHeadTimer();
343
Hiroshige Hayashizakie556eb02023-09-13 00:20:48344 enum class ServableState {
345 // Not servable nor should block until head received.
346 kNotServable,
347
348 // Servable.
349 kServable,
350
351 // |PrefetchService| should block until the head of |this| is
352 // received on a navigation to a matching URL.
353 kShouldBlockUntilHeadReceived,
354 };
Hiroshige Hayashizaki8f74d22b2023-09-28 04:48:08355
356 // Note: Even if this returns `kServable`, `CreateRequestHandler()` can still
357 // fail (returning null handler) due to final checks. See also the comment for
358 // `PrefetchResponseReader::CreateRequestHandler()`.
Hiroshige Hayashizakie556eb02023-09-13 00:20:48359 ServableState GetServableState(base::TimeDelta cacheable_duration) const;
Max Curran6b93426f2022-05-03 00:55:52360
Hiroshige Hayashizakib5879de2023-07-14 20:22:13361 // Called once it is determined whether or not the prefetch is servable, i.e.
362 // either when non-redirect response head is received, or when determined not
363 // servable.
364 void OnReceivedHead();
365 void SetOnReceivedHeadCallback(base::OnceClosure on_received_head_callback);
366 base::OnceClosure ReleaseOnReceivedHeadCallback();
Liviu Tintad97a6a32022-12-08 23:28:40367
Hiroshige Hayashizakid2161a2e2023-10-23 16:22:50368 void StartTimeoutTimer(base::TimeDelta timeout,
369 base::OnceClosure on_timeout_callback);
370
Liviu Tintad97a6a32022-12-08 23:28:40371 // Returns the head of the prefetched response. If there is no valid response,
372 // then returns null.
373 const network::mojom::URLResponseHead* GetHead();
374
Max Curran210cffa2022-09-06 22:24:31375 // Returns the time between the prefetch request was sent and the time the
376 // response headers were received. Not set if the prefetch request hasn't been
377 // sent or the response headers haven't arrived.
Arthur Sonzognic686e8f2024-01-11 08:36:37378 std::optional<base::TimeDelta> GetPrefetchHeaderLatency() const {
Max Curran210cffa2022-09-06 22:24:31379 return header_latency_;
380 }
381
Max Curran892ca5422022-12-12 20:55:34382 // Allow for the serving page to metrics when changes to the prefetch occur.
383 void SetServingPageMetrics(base::WeakPtr<PrefetchServingPageMetricsContainer>
384 serving_page_metrics_container);
385 void UpdateServingPageMetrics();
386
Iman Saboori65c356d2022-07-15 14:47:47387 // Returns request id to be used by DevTools
388 const std::string& RequestId() const { return request_id_; }
389
390 // Sets DevTools observer
391 void SetDevToolsObserver(
Johanna9fe85f2023-01-17 10:15:43392 base::WeakPtr<SpeculationHostDevToolsObserver> devtools_observer) {
Iman Saboori65c356d2022-07-15 14:47:47393 devtools_observer_ = std::move(devtools_observer);
394 }
395
396 // Returns DevTool observer
397 const base::WeakPtr<SpeculationHostDevToolsObserver>& GetDevToolsObserver()
398 const {
399 return devtools_observer_;
400 }
401
Arthur Sonzognic686e8f2024-01-11 08:36:37402 const std::optional<PrefetchResponseSizes>& GetPrefetchResponseSizes() const {
William Liuef934732022-11-02 22:46:29403 return prefetch_response_sizes_;
404 }
405
William Liu77089052022-12-15 18:53:35406 bool HasPreloadingAttempt() { return !!attempt_; }
Simon Pelchat9ed3e992023-02-17 01:16:16407 base::WeakPtr<PreloadingAttempt> preloading_attempt() { return attempt_; }
William Liu77089052022-12-15 18:53:35408
409 // Simulates a prefetch container that reaches the interceptor. It sets the
410 // `attempt_` to the correct state: `PreloadingEligibility::kEligible`,
411 // `PreloadingHoldbackStatus::kAllowed` and
412 // `PreloadingTriggeringOutcome::kReady`.
413 void SimulateAttemptAtInterceptorForTest();
414 void DisablePrecogLoggingForTest() { attempt_ = nullptr; }
415
Arthur Sonzognic686e8f2024-01-11 08:36:37416 const std::optional<net::HttpNoVarySearchData>& GetNoVarySearchData() const {
Hiroshige Hayashizaki47a83632023-06-16 18:09:22417 return no_vary_search_data_;
418 }
Hiroshige Hayashizaki2cbf67b92023-10-23 17:40:07419 // Sets `no_vary_search_data_` from `GetHead()`. Exposed for tests.
420 void SetNoVarySearchData(RenderFrameHost* rfh);
Hiroshige Hayashizaki47a83632023-06-16 18:09:22421
Hiroshige Hayashizakia51f624be2023-10-24 16:29:57422 // Called when cookies changes are detected via
423 // `HaveDefaultContextCookiesChanged()`, either for `this` or other
424 // `PrefetchContainer`s under the same `PrefetchMatchResolver`.
425 void OnCookiesChanged();
426
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37427 class SinglePrefetch;
428
429 // A `Reader` represents the current state of serving.
430 // The `Reader` methods all operate on the currently *serving*
431 // `SinglePrefetch`, which is the element in |redirect_chain_| at index
432 // |index_redirect_chain_to_serve_|.
433 //
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48434 // This works like `base::WeakPtr<PrefetchContainer>` plus additional states,
435 // so check that the reader is valid (e.g. `if (reader)`) before calling other
436 // methods (except for `Clone()`).
437 //
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37438 // TODO(crbug.com/1449360): Allow multiple Readers for a PrefetchContainer.
439 // This might need ownership/lifetime changes of `Reader` and further cleaning
440 // up the dependencies between `PrefetchContainer` and `Reader`.
441 class CONTENT_EXPORT Reader final {
442 public:
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48443 Reader();
444
445 Reader(base::WeakPtr<PrefetchContainer> prefetch_container,
446 size_t index_redirect_chain_to_serve);
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37447
448 Reader(const Reader&) = delete;
449 Reader& operator=(const Reader&) = delete;
450
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48451 Reader(Reader&&);
452 Reader& operator=(Reader&&);
453
454 ~Reader();
455
456 PrefetchContainer* GetPrefetchContainer() const {
457 return prefetch_container_.get();
458 }
459 Reader Clone() const;
460
461 // Returns true if `this` is valid.
462 // Do not call methods below if false.
463 explicit operator bool() const { return GetPrefetchContainer(); }
464
465 // Methods redirecting to `prefetch_container_`.
Hiroshige Hayashizakie556eb02023-09-13 00:20:48466 PrefetchContainer::ServableState GetServableState(
467 base::TimeDelta cacheable_duration) const;
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48468 bool HasPrefetchStatus() const;
469 PrefetchStatus GetPrefetchStatus() const;
470
471 // Returns whether the Reader reached the end. If true, the methods below
Hiroshige Hayashizaki73e42892023-06-26 16:48:48472 // shouldn't be called, because the current `SinglePrefetch` doesn't exist.
473 bool IsEnd() const;
474
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37475 // Whether or not an isolated network context is required to serve.
476 bool IsIsolatedNetworkContextRequiredToServe() const;
477
478 PrefetchNetworkContext* GetCurrentNetworkContextToServe() const;
479
480 bool HaveDefaultContextCookiesChanged() const;
481
482 // Before a prefetch can be served, any cookies added to the isolated
483 // network context must be copied over to the default network context. These
484 // functions are used to check and update the status of this process, as
485 // well as record metrics about how long this process takes.
486 bool HasIsolatedCookieCopyStarted() const;
487 bool IsIsolatedCookieCopyInProgress() const;
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48488 void OnIsolatedCookieCopyStart() const;
489 void OnIsolatedCookiesReadCompleteAndWriteStart() const;
490 void OnIsolatedCookieCopyComplete() const;
491 void OnInterceptorCheckCookieCopy() const;
492 void SetOnCookieCopyCompleteCallback(base::OnceClosure callback) const;
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37493
494 // Called with the result of the probe. If the probing feature is enabled,
495 // then a probe must complete successfully before the prefetch can be
496 // served.
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48497 void OnPrefetchProbeResult(PrefetchProbeResult probe_result) const;
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37498
499 // Checks if the given URL matches the the URL that can be served next.
500 bool DoesCurrentURLToServeMatch(const GURL& url) const;
501
502 // Returns the URL that can be served next.
503 const GURL& GetCurrentURLToServe() const;
504
Hiroshige Hayashizaki3b7e8e062023-08-14 21:47:39505 // Gets the current PrefetchResponseReader.
506 base::WeakPtr<PrefetchResponseReader>
507 GetCurrentResponseReaderToServeForTesting();
Hiroshige Hayashizaki73e42892023-06-26 16:48:48508
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37509 // Called when one element of |redirect_chain_| is served and the next
510 // element can now be served.
511 void AdvanceCurrentURLToServe() { index_redirect_chain_to_serve_++; }
512
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37513 // Returns the `SinglePrefetch` to be served next.
514 const SinglePrefetch& GetCurrentSinglePrefetchToServe() const;
515
Hiroshige Hayashizaki8f74d22b2023-09-28 04:48:08516 // See the comment for `PrefetchResponseReader::CreateRequestHandler()`.
Hiroshige Hayashizakic853c0302023-09-13 08:51:07517 PrefetchRequestHandler CreateRequestHandler();
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48518
Hiroshige Hayashizaki73e42892023-06-26 16:48:48519 private:
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48520 base::WeakPtr<PrefetchContainer> prefetch_container_;
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37521
522 // The index of the element in |prefetch_container_.redirect_chain_| that
523 // can be served.
524 size_t index_redirect_chain_to_serve_ = 0;
525 };
526
Hiroshige Hayashizaki00b3f002023-07-15 00:32:48527 Reader CreateReader();
Hiroshige Hayashizaki6a99ee92023-05-30 19:54:37528
Max Curran210cffa2022-09-06 22:24:31529 protected:
Hiroshige Hayashizakic0b6aea2023-10-17 21:56:43530 friend class PrefetchContainerTestBase;
Max Curran210cffa2022-09-06 22:24:31531
532 // Updates metrics based on the result of the prefetch request.
533 void UpdatePrefetchRequestMetrics(
Arthur Sonzognic686e8f2024-01-11 08:36:37534 const std::optional<network::URLLoaderCompletionStatus>&
Max Curran210cffa2022-09-06 22:24:31535 completion_status,
536 const network::mojom::URLResponseHead* head);
537
Max Curran646fb642022-03-16 00:44:09538 private:
Robert Lin92f3617e2023-05-20 10:14:49539 // Update |prefetch_status_| and report prefetch status to
540 // DevTools without updating TriggeringOutcome.
541 void SetPrefetchStatusWithoutUpdatingTriggeringOutcome(
542 PrefetchStatus prefetch_status);
543
Jeremy Roman586b5ec2024-02-13 15:14:40544 // Add client hints headers to a request bound for |origin|.
545 void AddClientHintsHeaders(const url::Origin& origin,
546 net::HttpRequestHeaders* request_headers);
547
Hiroshige Hayashizaki8ce7d8d2023-05-26 00:16:32548 // Returns the `SinglePrefetch` to be prefetched next. This is the last
549 // element in `redirect_chain_`, because, during prefetching from the network,
550 // we push back `SinglePrefetch`s to `redirect_chain_` and access the latest
551 // redirect hop.
552 SinglePrefetch& GetCurrentSinglePrefetchToPrefetch() const;
553
554 // Returns the `SinglePrefetch` for the redirect leg before
555 // `GetCurrentSinglePrefetchToPrefetch()`. This must be called only if `this`
556 // has redirect(s).
557 const SinglePrefetch& GetPreviousSinglePrefetchToPrefetch() const;
558
Hiroshige Hayashizaki2df45292023-10-10 22:59:03559 // The ID of the RenderFrameHost/Document that triggered the prefetch.
560 const GlobalRenderFrameHostId referring_render_frame_host_id_;
Kevin McNee06824c72024-02-06 18:59:52561 // The origin of the page that requested the prefetch.
562 const url::Origin referring_origin_;
563 // The URL of the page that requested the prefetch, stored as a hash as we
564 // just need it for equality checks for metrics.
565 const size_t referring_url_hash_;
Max Curran646fb642022-03-16 00:44:09566
Kouhei Ueno8ce54452023-11-21 03:58:02567 // The key used to match this PrefetchContainer, including the URL that was
568 // requested to prefetch.
569 const PrefetchContainer::Key key_;
Max Curran646fb642022-03-16 00:44:09570
571 // The type of this prefetch. This controls some specific details about how
572 // the prefetch is handled, including whether an isolated network context or
573 // the default network context is used to perform the prefetch, whether or
574 // not the preftch proxy is used, and whether or not subresources are
575 // prefetched.
576 PrefetchType prefetch_type_;
577
Kevin McNeee6ca0892022-09-28 15:36:22578 // The referrer to use for the request.
Devlin Cronin7f318c12023-06-09 00:57:01579 blink::mojom::Referrer referrer_;
Kevin McNeee6ca0892022-09-28 15:36:22580
Jeremy Roman45c89d012023-08-30 21:22:02581 // Information about the current prefetch request. Updated when a redirect is
582 // encountered, whether or not the direct can be processed by the same URL
583 // loader or requires the instantiation of a new loader.
584 std::unique_ptr<network::ResourceRequest> resource_request_;
585
Hiroshige Hayashizaki47a83632023-06-16 18:09:22586 // The No-Vary-Search response data, parsed from the actual response header
587 // (`GetHead()`).
Hiroshige Hayashizaki2cbf67b92023-10-23 17:40:07588 // Unless this is set, `no_vary_search` helpers don't perform No-Vary-Search
589 // matching for `this`, even if `GetHead()` has No-Vary-Search headers.
Arthur Sonzognic686e8f2024-01-11 08:36:37590 std::optional<net::HttpNoVarySearchData> no_vary_search_data_;
Hiroshige Hayashizaki47a83632023-06-16 18:09:22591
592 // The No-Vary-Search hint of the prefetch, which is specified by the
593 // speculation rules and can be different from actual `no_vary_search_data_`.
Arthur Sonzognic686e8f2024-01-11 08:36:37594 const std::optional<net::HttpNoVarySearchData> no_vary_search_hint_;
Liviu Tinta68a45802023-04-05 18:32:20595
Taiyo Mizuhashifc6afd6c2024-01-26 06:53:07596 // The |PrefetchDocumentManager| that requested |this|.
Max Curran18a6f2b2022-05-02 23:13:24597 base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager_;
598
Jeremy Roman586b5ec2024-02-13 15:14:40599 // The |BrowserContext| in which this is being run.
600 base::WeakPtr<BrowserContext> browser_context_;
601
Max Curran146bf442022-03-28 23:22:14602 // The current status, if any, of the prefetch.
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58603 // TODO(crbug.com/1494771): Use `load_state_` instead for non-metrics purpose.
Arthur Sonzognic686e8f2024-01-11 08:36:37604 std::optional<PrefetchStatus> prefetch_status_;
Max Curran146bf442022-03-28 23:22:14605
Hiroshige Hayashizaki4ce0f4292023-11-07 19:24:58606 // The current status of the prefetch.
607 LoadState load_state_ = LoadState::kNotStarted;
608
Max Curran5d4da4b42023-03-10 23:41:46609 // Looks up the proxy settings in the default network context all URLs in
610 // |redirect_chain_|.
Max Currancc1ab0c2022-09-12 22:03:11611 std::unique_ptr<ProxyLookupClientImpl> proxy_lookup_client_;
612
Max Curran18a6f2b2022-05-02 23:13:24613 // Whether this prefetch is a decoy or not. If the prefetch is a decoy then
614 // any prefetched resources will not be served.
615 bool is_decoy_ = false;
616
Kouhei Ueno8ce54452023-11-21 03:58:02617 // The redirect chain resulting from prefetching |GetURL()|.
Max Curran5d4da4b42023-03-10 23:41:46618 std::vector<std::unique_ptr<SinglePrefetch>> redirect_chain_;
Max Curranc4445fc2022-06-02 18:43:43619
Max Currana84311e2023-05-16 20:40:25620 // The network contexts used for this prefetch. They key corresponds to the
621 // |is_isolated_network_context_required| param of the
622 // |PrefetchNetworkContext|.
623 std::map<bool, std::unique_ptr<PrefetchNetworkContext>> network_contexts_;
Max Curran18a6f2b2022-05-02 23:13:24624
Hiroshige Hayashizaki638018f2023-09-12 17:05:45625 // The currently prefetching streaming URL loader, prefetching the last
626 // element of `redirect_chain_`. Multiple streaming URL loaders can be used in
627 // the event a redirect causes a change in the network context, but here only
628 // one (=last) `PrefetchStreamingURLLoader` is kept here, because when
629 // switching the network context and `PrefetchStreamingURLLoader`s, the old
630 // `PrefetchStreamingURLLoader` is scheduled for deletion and then the new
631 // `PrefetchStreamingURLLoader` is set here.
632 base::WeakPtr<PrefetchStreamingURLLoader> streaming_loader_;
Max Curran892ca5422022-12-12 20:55:34633
Max Curranc4445fc2022-06-02 18:43:43634 // The time at which |prefetched_response_| was received. This is used to
635 // determine whether or not |prefetched_response_| is stale.
Arthur Sonzognic686e8f2024-01-11 08:36:37636 std::optional<base::TimeTicks> prefetch_received_time_;
Max Curranc4445fc2022-06-02 18:43:43637
Max Curran210cffa2022-09-06 22:24:31638 ukm::SourceId ukm_source_id_;
639
William Liuef934732022-11-02 22:46:29640 // The sizes information of the prefetched response.
Arthur Sonzognic686e8f2024-01-11 08:36:37641 std::optional<PrefetchResponseSizes> prefetch_response_sizes_;
Max Curran210cffa2022-09-06 22:24:31642
643 // The amount of time it took for the prefetch to complete.
Arthur Sonzognic686e8f2024-01-11 08:36:37644 std::optional<base::TimeDelta> fetch_duration_;
Max Curran210cffa2022-09-06 22:24:31645
646 // The amount of time it took for the headers to be received.
Arthur Sonzognic686e8f2024-01-11 08:36:37647 std::optional<base::TimeDelta> header_latency_;
Max Curran210cffa2022-09-06 22:24:31648
649 // Whether or not a navigation to this prefetch occurred.
650 bool navigated_to_ = false;
651
652 // The result of probe when checked on navigation.
Arthur Sonzognic686e8f2024-01-11 08:36:37653 std::optional<PrefetchProbeResult> probe_result_;
Max Curran210cffa2022-09-06 22:24:31654
Max Curran892ca5422022-12-12 20:55:34655 // Reference to metrics related to the page that considered using this
656 // prefetch.
657 base::WeakPtr<PrefetchServingPageMetricsContainer>
658 serving_page_metrics_container_;
659
Iman Saboori65c356d2022-07-15 14:47:47660 // Request identifier used by DevTools
661 std::string request_id_;
662
663 // Weak pointer to DevTools observer
664 base::WeakPtr<SpeculationHostDevToolsObserver> devtools_observer_;
665
William Liu77089052022-12-15 18:53:35666 // `PreloadingAttempt` is used to track the lifecycle of the preloading event,
667 // and reports various statuses to UKM dashboard. It is initialised along with
668 // `this`, and destroyed when `WCO::DidFinishNavigation` is fired.
669 // `attempt_`'s eligibility is set in `OnEligibilityCheckComplete`, and its
670 // holdback status, triggering outcome and failure reason are set in
671 // `SetPrefetchStatus`.
672 base::WeakPtr<PreloadingAttempt> attempt_;
673
Robert Lina5f5ca72023-03-23 02:44:48674 // A DevTools token used to identify initiator document if the prefetch is
675 // triggered by SpeculationRules.
Arthur Sonzognic686e8f2024-01-11 08:36:37676 std::optional<base::UnguessableToken> initiator_devtools_navigation_token_ =
677 std::nullopt;
Robert Lina5f5ca72023-03-23 02:44:48678
Max Curran983f21a52023-03-23 23:52:58679 // The time at which |PrefetchService| started blocking until the head of
680 // |this| was received.
Arthur Sonzognic686e8f2024-01-11 08:36:37681 std::optional<base::TimeTicks> blocked_until_head_start_time_;
Max Curran983f21a52023-03-23 23:52:58682
Max Currane6679ca2023-06-06 19:01:39683 // A timer used to limit the maximum amount of time that a navigation can be
684 // blocked waiting for the head of this prefetch to be received.
685 std::unique_ptr<base::OneShotTimer> block_until_head_timer_;
686
Hiroshige Hayashizakib5879de2023-07-14 20:22:13687 // Called when `OnReceivedHead()` is called.
688 base::OnceClosure on_received_head_callback_;
689
Hiroshige Hayashizakid2161a2e2023-10-23 16:22:50690 std::unique_ptr<base::OneShotTimer> timeout_timer_;
691
Jeremy Roman586b5ec2024-02-13 15:14:40692 // Whether JavaScript is on in this contents (or was, when this prefetch
693 // started). This affects Client Hints behavior. Per-origin settings are
694 // handled later, according to
695 // |ClientHintsControllerDelegate::IsJavaScriptAllowed|.
696 bool is_javascript_enabled_ = false;
697
Max Curran646fb642022-03-16 00:44:09698 base::WeakPtrFactory<PrefetchContainer> weak_method_factory_{this};
699};
700
Hiroshige Hayashizaki3876eee2023-03-27 04:42:04701// For debug logs.
702CONTENT_EXPORT std::ostream& operator<<(
703 std::ostream& ostream,
704 const PrefetchContainer& prefetch_container);
705
Hiroshige Hayashizaki4d53c802023-09-28 05:36:40706CONTENT_EXPORT std::ostream& operator<<(
707 std::ostream& ostream,
Hiroshige Hayashizakif7f16b82023-10-10 01:57:47708 const PrefetchContainer::Key& prefetch_key);
709
710CONTENT_EXPORT std::ostream& operator<<(
711 std::ostream& ostream,
Hiroshige Hayashizaki4d53c802023-09-28 05:36:40712 PrefetchContainer::ServableState servable_state);
713
Max Curran646fb642022-03-16 00:44:09714} // namespace content
715
Sreeja Kamishettyf66553a2022-07-14 17:41:27716#endif // CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_CONTAINER_H_