blob: 46f834b75f55af6b217f2a1949fe333c8ef2f50c [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_REQUEST_H_
#define CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_REQUEST_H_
#include <optional>
#include <variant>
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/browser/preloading/prefetch/prefetch_key.h"
#include "content/browser/preloading/prefetch/prefetch_type.h"
#include "content/browser/preloading/speculation_rules/speculation_rules_tags.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_routing_id.h"
#include "net/http/http_no_vary_search_data.h"
#include "net/http/http_request_headers.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/mojom/loader/referrer.mojom.h"
#include "url/origin.h"
namespace content {
class BrowserContext;
class PrefetchDocumentManager;
class PrefetchRequestStatusListener;
class PreloadPipelineInfo;
class PreloadPipelineInfoImpl;
class PreloadingAttempt;
class RenderFrameHostImpl;
enum class PrefetchPriority;
enum class PreloadingHoldbackStatus;
// `PrefetchRendererInitiatorInfo` or `PrefetchBrowserInitiatorInfo` is created
// and attached to `PrefetchRequest` for a renderer-initiated or
// browser-initiated prefetch, respectively.
//
// They represents the initiator information and other request parameters
// specific to renderer-initiated or browser-initiated prefetches.
// For renderer-initiated prefetches: the initiator Document and its
// `RenderFrameHost`, `PrefetchDocumentManager`, etc.
class CONTENT_EXPORT PrefetchRendererInitiatorInfo final {
public:
PrefetchRendererInitiatorInfo(
RenderFrameHostImpl& render_frame_host,
base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager);
~PrefetchRendererInitiatorInfo();
// Move-only.
PrefetchRendererInitiatorInfo(const PrefetchRendererInitiatorInfo&) = delete;
PrefetchRendererInitiatorInfo& operator=(
const PrefetchRendererInitiatorInfo&) = delete;
PrefetchRendererInitiatorInfo(PrefetchRendererInitiatorInfo&&);
GlobalRenderFrameHostId GetRenderFrameHostId() const {
return render_frame_host_id_;
}
RenderFrameHostImpl* GetRenderFrameHost() const;
PrefetchDocumentManager* prefetch_document_manager() const {
return prefetch_document_manager_.get();
}
const std::optional<base::UnguessableToken>& devtools_navigation_token()
const {
return devtools_navigation_token_;
}
ukm::SourceId ukm_source_id() const { return ukm_source_id_; }
size_t url_hash() const { return url_hash_; }
private:
// The RenderFrameHostId/PrefetchDocumentManager of the Document that
// triggered the prefetch.
GlobalRenderFrameHostId render_frame_host_id_;
base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager_;
// A DevTools token used to identify initiator document.
std::optional<base::UnguessableToken> devtools_navigation_token_;
ukm::SourceId ukm_source_id_;
// Used by metrics for equality checks.
size_t url_hash_;
};
// For browser-initiated prefetches.
class CONTENT_EXPORT PrefetchBrowserInitiatorInfo final {
public:
PrefetchBrowserInitiatorInfo(
const std::string& embedder_histogram_suffix,
std::unique_ptr<PrefetchRequestStatusListener> request_status_listener);
~PrefetchBrowserInitiatorInfo();
// Move-only.
PrefetchBrowserInitiatorInfo(const PrefetchBrowserInitiatorInfo&) = delete;
PrefetchBrowserInitiatorInfo& operator=(const PrefetchBrowserInitiatorInfo&) =
delete;
PrefetchBrowserInitiatorInfo(PrefetchBrowserInitiatorInfo&&);
const std::string& embedder_histogram_suffix() const {
return embedder_histogram_suffix_;
}
PrefetchRequestStatusListener* request_status_listener() const {
return request_status_listener_.get();
}
private:
// The suffix string of embedder triggers used for generating histogram
// recorded per trigger.
std::string embedder_histogram_suffix_;
// Listener of prefetch request. Currently used for WebView initiated
// prefetch.
std::unique_ptr<PrefetchRequestStatusListener> request_status_listener_;
};
// `PrefetchRequest` represents request parameters to `PrefetchService` to
// prefetch a URL.
//
// TODO(https://crbug.com/437631382): Incrementally migrate the
// `PrefetchContainer` constructor arguments into `PrefetchRequest`, so that
// eventually all parameters are passed via `PrefetchRequest` from the current
// callers of the `PrefetchContainer` constructors. After that, we can make the
// callers to construct `PrefetchRequest` instead of `PrefetchContainer`.
class CONTENT_EXPORT PrefetchRequest final {
public:
PrefetchRequest(
const PrefetchType& prefetch_type,
const PrefetchKey& key,
const std::optional<net::HttpNoVarySearchData> no_vary_search_hint,
std::optional<PrefetchPriority> priority,
scoped_refptr<PreloadPipelineInfo> preload_pipeline_info,
base::WeakPtr<PreloadingAttempt> attempt,
bool is_javascript_enabled,
const blink::mojom::Referrer& initial_referrer,
const std::optional<url::Origin>& referring_origin,
base::WeakPtr<BrowserContext> browser_context,
std::optional<SpeculationRulesTags> speculation_rules_tags,
const net::HttpRequestHeaders& additional_headers,
base::TimeDelta ttl,
std::optional<PreloadingHoldbackStatus> holdback_status_override,
bool should_append_variations_header,
bool should_disable_block_until_head_timeout,
std::variant<PrefetchRendererInitiatorInfo, PrefetchBrowserInitiatorInfo>
info);
~PrefetchRequest();
const PrefetchType& prefetch_type() const { return prefetch_type_; }
const PrefetchKey& key() const { return key_; }
const std::optional<net::HttpNoVarySearchData>& no_vary_search_hint() const {
return no_vary_search_hint_;
}
const std::optional<PrefetchPriority>& priority() const { return priority_; }
PreloadPipelineInfoImpl& preload_pipeline_info() const {
return *preload_pipeline_info_;
}
PreloadingAttempt* attempt() const { return attempt_.get(); }
bool is_javascript_enabled() const { return is_javascript_enabled_; }
const blink::mojom::Referrer& initial_referrer() const {
return initial_referrer_;
}
const std::optional<url::Origin>& referring_origin() const {
return referring_origin_;
}
BrowserContext* browser_context() const { return browser_context_.get(); }
const std::optional<SpeculationRulesTags>& speculation_rules_tags() const {
return speculation_rules_tags_;
}
const net::HttpRequestHeaders& additional_headers() const {
return additional_headers_;
}
const base::TimeDelta& ttl() const { return ttl_; }
const std::optional<PreloadingHoldbackStatus>& holdback_status_override()
const {
return holdback_status_override_;
}
bool should_append_variations_header() const {
return should_append_variations_header_;
}
bool should_disable_block_until_head_timeout() const {
return should_disable_block_until_head_timeout_;
}
// Returns non-null if renderer-initiated/browser-initiated, respectively.
// Exactly one of them returns non-null.
const PrefetchRendererInitiatorInfo* GetRendererInitiatorInfo() const;
const PrefetchBrowserInitiatorInfo* GetBrowserInitiatorInfo() const;
private:
// The type of this prefetch. This controls some specific details about how
// the prefetch is handled, including whether an isolated network context or
// the default network context is used to perform the prefetch, whether or
// not the preftch proxy is used, and whether or not subresources are
// prefetched.
const PrefetchType prefetch_type_;
// The key used to match this PrefetchContainer, including the URL that was
// requested to prefetch.
const PrefetchKey key_;
// The No-Vary-Search hint of the prefetch, which is specified by the
// speculation rules and can be different from actual
// `PrefetchContainer::no_vary_search_data_`.
const std::optional<net::HttpNoVarySearchData> no_vary_search_hint_;
// An optimization hint indicating how quickly this prefetch should be
// available.
const std::optional<PrefetchPriority> priority_;
// The primary `PreloadPipelineInfo`, i.e. that of the first initiator.
// Subsequent requests' `PreloadPipelineInfo`s are tracked by
// `PrefetchContainer::inherited_preload_pipeline_infos_`.
// The pointer is immutable (i.e. pointing to the same
// `PreloadPipelineInfoImpl` throughout the lifetime) while the pointed
// PreloadPipelineInfoImpl is mutable as we'll update/notify the
// PreloadPipelineInfoImpl.
const scoped_refptr<PreloadPipelineInfoImpl> preload_pipeline_info_;
// `PreloadingAttempt` is used to track the lifecycle of the preloading event,
// and reports various statuses to UKM dashboard. It is initialised along with
// `this`, and destroyed when `WCO::DidFinishNavigation` is fired.
// `attempt_`'s eligibility is set in `OnEligibilityCheckComplete`, and its
// holdback status, triggering outcome and failure reason are set in
// `SetPrefetchStatus`.
const base::WeakPtr<PreloadingAttempt> attempt_;
// Whether JavaScript is on in this contents (or was, when this prefetch
// started). This affects Client Hints behavior. Per-origin settings are
// handled later, according to
// |ClientHintsControllerDelegate::IsJavaScriptAllowed|.
const bool is_javascript_enabled_;
// The referrer to use for the initial request.
// Only for initialization of `PrefetchContainer::referrer_`.
// For other cases, use `PrefetchContainer::referrer_` instead.
const blink::mojom::Referrer initial_referrer_;
// The origin and URL that initiates the prefetch request.
// For renderer-initiated prefetch, this is calculated by referring
// RenderFrameHost's LastCommittedOrigin. For browser-initiated prefetch, this
// is sometimes explicitly passed via ctor.
const std::optional<url::Origin> referring_origin_;
// The |BrowserContext| in which this is being run.
const base::WeakPtr<BrowserContext> browser_context_;
// -------- Parameters that can have non-default values only for
// -------- renderer-initiated prefetches:
// The tags of the speculation rules that triggered this prefetch, and this
// field is non-null if and only if this is created by SpeculationRules
// prefech. These are assumed to have been validated by the time this is
// constructed.
std::optional<SpeculationRulesTags> speculation_rules_tags_;
// -------- Parameters that can have non-default values only for
// -------- browser-initiated prefetches:
// Additional headers for WebView initiated prefetch.
// This must be empty for non-WebView initiated prefetches.
// TODO(crbug.com/369859822): Revisit the semantics if needed.
const net::HttpRequestHeaders additional_headers_;
// Time-to-live (TTL) for this prefetched data. Currently, this is configured
// for browser-initiated prefetch that doesn't depend on web content.
// Default value is `PrefetchContainerDefaultTtlInPrefetchService()`.
base::TimeDelta ttl_;
// If set, this value is used to override holdback status derived by the
// normal process. It is set to `attempt_` on
// PrefetchService::CheckAndSetPrefetchHoldbackStatus().
const std::optional<PreloadingHoldbackStatus> holdback_status_override_;
// Whether to add the X-Client-Data header with experiment IDs from field
// trials. This will not be applied to redirects. Currently, this is
// configured for browser-initiated prefetch that doesn't depend on web
// content. Default value is `true`.
const bool should_append_variations_header_;
// Whether the caller of prefetches requests to disable
// `BlockUntilHeadTimeout`, which is currently calculated by
// `PrefetchBlockUntilHeadTimeout()` as a `prefetch_params`.
// Default value is `false`.
const bool should_disable_block_until_head_timeout_;
const std::variant<PrefetchRendererInitiatorInfo,
PrefetchBrowserInitiatorInfo>
initiator_info_;
};
} // namespace content
#endif // CONTENT_BROWSER_PRELOADING_PREFETCH_PREFETCH_REQUEST_H_