blob: 4ad2d5dad56446b0a68e1301a30fa293e5b10bdb [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.
#include "content/browser/preloading/prefetch/prefetch_request.h"
#include <variant>
#include "base/memory/weak_ptr.h"
#include "content/browser/preloading/prefetch/prefetch_params.h"
#include "content/browser/preloading/prefetch/prefetch_type.h"
#include "content/browser/preloading/preload_pipeline_info_impl.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/prefetch_request_status_listener.h"
namespace content {
namespace {
ukm::SourceId GetUkmSourceId(RenderFrameHostImpl& rfhi) {
// Prerendering page should not trigger prefetches.
CHECK(
!rfhi.IsInLifecycleState(RenderFrameHost::LifecycleState::kPrerendering));
return rfhi.GetPageUkmSourceId();
}
} // namespace
PrefetchRendererInitiatorInfo::PrefetchRendererInitiatorInfo(
RenderFrameHostImpl& render_frame_host,
base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager)
: render_frame_host_id_(render_frame_host.GetGlobalId()),
prefetch_document_manager_(std::move(prefetch_document_manager)),
devtools_navigation_token_(
render_frame_host.GetDevToolsNavigationToken()),
ukm_source_id_(GetUkmSourceId(render_frame_host)) {}
PrefetchRendererInitiatorInfo::PrefetchRendererInitiatorInfo(
PrefetchRendererInitiatorInfo&&) = default;
PrefetchRendererInitiatorInfo::~PrefetchRendererInitiatorInfo() = default;
RenderFrameHostImpl* PrefetchRendererInitiatorInfo::GetRenderFrameHost() const {
return RenderFrameHostImpl::FromID(render_frame_host_id_);
}
PrefetchBrowserInitiatorInfo::~PrefetchBrowserInitiatorInfo() = default;
PrefetchBrowserInitiatorInfo::PrefetchBrowserInitiatorInfo(
PrefetchBrowserInitiatorInfo&&) = default;
PrefetchBrowserInitiatorInfo::PrefetchBrowserInitiatorInfo(
const std::string& embedder_histogram_suffix,
std::unique_ptr<PrefetchRequestStatusListener> request_status_listener)
: embedder_histogram_suffix_(embedder_histogram_suffix),
request_status_listener_(std::move(request_status_listener)) {
CHECK(!embedder_histogram_suffix_.empty());
}
PrefetchRequest::PrefetchRequest(
base::PassKey<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,
base::WeakPtr<WebContents> referring_web_contents,
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,
PreloadingHoldbackStatus holdback_status_override,
bool should_append_variations_header,
bool should_disable_block_until_head_timeout,
std::variant<PrefetchRendererInitiatorInfo, PrefetchBrowserInitiatorInfo>
initiator_info)
: prefetch_type_(prefetch_type),
key_(key),
no_vary_search_hint_(std::move(no_vary_search_hint)),
priority_(std::move(priority)),
preload_pipeline_info_(base::WrapRefCounted(
static_cast<PreloadPipelineInfoImpl*>(preload_pipeline_info.get()))),
attempt_(std::move(attempt)),
is_javascript_enabled_(is_javascript_enabled),
initial_referrer_(initial_referrer),
referring_origin_(referring_origin),
referring_web_contents_(std::move(referring_web_contents)),
browser_context_(std::move(browser_context)),
speculation_rules_tags_(std::move(speculation_rules_tags)),
additional_headers_(additional_headers),
ttl_(std::move(ttl)),
holdback_status_override_(std::move(holdback_status_override)),
should_append_variations_header_(should_append_variations_header),
should_disable_block_until_head_timeout_(
should_disable_block_until_head_timeout),
initiator_info_(std::move(initiator_info)) {
CHECK(preload_pipeline_info_);
if (prefetch_type_.IsRendererInitiated()) {
CHECK(GetRendererInitiatorInfo());
CHECK(!GetBrowserInitiatorInfo());
CHECK(additional_headers_.IsEmpty());
CHECK_EQ(ttl_, PrefetchContainerDefaultTtlInPrefetchService());
CHECK_EQ(holdback_status_override_, PreloadingHoldbackStatus::kUnspecified);
CHECK(should_append_variations_header_);
CHECK(!should_disable_block_until_head_timeout_);
} else {
CHECK(!GetRendererInitiatorInfo());
CHECK(GetBrowserInitiatorInfo());
CHECK(!speculation_rules_tags_);
}
}
PrefetchRequest::~PrefetchRequest() = default;
// static
std::unique_ptr<const PrefetchRequest> PrefetchRequest::CreateRendererInitiated(
RenderFrameHostImpl& referring_render_frame_host,
const blink::DocumentToken& referring_document_token,
const GURL& url,
const PrefetchType& prefetch_type,
const blink::mojom::Referrer& referrer,
std::optional<SpeculationRulesTags> speculation_rules_tags,
std::optional<net::HttpNoVarySearchData> no_vary_search_hint,
std::optional<PrefetchPriority> priority,
base::WeakPtr<PrefetchDocumentManager> prefetch_document_manager,
scoped_refptr<PreloadPipelineInfo> preload_pipeline_info,
base::WeakPtr<PreloadingAttempt> attempt) {
return std::make_unique<PrefetchRequest>(
base::PassKey<PrefetchRequest>(), prefetch_type,
PrefetchKey(referring_document_token, url),
std::move(no_vary_search_hint), std::move(priority),
std::move(preload_pipeline_info), std::move(attempt),
WebContentsImpl::FromRenderFrameHostImpl(&referring_render_frame_host)
->GetWeakPtr(),
WebContentsImpl::FromRenderFrameHostImpl(&referring_render_frame_host)
->GetOrCreateWebPreferences()
.javascript_enabled,
referrer, referring_render_frame_host.GetLastCommittedOrigin(),
referring_render_frame_host.GetBrowserContext()->GetWeakPtr(),
std::move(speculation_rules_tags),
/*Must be empty: additional_headers=*/net::HttpRequestHeaders(),
PrefetchContainerDefaultTtlInPrefetchService(),
/*holdback_status_override=*/PreloadingHoldbackStatus::kUnspecified,
/*should_append_variations_header=*/true,
/*should_disable_block_until_head_timeout=*/false,
PrefetchRendererInitiatorInfo(referring_render_frame_host,
std::move(prefetch_document_manager)));
}
// static
std::unique_ptr<const PrefetchRequest> PrefetchRequest::CreateBrowserInitiated(
WebContents& referring_web_contents,
const GURL& url,
const PrefetchType& prefetch_type,
const std::string& embedder_histogram_suffix,
const blink::mojom::Referrer& referrer,
const std::optional<url::Origin>& referring_origin,
std::optional<net::HttpNoVarySearchData> no_vary_search_hint,
std::optional<PrefetchPriority> priority,
scoped_refptr<PreloadPipelineInfo> preload_pipeline_info,
base::WeakPtr<PreloadingAttempt> attempt,
PreloadingHoldbackStatus holdback_status_override,
std::optional<base::TimeDelta> ttl) {
return std::make_unique<PrefetchRequest>(
base::PassKey<PrefetchRequest>(), prefetch_type,
PrefetchKey(std::optional<blink::DocumentToken>(std::nullopt), url),
std::move(no_vary_search_hint), std::move(priority),
std::move(preload_pipeline_info), std::move(attempt),
referring_web_contents.GetWeakPtr(),
referring_web_contents.GetOrCreateWebPreferences().javascript_enabled,
referrer, referring_origin,
referring_web_contents.GetBrowserContext()->GetWeakPtr(),
/*speculation_rules_tags=*/std::nullopt,
/*Must be empty: additional_headers=*/net::HttpRequestHeaders(),
ttl.has_value() ? ttl.value()
: PrefetchContainerDefaultTtlInPrefetchService(),
std::move(holdback_status_override),
/*should_append_variations_header=*/true,
/*should_disable_block_until_head_timeout=*/false,
PrefetchBrowserInitiatorInfo(embedder_histogram_suffix,
/*request_status_listener=*/nullptr));
}
// static
std::unique_ptr<const PrefetchRequest>
PrefetchRequest::CreateBrowserInitiatedWithoutWebContents(
BrowserContext* browser_context,
const GURL& url,
const PrefetchType& prefetch_type,
const std::string& embedder_histogram_suffix,
const blink::mojom::Referrer& referrer,
bool javascript_enabled,
const std::optional<url::Origin>& referring_origin,
std::optional<net::HttpNoVarySearchData> no_vary_search_hint,
std::optional<PrefetchPriority> priority,
base::WeakPtr<PreloadingAttempt> attempt,
const net::HttpRequestHeaders& additional_headers,
std::unique_ptr<PrefetchRequestStatusListener> request_status_listener,
base::TimeDelta ttl,
bool should_append_variations_header,
bool should_disable_block_until_head_timeout) {
return std::make_unique<PrefetchRequest>(
base::PassKey<PrefetchRequest>(), prefetch_type,
PrefetchKey(std::optional<blink::DocumentToken>(std::nullopt), url),
std::move(no_vary_search_hint), std::move(priority),
PreloadPipelineInfo::Create(
/*planned_max_preloading_type=*/PreloadingType::kPrefetch),
std::move(attempt), /*referring_web_contents=*/nullptr,
javascript_enabled, referrer, referring_origin,
browser_context->GetWeakPtr(),
/*speculation_rules_tags=*/
std::nullopt, additional_headers, ttl,
/*holdback_status_override=*/PreloadingHoldbackStatus::kUnspecified,
should_append_variations_header, should_disable_block_until_head_timeout,
PrefetchBrowserInitiatorInfo(embedder_histogram_suffix,
std::move(request_status_listener)));
}
const PrefetchRendererInitiatorInfo* PrefetchRequest::GetRendererInitiatorInfo()
const {
return std::get_if<PrefetchRendererInitiatorInfo>(&initiator_info_);
}
const PrefetchBrowserInitiatorInfo* PrefetchRequest::GetBrowserInitiatorInfo()
const {
return std::get_if<PrefetchBrowserInitiatorInfo>(&initiator_info_);
}
} // namespace content