blob: 58b5d035a94033a99d8584e2da3edd840c845cf0 [file] [log] [blame]
// Copyright 2023 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/devtools/protocol/preload_handler.h"
#include <memory>
#include <utility>
#include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/browser/devtools/devtools_preload_storage.h"
#include "content/browser/devtools/protocol/preload.h"
#include "content/browser/devtools/render_frame_devtools_agent_host.h"
#include "content/browser/preloading/prefetch/prefetch_service.h"
#include "content/browser/preloading/preloading.h"
#include "content/browser/preloading/preloading_config.h"
#include "content/browser/preloading/prerender/prerender_final_status.h"
#include "content/browser/preloading/prerender/prerender_metrics.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/prefetch_service_delegate.h"
namespace content::protocol {
namespace {
Preload::PrerenderFinalStatus PrerenderFinalStatusToProtocol(
PrerenderFinalStatus feature) {
switch (feature) {
case PrerenderFinalStatus::kActivated:
return Preload::PrerenderFinalStatusEnum::Activated;
case PrerenderFinalStatus::kBlockedByClient:
return Preload::PrerenderFinalStatusEnum::BlockedByClient;
case PrerenderFinalStatus::kCancelAllHostsForTesting:
return Preload::PrerenderFinalStatusEnum::CancelAllHostsForTesting;
case PrerenderFinalStatus::kClientCertRequested:
return Preload::PrerenderFinalStatusEnum::ClientCertRequested;
case PrerenderFinalStatus::kDataSaverEnabled:
return Preload::PrerenderFinalStatusEnum::DataSaverEnabled;
case PrerenderFinalStatus::kDestroyed:
return Preload::PrerenderFinalStatusEnum::Destroyed;
case PrerenderFinalStatus::kDidFailLoad:
return Preload::PrerenderFinalStatusEnum::DidFailLoad;
case PrerenderFinalStatus::kDownload:
return Preload::PrerenderFinalStatusEnum::Download;
case PrerenderFinalStatus::kInvalidSchemeNavigation:
return Preload::PrerenderFinalStatusEnum::InvalidSchemeNavigation;
case PrerenderFinalStatus::kInvalidSchemeRedirect:
return Preload::PrerenderFinalStatusEnum::InvalidSchemeRedirect;
case PrerenderFinalStatus::kLoginAuthRequested:
return Preload::PrerenderFinalStatusEnum::LoginAuthRequested;
case PrerenderFinalStatus::kLowEndDevice:
return Preload::PrerenderFinalStatusEnum::LowEndDevice;
case PrerenderFinalStatus::kMemoryLimitExceeded:
return Preload::PrerenderFinalStatusEnum::MemoryLimitExceeded;
case PrerenderFinalStatus::kMixedContent:
return Preload::PrerenderFinalStatusEnum::MixedContent;
case PrerenderFinalStatus::kMojoBinderPolicy:
return Preload::PrerenderFinalStatusEnum::MojoBinderPolicy;
case PrerenderFinalStatus::kNavigationBadHttpStatus:
return Preload::PrerenderFinalStatusEnum::NavigationBadHttpStatus;
case PrerenderFinalStatus::kNavigationNotCommitted:
return Preload::PrerenderFinalStatusEnum::NavigationNotCommitted;
case PrerenderFinalStatus::kNavigationRequestBlockedByCsp:
return Preload::PrerenderFinalStatusEnum::NavigationRequestBlockedByCsp;
case PrerenderFinalStatus::kNavigationRequestNetworkError:
return Preload::PrerenderFinalStatusEnum::NavigationRequestNetworkError;
case PrerenderFinalStatus::kRendererProcessCrashed:
return Preload::PrerenderFinalStatusEnum::RendererProcessCrashed;
case PrerenderFinalStatus::kRendererProcessKilled:
return Preload::PrerenderFinalStatusEnum::RendererProcessKilled;
case PrerenderFinalStatus::kSslCertificateError:
return Preload::PrerenderFinalStatusEnum::SslCertificateError;
case PrerenderFinalStatus::kStop:
return Preload::PrerenderFinalStatusEnum::Stop;
case PrerenderFinalStatus::kTriggerBackgrounded:
return Preload::PrerenderFinalStatusEnum::TriggerBackgrounded;
case PrerenderFinalStatus::kTriggerDestroyed:
return Preload::PrerenderFinalStatusEnum::TriggerDestroyed;
case PrerenderFinalStatus::kUaChangeRequiresReload:
return Preload::PrerenderFinalStatusEnum::UaChangeRequiresReload;
case PrerenderFinalStatus::kTriggerUrlHasEffectiveUrl:
return Preload::PrerenderFinalStatusEnum::TriggerUrlHasEffectiveUrl;
case PrerenderFinalStatus::kActivatedBeforeStarted:
return Preload::PrerenderFinalStatusEnum::ActivatedBeforeStarted;
case PrerenderFinalStatus::kInactivePageRestriction:
return Preload::PrerenderFinalStatusEnum::InactivePageRestriction;
case PrerenderFinalStatus::kStartFailed:
return Preload::PrerenderFinalStatusEnum::StartFailed;
case PrerenderFinalStatus::kTimeoutBackgrounded:
return Preload::PrerenderFinalStatusEnum::TimeoutBackgrounded;
case PrerenderFinalStatus::kCrossSiteRedirectInInitialNavigation:
return Preload::PrerenderFinalStatusEnum::
CrossSiteRedirectInInitialNavigation;
case PrerenderFinalStatus::kCrossSiteNavigationInInitialNavigation:
return Preload::PrerenderFinalStatusEnum::
CrossSiteNavigationInInitialNavigation;
case PrerenderFinalStatus::
kSameSiteCrossOriginRedirectNotOptInInInitialNavigation:
return Preload::PrerenderFinalStatusEnum::
SameSiteCrossOriginRedirectNotOptInInInitialNavigation;
case PrerenderFinalStatus::
kSameSiteCrossOriginNavigationNotOptInInInitialNavigation:
return Preload::PrerenderFinalStatusEnum::
SameSiteCrossOriginNavigationNotOptInInInitialNavigation;
case PrerenderFinalStatus::kActivationNavigationParameterMismatch:
return Preload::PrerenderFinalStatusEnum::
ActivationNavigationParameterMismatch;
case PrerenderFinalStatus::kActivatedInBackground:
return Preload::PrerenderFinalStatusEnum::ActivatedInBackground;
case PrerenderFinalStatus::kActivationNavigationDestroyedBeforeSuccess:
return Preload::PrerenderFinalStatusEnum::
ActivationNavigationDestroyedBeforeSuccess;
case PrerenderFinalStatus::kTabClosedByUserGesture:
return Preload::PrerenderFinalStatusEnum::TabClosedByUserGesture;
case PrerenderFinalStatus::kTabClosedWithoutUserGesture:
return Preload::PrerenderFinalStatusEnum::TabClosedWithoutUserGesture;
case PrerenderFinalStatus::kPrimaryMainFrameRendererProcessCrashed:
return Preload::PrerenderFinalStatusEnum::
PrimaryMainFrameRendererProcessCrashed;
case PrerenderFinalStatus::kPrimaryMainFrameRendererProcessKilled:
return Preload::PrerenderFinalStatusEnum::
PrimaryMainFrameRendererProcessKilled;
case PrerenderFinalStatus::kActivationFramePolicyNotCompatible:
return Preload::PrerenderFinalStatusEnum::
ActivationFramePolicyNotCompatible;
case PrerenderFinalStatus::kPreloadingDisabled:
return Preload::PrerenderFinalStatusEnum::PreloadingDisabled;
case PrerenderFinalStatus::kBatterySaverEnabled:
return Preload::PrerenderFinalStatusEnum::BatterySaverEnabled;
case PrerenderFinalStatus::kActivatedDuringMainFrameNavigation:
return Preload::PrerenderFinalStatusEnum::
ActivatedDuringMainFrameNavigation;
case PrerenderFinalStatus::kPreloadingUnsupportedByWebContents:
return Preload::PrerenderFinalStatusEnum::
PreloadingUnsupportedByWebContents;
case PrerenderFinalStatus::kCrossSiteRedirectInMainFrameNavigation:
return Preload::PrerenderFinalStatusEnum::
CrossSiteRedirectInMainFrameNavigation;
case PrerenderFinalStatus::kCrossSiteNavigationInMainFrameNavigation:
return Preload::PrerenderFinalStatusEnum::
CrossSiteNavigationInMainFrameNavigation;
case PrerenderFinalStatus::
kSameSiteCrossOriginRedirectNotOptInInMainFrameNavigation:
return Preload::PrerenderFinalStatusEnum::
SameSiteCrossOriginRedirectNotOptInInMainFrameNavigation;
case PrerenderFinalStatus::
kSameSiteCrossOriginNavigationNotOptInInMainFrameNavigation:
return Preload::PrerenderFinalStatusEnum::
SameSiteCrossOriginNavigationNotOptInInMainFrameNavigation;
case PrerenderFinalStatus::kMemoryPressureOnTrigger:
return Preload::PrerenderFinalStatusEnum::MemoryPressureOnTrigger;
case PrerenderFinalStatus::kMemoryPressureAfterTriggered:
return Preload::PrerenderFinalStatusEnum::MemoryPressureAfterTriggered;
case PrerenderFinalStatus::kPrerenderingDisabledByDevTools:
return Preload::PrerenderFinalStatusEnum::PrerenderingDisabledByDevTools;
case PrerenderFinalStatus::kSpeculationRuleRemoved:
return Preload::PrerenderFinalStatusEnum::SpeculationRuleRemoved;
case PrerenderFinalStatus::kActivatedWithAuxiliaryBrowsingContexts:
return Preload::PrerenderFinalStatusEnum::
ActivatedWithAuxiliaryBrowsingContexts;
case PrerenderFinalStatus::kMaxNumOfRunningImmediatePrerendersExceeded:
return Preload::PrerenderFinalStatusEnum::
MaxNumOfRunningEagerPrerendersExceeded;
case PrerenderFinalStatus::kMaxNumOfRunningNonImmediatePrerendersExceeded:
return Preload::PrerenderFinalStatusEnum::
MaxNumOfRunningNonEagerPrerendersExceeded;
case PrerenderFinalStatus::kMaxNumOfRunningEmbedderPrerendersExceeded:
return Preload::PrerenderFinalStatusEnum::
MaxNumOfRunningEmbedderPrerendersExceeded;
case PrerenderFinalStatus::kPrerenderingUrlHasEffectiveUrl:
return Preload::PrerenderFinalStatusEnum::PrerenderingUrlHasEffectiveUrl;
case PrerenderFinalStatus::kRedirectedPrerenderingUrlHasEffectiveUrl:
return Preload::PrerenderFinalStatusEnum::
RedirectedPrerenderingUrlHasEffectiveUrl;
case PrerenderFinalStatus::kActivationUrlHasEffectiveUrl:
return Preload::PrerenderFinalStatusEnum::ActivationUrlHasEffectiveUrl;
case PrerenderFinalStatus::kJavaScriptInterfaceAdded:
return Preload::PrerenderFinalStatusEnum::JavaScriptInterfaceAdded;
case PrerenderFinalStatus::kJavaScriptInterfaceRemoved:
return Preload::PrerenderFinalStatusEnum::JavaScriptInterfaceRemoved;
case PrerenderFinalStatus::kAllPrerenderingCanceled:
return Preload::PrerenderFinalStatusEnum::AllPrerenderingCanceled;
case PrerenderFinalStatus::kWindowClosed:
return Preload::PrerenderFinalStatusEnum::WindowClosed;
case PrerenderFinalStatus::kSlowNetwork:
return Preload::PrerenderFinalStatusEnum::SlowNetwork;
case PrerenderFinalStatus::kOtherPrerenderedPageActivated:
return Preload::PrerenderFinalStatusEnum::OtherPrerenderedPageActivated;
case PrerenderFinalStatus::kPrerenderFailedDuringPrefetch:
return Preload::PrerenderFinalStatusEnum::PrerenderFailedDuringPrefetch;
case PrerenderFinalStatus::kBrowsingDataRemoved:
return Preload::PrerenderFinalStatusEnum::BrowsingDataRemoved;
case PrerenderFinalStatus::kPrerenderHostReused:
return Preload::PrerenderFinalStatusEnum::PrerenderHostReused;
}
}
Preload::PreloadingStatus PreloadingTriggeringOutcomeToProtocol(
PreloadingTriggeringOutcome feature) {
switch (feature) {
case PreloadingTriggeringOutcome::kRunning:
return Preload::PreloadingStatusEnum::Running;
case PreloadingTriggeringOutcome::kReady:
return Preload::PreloadingStatusEnum::Ready;
case PreloadingTriggeringOutcome::kSuccess:
return Preload::PreloadingStatusEnum::Success;
case PreloadingTriggeringOutcome::kFailure:
return Preload::PreloadingStatusEnum::Failure;
case PreloadingTriggeringOutcome::kTriggeredButPending:
return Preload::PreloadingStatusEnum::Pending;
case PreloadingTriggeringOutcome::kUnspecified:
case PreloadingTriggeringOutcome::kDuplicate:
case PreloadingTriggeringOutcome::kTriggeredButOutcomeUnknown:
case PreloadingTriggeringOutcome::kTriggeredButUpgradedToPrerender:
case PreloadingTriggeringOutcome::kNoOp:
return Preload::PreloadingStatusEnum::NotSupported;
}
}
Preload::PrefetchStatus PrefetchStatusToProtocol(PrefetchStatus status) {
switch (status) {
case PrefetchStatus::kPrefetchNotUsedProbeFailed:
return Preload::PrefetchStatusEnum::PrefetchNotUsedProbeFailed;
case PrefetchStatus::kPrefetchNotStarted:
return Preload::PrefetchStatusEnum::PrefetchNotStarted;
case PrefetchStatus::kPrefetchIneligibleUserHasCookies:
return Preload::PrefetchStatusEnum::PrefetchNotEligibleUserHasCookies;
case PrefetchStatus::kPrefetchIneligibleUserHasServiceWorker:
return Preload::PrefetchStatusEnum::
PrefetchNotEligibleUserHasServiceWorker;
case PrefetchStatus::kPrefetchIneligibleSchemeIsNotHttps:
return Preload::PrefetchStatusEnum::PrefetchNotEligibleSchemeIsNotHttps;
case PrefetchStatus::kPrefetchIneligibleNonDefaultStoragePartition:
return Preload::PrefetchStatusEnum::
PrefetchNotEligibleNonDefaultStoragePartition;
case PrefetchStatus::kPrefetchNotFinishedInTime:
return Preload::PrefetchStatusEnum::PrefetchNotFinishedInTime;
case PrefetchStatus::kPrefetchFailedNetError:
return Preload::PrefetchStatusEnum::PrefetchFailedNetError;
case PrefetchStatus::kPrefetchFailedNon2XX:
return Preload::PrefetchStatusEnum::PrefetchFailedNon2XX;
case PrefetchStatus::kPrefetchFailedMIMENotSupported:
return Preload::PrefetchStatusEnum::PrefetchFailedMIMENotSupported;
case PrefetchStatus::kPrefetchSuccessful:
return Preload::PrefetchStatusEnum::PrefetchSuccessfulButNotUsed;
case PrefetchStatus::kPrefetchIneligibleRetryAfter:
return Preload::PrefetchStatusEnum::PrefetchIneligibleRetryAfter;
case PrefetchStatus::kPrefetchIneligiblePrefetchProxyNotAvailable:
return Preload::PrefetchStatusEnum::PrefetchProxyNotAvailable;
case PrefetchStatus::kPrefetchIsPrivacyDecoy:
return Preload::PrefetchStatusEnum::PrefetchIsPrivacyDecoy;
case PrefetchStatus::kPrefetchIsStale:
return Preload::PrefetchStatusEnum::PrefetchIsStale;
case PrefetchStatus::kPrefetchNotUsedCookiesChanged:
return Preload::PrefetchStatusEnum::PrefetchNotUsedCookiesChanged;
case PrefetchStatus::kPrefetchIneligibleHostIsNonUnique:
return Preload::PrefetchStatusEnum::PrefetchNotEligibleHostIsNonUnique;
case PrefetchStatus::kPrefetchIneligibleDataSaverEnabled:
return Preload::PrefetchStatusEnum::PrefetchNotEligibleDataSaverEnabled;
case PrefetchStatus::kPrefetchIneligibleExistingProxy:
return Preload::PrefetchStatusEnum::PrefetchNotEligibleExistingProxy;
case PrefetchStatus::kPrefetchIneligiblePreloadingDisabled:
return Preload::PrefetchStatusEnum::PrefetchNotEligiblePreloadingDisabled;
case PrefetchStatus::kPrefetchIneligibleBatterySaverEnabled:
return Preload::PrefetchStatusEnum::
PrefetchNotEligibleBatterySaverEnabled;
case PrefetchStatus::kPrefetchHeldback:
return Preload::PrefetchStatusEnum::PrefetchHeldback;
case PrefetchStatus::kPrefetchResponseUsed:
return Preload::PrefetchStatusEnum::PrefetchResponseUsed;
case PrefetchStatus::kPrefetchFailedInvalidRedirect:
return Preload::PrefetchStatusEnum::PrefetchFailedInvalidRedirect;
case PrefetchStatus::kPrefetchFailedIneligibleRedirect:
return Preload::PrefetchStatusEnum::PrefetchFailedIneligibleRedirect;
case PrefetchStatus::
kPrefetchIneligibleSameSiteCrossOriginPrefetchRequiredProxy:
return Preload::PrefetchStatusEnum::
PrefetchNotEligibleSameSiteCrossOriginPrefetchRequiredProxy;
case PrefetchStatus::kPrefetchEvictedAfterCandidateRemoved:
return Preload::PrefetchStatusEnum::PrefetchEvictedAfterCandidateRemoved;
case PrefetchStatus::kPrefetchEvictedForNewerPrefetch:
return Preload::PrefetchStatusEnum::PrefetchEvictedForNewerPrefetch;
case PrefetchStatus::kPrefetchIneligibleRedirectFromServiceWorker:
return Preload::PrefetchStatusEnum::
PrefetchNotEligibleRedirectFromServiceWorker;
case PrefetchStatus::kPrefetchIneligibleRedirectToServiceWorker:
return Preload::PrefetchStatusEnum::
PrefetchNotEligibleRedirectToServiceWorker;
case PrefetchStatus::kPrefetchIneligibleUserHasServiceWorkerNoFetchHandler:
return Preload::PrefetchStatusEnum::
PrefetchNotEligibleUserHasServiceWorkerNoFetchHandler;
case PrefetchStatus::kPrefetchEvictedAfterBrowsingDataRemoved:
return Preload::PrefetchStatusEnum::
PrefetchEvictedAfterBrowsingDataRemoved;
}
}
bool PreloadingTriggeringOutcomeSupportedByPrefetch(
PreloadingTriggeringOutcome feature) {
// TODO(crbug.com/40246462): revisit the unsupported cases call sites to make
// sure that either they are covered by other CDPs or they are included by the
// current CDPs in the future.
switch (feature) {
case PreloadingTriggeringOutcome::kRunning:
case PreloadingTriggeringOutcome::kReady:
case PreloadingTriggeringOutcome::kSuccess:
case PreloadingTriggeringOutcome::kFailure:
return true;
case PreloadingTriggeringOutcome::kTriggeredButPending:
case PreloadingTriggeringOutcome::kUnspecified:
case PreloadingTriggeringOutcome::kDuplicate:
case PreloadingTriggeringOutcome::kTriggeredButOutcomeUnknown:
case PreloadingTriggeringOutcome::kTriggeredButUpgradedToPrerender:
case PreloadingTriggeringOutcome::kNoOp:
return false;
}
}
bool PreloadingTriggeringOutcomeSupportedByPrerender(
PreloadingTriggeringOutcome feature) {
// TODO(crbug.com/40246462): revisit the unsupported cases call sites to make
// sure that either they are covered by other CDPs or they are included by the
// current CDPs in the future.
switch (feature) {
case PreloadingTriggeringOutcome::kRunning:
case PreloadingTriggeringOutcome::kReady:
case PreloadingTriggeringOutcome::kSuccess:
case PreloadingTriggeringOutcome::kFailure:
case PreloadingTriggeringOutcome::kTriggeredButPending:
return true;
case PreloadingTriggeringOutcome::kUnspecified:
case PreloadingTriggeringOutcome::kDuplicate:
case PreloadingTriggeringOutcome::kTriggeredButOutcomeUnknown:
case PreloadingTriggeringOutcome::kTriggeredButUpgradedToPrerender:
case PreloadingTriggeringOutcome::kNoOp:
return false;
}
}
std::optional<protocol::Preload::SpeculationTargetHint>
GetProtocolSpeculationTargetHint(
std::optional<blink::mojom::SpeculationTargetHint> target_hint) {
if (!target_hint.has_value()) {
return std::nullopt;
}
switch (target_hint.value()) {
case blink::mojom::SpeculationTargetHint::kNoHint:
return std::nullopt;
case blink::mojom::SpeculationTargetHint::kBlank:
return protocol::Preload::SpeculationTargetHintEnum::Blank;
case blink::mojom::SpeculationTargetHint::kSelf:
return protocol::Preload::SpeculationTargetHintEnum::Self;
}
}
} // namespace
PreloadHandler::PreloadHandler()
: DevToolsDomainHandler(Preload::Metainfo::domainName) {}
PreloadHandler::~PreloadHandler() = default;
// static
std::vector<PreloadHandler*> PreloadHandler::ForAgentHost(
DevToolsAgentHostImpl* host) {
return host->HandlersByName<PreloadHandler>(Preload::Metainfo::domainName);
}
void PreloadHandler::DidUpdatePrefetchStatus(
const base::UnguessableToken& initiator_devtools_navigation_token,
const std::string& initiating_frame_id,
const GURL& prefetch_url,
const base::UnguessableToken& preload_pipeline_id,
PreloadingTriggeringOutcome status,
PrefetchStatus prefetch_status,
const std::string& request_id) {
if (!enabled_) {
return;
}
auto preloading_attempt_key =
protocol::Preload::PreloadingAttemptKey::Create()
.SetLoaderId(initiator_devtools_navigation_token.ToString())
.SetAction(Preload::SpeculationActionEnum::Prefetch)
.SetUrl(prefetch_url.spec())
.Build();
if (PreloadingTriggeringOutcomeSupportedByPrefetch(status)) {
frontend_->PrefetchStatusUpdated(
std::move(preloading_attempt_key), preload_pipeline_id.ToString(),
initiating_frame_id, prefetch_url.spec(),
PreloadingTriggeringOutcomeToProtocol(status),
PrefetchStatusToProtocol(prefetch_status), request_id);
}
}
void PreloadHandler::DidUpdatePrerenderStatus(
const base::UnguessableToken& initiator_devtools_navigation_token,
const GURL& prerender_url,
std::optional<blink::mojom::SpeculationTargetHint> target_hint,
const base::UnguessableToken& preload_pipeline_id,
PreloadingTriggeringOutcome status,
std::optional<PrerenderFinalStatus> prerender_status,
std::optional<std::string> disallowed_mojo_interface,
const std::vector<PrerenderMismatchedHeaders>* mismatched_headers) {
if (!enabled_) {
return;
}
auto preloading_attempt_key =
protocol::Preload::PreloadingAttemptKey::Create()
.SetLoaderId(initiator_devtools_navigation_token.ToString())
.SetAction(Preload::SpeculationActionEnum::Prerender)
.SetUrl(prerender_url.spec())
.Build();
std::optional<protocol::Preload::SpeculationTargetHint> protocol_target_hint =
GetProtocolSpeculationTargetHint(target_hint);
if (protocol_target_hint.has_value()) {
preloading_attempt_key->SetTargetHint(protocol_target_hint.value());
}
std::optional<Preload::PrerenderFinalStatus> protocol_prerender_status =
prerender_status.has_value()
? PrerenderFinalStatusToProtocol(prerender_status.value())
: std::optional<Preload::PrerenderFinalStatus>();
std::optional<std::string> protocol_disallowed_mojo_interface =
disallowed_mojo_interface.has_value()
? std::optional<std::string>(disallowed_mojo_interface.value())
: std::nullopt;
std::unique_ptr<
protocol::Array<protocol::Preload::PrerenderMismatchedHeaders>>
maybe_mismatched_headers;
if (mismatched_headers) {
auto mismatched_headers_internal = std::make_unique<
protocol::Array<protocol::Preload::PrerenderMismatchedHeaders>>();
for (const auto& mismatched_headers_it : *mismatched_headers) {
auto protocol_mismatched_headers =
protocol::Preload::PrerenderMismatchedHeaders::Create()
.SetHeaderName(mismatched_headers_it.header_name)
.Build();
if (mismatched_headers_it.initial_value) {
protocol_mismatched_headers->SetInitialValue(
mismatched_headers_it.initial_value.value());
}
if (mismatched_headers_it.activation_value) {
protocol_mismatched_headers->SetActivationValue(
mismatched_headers_it.activation_value.value());
}
mismatched_headers_internal->push_back(
std::move(protocol_mismatched_headers));
}
maybe_mismatched_headers = std::move(mismatched_headers_internal);
}
if (PreloadingTriggeringOutcomeSupportedByPrerender(status)) {
frontend_->PrerenderStatusUpdated(
std::move(preloading_attempt_key), preload_pipeline_id.ToString(),
PreloadingTriggeringOutcomeToProtocol(status),
std::move(protocol_prerender_status),
std::move(protocol_disallowed_mojo_interface),
std::move(maybe_mismatched_headers));
}
}
Response PreloadHandler::Enable() {
enabled_ = true;
SendInitialPreloadEnabledState();
SendCurrentPreloadStatus();
return Response::FallThrough();
}
Response PreloadHandler::Disable() {
enabled_ = false;
return Response::FallThrough();
}
void PreloadHandler::Wire(UberDispatcher* dispatcher) {
frontend_ = std::make_unique<Preload::Frontend>(dispatcher->channel());
Preload::Dispatcher::wire(dispatcher, this);
}
void PreloadHandler::SetRenderer(int process_host_id,
RenderFrameHostImpl* frame_host) {
host_ = frame_host;
}
void PreloadHandler::SendInitialPreloadEnabledState() {
if (!host_) {
return;
}
WebContentsImpl* web_contents =
WebContentsImpl::FromRenderFrameHostImpl(host_);
PrefetchService* prefetch_service = PrefetchService::GetFromFrameTreeNodeId(
web_contents->GetPrimaryMainFrame()->GetFrameTreeNodeId());
if (!prefetch_service || !prefetch_service->GetPrefetchServiceDelegate()) {
return;
}
auto* delegate = prefetch_service->GetPrefetchServiceDelegate();
auto& config = PreloadingConfig::GetInstance();
// TODO(crbug.com/40246462): Add more grainularity to
// PreloadingEligibility to distinguish PreloadHoldback and
// DisabledByPreference for PreloadingEligibility::kPreloadingDisabled.
// Use more general method to check status of Preloading instead of
// relying on PrefetchService.
frontend_->PreloadEnabledStateUpdated(
!delegate->IsPreloadingPrefEnabled(), delegate->IsDataSaverEnabled(),
delegate->IsBatterySaverEnabled(),
// Keep them in alphabetical order.
config.ShouldHoldback(
PreloadingType::kPrefetch,
content::content_preloading_predictor::kSpeculationRules),
config.ShouldHoldback(
PreloadingType::kPrerender,
content::content_preloading_predictor::kSpeculationRules));
// TODO(https://crbug.com/428500219): Set holdback status for
// prerender-until-script.
}
void PreloadHandler::SendCurrentPreloadStatus() {
if (!host_) {
return;
}
std::vector<RenderFrameHostImpl*> documents_in_local_subtree;
RenderFrameHostImpl* root = host_;
host_->ForEachRenderFrameHostImplWithAction(
[&documents_in_local_subtree, root](
RenderFrameHostImpl* rfh) -> RenderFrameHost::FrameIterationAction {
if (rfh != root &&
RenderFrameDevToolsAgentHost::ShouldCreateDevToolsForHost(rfh)) {
return RenderFrameHost::FrameIterationAction::kSkipChildren;
}
documents_in_local_subtree.push_back(rfh);
return RenderFrameHost::FrameIterationAction::kContinue;
});
for (RenderFrameHostImpl* document : documents_in_local_subtree) {
auto* preload_storage =
DevToolsPreloadStorage::GetForCurrentDocument(document);
if (!preload_storage) {
continue;
}
std::optional<base::UnguessableToken> maybe_navigation_token =
document->GetDevToolsNavigationToken();
if (!maybe_navigation_token.has_value()) {
continue;
}
const base::UnguessableToken initiator_devtools_navigation_token =
maybe_navigation_token.value();
const std::string initiating_frame_id =
document->GetDevToolsFrameToken().ToString();
for (const auto& [key, data] : preload_storage->prefetch_data_map()) {
DidUpdatePrefetchStatus(initiator_devtools_navigation_token,
initiating_frame_id,
/*prefetch_url=*/key, data.preload_pipeline_id,
data.outcome, data.status, data.request_id);
}
for (const auto& [key, data] : preload_storage->prerender_data_map()) {
DidUpdatePrerenderStatus(
initiator_devtools_navigation_token, /*prerender_url=*/key.first,
/*target_hint=*/key.second, data.preload_pipeline_id, data.outcome,
data.status, data.disallowed_mojo_interface,
data.mismatched_headers.empty() ? nullptr : &data.mismatched_headers);
}
}
}
} // namespace content::protocol