Skip to content

Commit

Permalink
prerender: Expose PrerenderHost::FinalStatus to DevTools
Browse files Browse the repository at this point in the history
This CL introduces cancellation FinalStatus in PrerenderHost to DevTools
, and adds related inspector protocol tests.

Bug: 1249776
Change-Id: I7b6f4ca2c7ebc57f60638e6e7edbb02a4fed63e9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3573829
Reviewed-by: Asami Doi <asamidoi@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Commit-Queue: Huanpo Lin <robertlin@chromium.org>
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1001800}
  • Loading branch information
Robert Lin authored and Chromium LUCI CQ committed May 10, 2022
1 parent 365a7d7 commit 286e2eb
Show file tree
Hide file tree
Showing 16 changed files with 193 additions and 6 deletions.
8 changes: 8 additions & 0 deletions content/browser/devtools/devtools_instrumentation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,14 @@ void DidActivatePrerender(const NavigationRequest& nav_request) {
nav_request);
}

void DidCancelPrerender(const GURL& prerendering_url,
FrameTreeNode* ftn,
PrerenderHost::FinalStatus status) {
std::string initiating_frame_id = ftn->devtools_frame_token().ToString();
DispatchToAgents(ftn, &protocol::PageHandler::DidCancelPrerender,
prerendering_url, initiating_frame_id, status);
}

namespace {

protocol::String BuildBlockedByResponseReason(
Expand Down
4 changes: 4 additions & 0 deletions content/browser/devtools/devtools_instrumentation.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <vector>

#include "content/browser/devtools/devtools_throttle_handle.h"
#include "content/browser/prerender/prerender_host.h"
#include "content/browser/renderer_host/back_forward_cache_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/certificate_request_result_type.h"
Expand Down Expand Up @@ -160,6 +161,9 @@ void BackForwardCacheNotUsed(
const BackForwardCacheCanStoreTreeResult* tree_result);

void DidActivatePrerender(const NavigationRequest& nav_request);
void DidCancelPrerender(const GURL& prerendering_url,
FrameTreeNode* ftn,
PrerenderHost::FinalStatus status);

void OnSignedExchangeReceived(
FrameTreeNode* frame_tree_node,
Expand Down
85 changes: 85 additions & 0 deletions content/browser/devtools/protocol/page_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1423,6 +1423,80 @@ Page::BackForwardCacheNotRestoredReason NotRestoredReasonToProtocol(
}
}

Page::PrerenderFinalStatus PrerenderFinalStatusToProtocol(
PrerenderHost::FinalStatus feature) {
switch (feature) {
case PrerenderHost::FinalStatus::kActivated:
return Page::PrerenderFinalStatusEnum::Activated;
case PrerenderHost::FinalStatus::kAudioOutputDeviceRequested:
return Page::PrerenderFinalStatusEnum::AudioOutputDeviceRequested;
case PrerenderHost::FinalStatus::kBlockedByClient:
return Page::PrerenderFinalStatusEnum::BlockedByClient;
case PrerenderHost::FinalStatus::kCancelAllHostsForTesting:
return Page::PrerenderFinalStatusEnum::CancelAllHostsForTesting;
case PrerenderHost::FinalStatus::kClientCertRequested:
return Page::PrerenderFinalStatusEnum::ClientCertRequested;
case PrerenderHost::FinalStatus::kCrossOriginNavigation:
return Page::PrerenderFinalStatusEnum::CrossOriginNavigation;
case PrerenderHost::FinalStatus::kCrossOriginRedirect:
return Page::PrerenderFinalStatusEnum::CrossOriginRedirect;
case PrerenderHost::FinalStatus::kDestroyed:
return Page::PrerenderFinalStatusEnum::Destroyed;
case PrerenderHost::FinalStatus::kDidFailLoad:
return Page::PrerenderFinalStatusEnum::DidFailLoad;
case PrerenderHost::FinalStatus::kDownload:
return Page::PrerenderFinalStatusEnum::Download;
case PrerenderHost::FinalStatus::kEmbedderTriggeredAndCrossOriginRedirected:
return Page::PrerenderFinalStatusEnum::
EmbedderTriggeredAndCrossOriginRedirected;
case PrerenderHost::FinalStatus::kEmbedderTriggeredAndDestroyed:
return Page::PrerenderFinalStatusEnum::EmbedderTriggeredAndDestroyed;
case PrerenderHost::FinalStatus::kEmbedderTriggeredAndSameOriginRedirected:
return Page::PrerenderFinalStatusEnum::
EmbedderTriggeredAndSameOriginRedirected;
case PrerenderHost::FinalStatus::kInProgressNavigation:
return Page::PrerenderFinalStatusEnum::InProgressNavigation;
case PrerenderHost::FinalStatus::kInvalidSchemeNavigation:
return Page::PrerenderFinalStatusEnum::InvalidSchemeNavigation;
case PrerenderHost::FinalStatus::kInvalidSchemeRedirect:
return Page::PrerenderFinalStatusEnum::InvalidSchemeRedirect;
case PrerenderHost::FinalStatus::kLoginAuthRequested:
return Page::PrerenderFinalStatusEnum::LoginAuthRequested;
case PrerenderHost::FinalStatus::kLowEndDevice:
return Page::PrerenderFinalStatusEnum::LowEndDevice;
case PrerenderHost::FinalStatus::kMainFrameNavigation:
return Page::PrerenderFinalStatusEnum::MainFrameNavigation;
case PrerenderHost::FinalStatus::kMaxNumOfRunningPrerendersExceeded:
return Page::PrerenderFinalStatusEnum::MaxNumOfRunningPrerendersExceeded;
case PrerenderHost::FinalStatus::kMixedContent:
return Page::PrerenderFinalStatusEnum::MixedContent;
case PrerenderHost::FinalStatus::kMojoBinderPolicy:
return Page::PrerenderFinalStatusEnum::MojoBinderPolicy;
case PrerenderHost::FinalStatus::kNavigationBadHttpStatus:
return Page::PrerenderFinalStatusEnum::NavigationBadHttpStatus;
case PrerenderHost::FinalStatus::kNavigationNotCommitted:
return Page::PrerenderFinalStatusEnum::NavigationNotCommitted;
case PrerenderHost::FinalStatus::kNavigationRequestBlockedByCsp:
return Page::PrerenderFinalStatusEnum::NavigationRequestBlockedByCsp;
case PrerenderHost::FinalStatus::kNavigationRequestNetworkError:
return Page::PrerenderFinalStatusEnum::NavigationRequestNetworkError;
case PrerenderHost::FinalStatus::kRendererProcessCrashed:
return Page::PrerenderFinalStatusEnum::RendererProcessCrashed;
case PrerenderHost::FinalStatus::kRendererProcessKilled:
return Page::PrerenderFinalStatusEnum::RendererProcessKilled;
case PrerenderHost::FinalStatus::kSslCertificateError:
return Page::PrerenderFinalStatusEnum::SslCertificateError;
case PrerenderHost::FinalStatus::kStop:
return Page::PrerenderFinalStatusEnum::CancelAllHostsForTesting;
case PrerenderHost::FinalStatus::kTriggerBackgrounded:
return Page::PrerenderFinalStatusEnum::TriggerBackgrounded;
case PrerenderHost::FinalStatus::kTriggerDestroyed:
return Page::PrerenderFinalStatusEnum::TriggerDestroyed;
case PrerenderHost::FinalStatus::kUaChangeRequiresReload:
return Page::PrerenderFinalStatusEnum::UaChangeRequiresReload;
}
}

using blink::scheduler::WebSchedulerTrackedFeature;
Page::BackForwardCacheNotRestoredReason BlocklistedFeatureToProtocol(
WebSchedulerTrackedFeature feature) {
Expand Down Expand Up @@ -1879,6 +1953,17 @@ void PageHandler::DidActivatePrerender(const NavigationRequest& nav_request) {
Page::PrerenderFinalStatusEnum::Activated);
}

void PageHandler::DidCancelPrerender(const GURL& prerendering_url,
const std::string& initiating_frame_id,
PrerenderHost::FinalStatus status) {
if (!enabled_)
return;
DCHECK_NE(status, PrerenderHost::FinalStatus::kActivated);
frontend_->PrerenderAttemptCompleted(initiating_frame_id,
prerendering_url.spec(),
PrerenderFinalStatusToProtocol(status));
}

bool PageHandler::ShouldBypassCSP() {
return enabled_ && bypass_csp_;
}
Expand Down
4 changes: 4 additions & 0 deletions content/browser/devtools/protocol/page_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "content/browser/devtools/protocol/devtools_domain_handler.h"
#include "content/browser/devtools/protocol/devtools_download_manager_delegate.h"
#include "content/browser/devtools/protocol/page.h"
#include "content/browser/prerender/prerender_host.h"
#include "content/browser/renderer_host/back_forward_cache_impl.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/javascript_dialog_manager.h"
Expand Down Expand Up @@ -110,6 +111,9 @@ class PageHandler : public DevToolsDomainHandler,
const BackForwardCacheCanStoreTreeResult* tree_result);

void DidActivatePrerender(const NavigationRequest& nav_request);
void DidCancelPrerender(const GURL& prerendering_url,
const std::string& initiating_frame_id,
PrerenderHost::FinalStatus status);

Response Enable() override;
Response Disable() override;
Expand Down
3 changes: 3 additions & 0 deletions content/browser/prerender/prerender_attributes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ PrerenderAttributes::PrerenderAttributes(
const GURL& initiator_url,
int initiator_process_id,
absl::optional<blink::LocalFrameToken> initiator_frame_token,
int initiator_frame_tree_node_id,
ukm::SourceId initiator_ukm_id,
ui::PageTransition transition_type,
absl::optional<base::RepeatingCallback<bool(const GURL&)>>
Expand All @@ -36,6 +37,7 @@ PrerenderAttributes::PrerenderAttributes(
initiator_url(initiator_url),
initiator_process_id(initiator_process_id),
initiator_frame_token(std::move(initiator_frame_token)),
initiator_frame_tree_node_id(initiator_frame_tree_node_id),
initiator_ukm_id(initiator_ukm_id),
transition_type(transition_type),
url_match_predicate(std::move(url_match_predicate)) {}
Expand All @@ -54,6 +56,7 @@ PrerenderAttributes::PrerenderAttributes(PrerenderAttributes&& attributes)
initiator_url(attributes.initiator_url),
initiator_process_id(attributes.initiator_process_id),
initiator_frame_token(attributes.initiator_frame_token),
initiator_frame_tree_node_id(attributes.initiator_frame_tree_node_id),
initiator_ukm_id(attributes.initiator_ukm_id),
transition_type(attributes.transition_type),
url_match_predicate(attributes.url_match_predicate) {}
Expand Down
5 changes: 5 additions & 0 deletions content/browser/prerender/prerender_attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct CONTENT_EXPORT PrerenderAttributes {
const GURL& initiator_url,
int initiator_process_id,
absl::optional<blink::LocalFrameToken> initiator_frame_token,
int initiator_frame_tree_node_id,
ukm::SourceId initiator_ukm_id,
ui::PageTransition transition_type,
absl::optional<base::RepeatingCallback<bool(const GURL&)>>
Expand Down Expand Up @@ -64,6 +65,10 @@ struct CONTENT_EXPORT PrerenderAttributes {
// This is absl::nullopt when prerendering is initiated by the browser.
absl::optional<blink::LocalFrameToken> initiator_frame_token;

// This is RenderFrameHost::kNoFrameTreeNodeId when prerendering is initiated
// by the browser.
int initiator_frame_tree_node_id;

// This is ukm::kInvalidSourceId when prerendering is initiated by the
// browser.
ukm::SourceId initiator_ukm_id;
Expand Down
10 changes: 10 additions & 0 deletions content/browser/prerender/prerender_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,16 @@ void PrerenderHost::RecordFinalStatus(FinalStatus status,
RecordPrerenderHostFinalStatus(status, trigger_type(),
embedder_histogram_suffix(), initiator_ukm_id,
prerendered_ukm_id);

// The kActivated case is recorded in `PrerenderHost::Activate`. Browser
// initiated prerendering doesn't report cancellation reasons to the DevTools
// as it doesn't have the initiator frame associated with DevTools agents.
if (final_status_ != FinalStatus::kActivated && !IsBrowserInitiated()) {
auto* ftn = FrameTreeNode::GloballyFindByID(initiator_frame_tree_node_id());
DCHECK(ftn);
devtools_instrumentation::DidCancelPrerender(attributes_.prerendering_url,
ftn, status);
}
}

const GURL& PrerenderHost::GetInitialUrl() const {
Expand Down
4 changes: 4 additions & 0 deletions content/browser/prerender/prerender_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ class CONTENT_EXPORT PrerenderHost : public WebContentsObserver {

int frame_tree_node_id() const { return frame_tree_node_id_; }

int initiator_frame_tree_node_id() const {
return attributes_.initiator_frame_tree_node_id;
}

bool is_ready_for_activation() const { return is_ready_for_activation_; }

const absl::optional<FinalStatus>& final_status() const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ PrerenderAttributes GeneratePrerenderAttributes(
url, trigger_type, embedder_histogram_suffix, Referrer(),
rfh->GetLastCommittedOrigin(), rfh->GetLastCommittedURL(),
rfh->GetProcess()->GetID(), rfh->GetFrameToken(),
rfh->GetFrameTreeNodeId(),
trigger_type == PrerenderTriggerType::kSpeculationRule
? rfh->GetPageUkmSourceId()
: ukm::kInvalidSourceId,
Expand Down
7 changes: 4 additions & 3 deletions content/browser/prerender/prerender_host_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ PrerenderAttributes GeneratePrerenderAttributes(const GURL& url,
/*embedder_histogram_suffix=*/"", Referrer(),
rfh->GetLastCommittedOrigin(), rfh->GetLastCommittedURL(),
rfh->GetProcess()->GetID(), rfh->GetFrameToken(),
rfh->GetPageUkmSourceId(), ui::PAGE_TRANSITION_LINK,
rfh->GetFrameTreeNodeId(), rfh->GetPageUkmSourceId(),
ui::PAGE_TRANSITION_LINK,
/*url_match_predicate=*/absl::nullopt);
}

Expand All @@ -130,8 +131,8 @@ PrerenderAttributes GeneratePrerenderAttributesWithPredicate(
/*embedder_histogram_suffix=*/"", Referrer(),
rfh->GetLastCommittedOrigin(), rfh->GetLastCommittedURL(),
rfh->GetProcess()->GetID(), rfh->GetFrameToken(),
rfh->GetPageUkmSourceId(), ui::PAGE_TRANSITION_LINK,
std::move(url_match_predicate));
rfh->GetFrameTreeNodeId(), rfh->GetPageUkmSourceId(),
ui::PAGE_TRANSITION_LINK, std::move(url_match_predicate));
}

class TestWebContentsDelegate : public WebContentsDelegate {
Expand Down
3 changes: 2 additions & 1 deletion content/browser/speculation_rules/speculation_host_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ void SpeculationHostImpl::ProcessCandidatesForPrerender(
/*embedder_histogram_suffix=*/"", Referrer(*(it->referrer)),
rfhi->GetLastCommittedOrigin(), rfhi->GetLastCommittedURL(),
rfhi->GetProcess()->GetID(), rfhi->GetFrameToken(),
rfhi->GetPageUkmSourceId(), ui::PAGE_TRANSITION_LINK,
rfhi->GetFrameTreeNodeId(), rfhi->GetPageUkmSourceId(),
ui::PAGE_TRANSITION_LINK,
/*url_match_predicate=*/absl::nullopt),
*web_contents);
if (prerender_host_id != RenderFrameHost::kNoFrameTreeNodeId)
Expand Down
5 changes: 3 additions & 2 deletions content/browser/web_contents/web_contents_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9364,8 +9364,9 @@ std::unique_ptr<PrerenderHandle> WebContentsImpl::StartPrerendering(
prerendering_url, trigger_type, embedder_histogram_suffix,
content::Referrer(), /*initiator_origin=*/absl::nullopt, prerendering_url,
content::ChildProcessHost::kInvalidUniqueID,
/*initiator_frame_token=*/absl::nullopt, ukm::kInvalidSourceId,
page_transition, url_match_predicate);
/*initiator_frame_token=*/absl::nullopt,
/*initiator_frame_tree_node_id=*/RenderFrameHost::kNoFrameTreeNodeId,
ukm::kInvalidSourceId, page_transition, url_match_predicate);
int frame_tree_node_id =
GetPrerenderHostRegistry()->CreateAndStartHost(attributes, *this);

Expand Down
1 change: 1 addition & 0 deletions content/test/test_web_contents.cc
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ int TestWebContents::AddPrerender(const GURL& url) {
rfhi->GetLastCommittedOrigin(),
rfhi->GetLastCommittedURL(),
rfhi->GetProcess()->GetID(), rfhi->GetFrameToken(),
rfhi->GetFrameTreeNodeId(),
rfhi->GetPageUkmSourceId(), ui::PAGE_TRANSITION_LINK,
/*url_match_predicate=*/absl::nullopt),
*this);
Expand Down
32 changes: 32 additions & 0 deletions third_party/blink/public/devtools_protocol/browser_protocol.pdl
Original file line number Diff line number Diff line change
Expand Up @@ -8319,6 +8319,38 @@ domain Page
type PrerenderFinalStatus extends string
enum
Activated
Destroyed
LowEndDevice
CrossOriginRedirect
CrossOriginNavigation
InvalidSchemeRedirect
InvalidSchemeNavigation
InProgressNavigation
NavigationRequestBlockedByCsp
MainFrameNavigation
MojoBinderPolicy
RendererProcessCrashed
RendererProcessKilled
Download
TriggerDestroyed
NavigationNotCommitted
NavigationBadHttpStatus
ClientCertRequested
NavigationRequestNetworkError
MaxNumOfRunningPrerendersExceeded
CancelAllHostsForTesting
DidFailLoad
Stop
SslCertificateError
LoginAuthRequested
UaChangeRequiresReload
BlockedByClient
AudioOutputDeviceRequested
MixedContent
TriggerBackgrounded
EmbedderTriggeredAndSameOriginRedirected
EmbedderTriggeredAndCrossOriginRedirected
EmbedderTriggeredAndDestroyed

# Fired when a prerender attempt is completed.
event prerenderAttemptCompleted
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// This test makes sure that the inspector is notified of the final status when
// prerendering is cancelled for some reasons. To emulate the cancellation,
// this test navigates the prerender trigger page to an unrelated page so that
// prerendering is cancelled with the `Destroyed` final status.
(async function(testRunner) {
const {page, session, dp} = await testRunner.startBlank(
`Test that prerender navigations report the final status`);
await dp.Page.enable();

// Navigate to speculation rules Prerender Page.
await page.navigate('resources/simple-prerender.html');
page.navigate('resources/empty.html?navigateaway');
const statusReport = await dp.Page.oncePrerenderAttemptCompleted();
testRunner.log(statusReport, '', ['initiatingFrameId', 'sessionId']);
testRunner.completeTest();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Test that prerender navigations report the final status
{
method : Page.prerenderAttemptCompleted
params : {
finalStatus : TriggerDestroyed
initiatingFrameId : <string>
prerenderingUrl : http://127.0.0.1:8000/inspector-protocol/prerender/resources/empty.html
}
sessionId : <string>
}

0 comments on commit 286e2eb

Please sign in to comment.