Commit 8f6a95d8 authored by Hiroki Nakagawa's avatar Hiroki Nakagawa Committed by Chromium LUCI CQ

Prerender: Avoid starting navigation for prerendering when it is duplicate

This CL avoids starting navigation for prerendering when it already
started for the same URL.

To do that, this moves PrerenderHost::StartNavigation() call into
PrerenderHostRegistry::RegisterHost(). This doesn't change behavior
around networking. Even before this change, the duplicate navigation
didn't issue a network request because PrerenderHost was destroyed right
after PrerenderHost::StartNavigation() was called. The browser tests
make sure this behavior.

In addition to that, this change renames RegisterHost() to
CreateAndStartHost() and then moves the PrerenderHost creation into the
function for code cleanup.

Bug: 1132746
Change-Id: Ibc1d51921d845c2746a1a0caca27e08e77256699
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2567514Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarTakashi Toyoshima <toyoshim@chromium.org>
Commit-Queue: Hiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833583}
parent 71ad7332
...@@ -18,16 +18,29 @@ PrerenderHostRegistry::PrerenderHostRegistry() { ...@@ -18,16 +18,29 @@ PrerenderHostRegistry::PrerenderHostRegistry() {
PrerenderHostRegistry::~PrerenderHostRegistry() = default; PrerenderHostRegistry::~PrerenderHostRegistry() = default;
void PrerenderHostRegistry::RegisterHost( void PrerenderHostRegistry::CreateAndStartHost(
const GURL& prerendering_url, blink::mojom::PrerenderAttributesPtr attributes,
std::unique_ptr<PrerenderHost> prerender_host) { const GlobalFrameRoutingId& initiator_render_frame_host_id,
const url::Origin& initiator_origin) {
DCHECK(attributes);
// Ignore prerendering requests for the same URL. // Ignore prerendering requests for the same URL.
if (base::Contains(prerender_host_by_url_, prerendering_url)) { const GURL prerendering_url = attributes->url;
// TODO(https://crbug.com/1132746): In addition to this check, we may have if (base::Contains(prerender_host_by_url_, prerendering_url))
// to avoid duplicate requests in the PrerenderHost layer so that the
// prerender host doesn't start navigation for the duplicate requests.
return; return;
}
auto prerender_host = std::make_unique<PrerenderHost>(
std::move(attributes), initiator_render_frame_host_id, initiator_origin);
// Start prerendering before adding the host to the map to make sure
// navigation for prerendering doesn't select itself.
// TODO(https://crbug.com/1132746): SelectForNavigation() should avoid select
// a prerender host when the current NavigationRequest is for prerendering
// regardless of the calling order of StartPrerendering(). This modification
// would require the proper `is_prerendering` state in NavigationRequest,
// RenderFrameHostImpl, or somewhere else.
prerender_host->StartPrerendering();
prerender_host_by_url_[prerendering_url] = std::move(prerender_host); prerender_host_by_url_[prerendering_url] = std::move(prerender_host);
} }
......
...@@ -8,7 +8,10 @@ ...@@ -8,7 +8,10 @@
#include <map> #include <map>
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/public/browser/global_routing_id.h"
#include "third_party/blink/public/mojom/prerender/prerender.mojom.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/origin.h"
namespace content { namespace content {
...@@ -19,7 +22,7 @@ class PrerenderHost; ...@@ -19,7 +22,7 @@ class PrerenderHost;
// to navigation code for activating prerendered contents. This is created and // to navigation code for activating prerendered contents. This is created and
// owned by StoragePartitionImpl. // owned by StoragePartitionImpl.
// //
// TODO(https://crbug.com/1132746): Once the Prerender2 is migrated to the // TODO(https://crbug.com/1154501): Once the Prerender2 is migrated to the
// MPArch, it would be more natural to make PrerenderHostRegistry scoped to // MPArch, it would be more natural to make PrerenderHostRegistry scoped to
// WebContents, that is, WebContents will own this. // WebContents, that is, WebContents will own this.
class CONTENT_EXPORT PrerenderHostRegistry { class CONTENT_EXPORT PrerenderHostRegistry {
...@@ -32,9 +35,11 @@ class CONTENT_EXPORT PrerenderHostRegistry { ...@@ -32,9 +35,11 @@ class CONTENT_EXPORT PrerenderHostRegistry {
PrerenderHostRegistry(PrerenderHostRegistry&&) = delete; PrerenderHostRegistry(PrerenderHostRegistry&&) = delete;
PrerenderHostRegistry& operator=(PrerenderHostRegistry&&) = delete; PrerenderHostRegistry& operator=(PrerenderHostRegistry&&) = delete;
// Registers the host for `prerendering_url`. // Creates and starts a host for `prerendering_url`.
void RegisterHost(const GURL& prerendering_url, void CreateAndStartHost(
std::unique_ptr<PrerenderHost> prerender_host); blink::mojom::PrerenderAttributesPtr attributes,
const GlobalFrameRoutingId& initiator_render_frame_host_id,
const url::Origin& initiator_origin);
// Destroys the host registered for `prerendering_url`. // Destroys the host registered for `prerendering_url`.
void AbandonHost(const GURL& prerendering_url); void AbandonHost(const GURL& prerendering_url);
......
...@@ -54,7 +54,7 @@ class PrerenderHostRegistryTest : public RenderViewHostImplTestHarness { ...@@ -54,7 +54,7 @@ class PrerenderHostRegistryTest : public RenderViewHostImplTestHarness {
std::unique_ptr<TestBrowserContext> browser_context_; std::unique_ptr<TestBrowserContext> browser_context_;
}; };
TEST_F(PrerenderHostRegistryTest, RegisterHost) { TEST_F(PrerenderHostRegistryTest, CreateAndStartHost) {
std::unique_ptr<TestWebContents> web_contents = std::unique_ptr<TestWebContents> web_contents =
CreateWebContents(GURL("https://example.com/")); CreateWebContents(GURL("https://example.com/"));
RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame(); RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame();
...@@ -63,26 +63,23 @@ TEST_F(PrerenderHostRegistryTest, RegisterHost) { ...@@ -63,26 +63,23 @@ TEST_F(PrerenderHostRegistryTest, RegisterHost) {
const GURL kPrerenderingUrl("https://example.com/next"); const GURL kPrerenderingUrl("https://example.com/next");
auto attributes = blink::mojom::PrerenderAttributes::New(); auto attributes = blink::mojom::PrerenderAttributes::New();
attributes->url = kPrerenderingUrl; attributes->url = kPrerenderingUrl;
auto prerender_host = std::make_unique<PrerenderHost>(
std::move(attributes), render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
PrerenderHost* prerender_host_rawptr = prerender_host.get();
PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
registry->CreateAndStartHost(std::move(attributes),
registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host)); render_frame_host->GetGlobalFrameRoutingId(),
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), render_frame_host->GetLastCommittedOrigin());
prerender_host_rawptr); PrerenderHost* prerender_host =
registry->FindHostByUrlForTesting(kPrerenderingUrl);
// Artificially finish navigation to make the prerender host ready to activate // Artificially finish navigation to make the prerender host ready to activate
// the prerendered page. // the prerendered page.
prerender_host_rawptr->DidFinishNavigation(nullptr); prerender_host->DidFinishNavigation(nullptr);
EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl)); EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl));
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr); EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
} }
TEST_F(PrerenderHostRegistryTest, RegisterHostForSameURL) { TEST_F(PrerenderHostRegistryTest, CreateAndStartHostForSameURL) {
std::unique_ptr<TestWebContents> web_contents = std::unique_ptr<TestWebContents> web_contents =
CreateWebContents(GURL("https://example.com/")); CreateWebContents(GURL("https://example.com/"));
RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame(); RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame();
...@@ -92,41 +89,34 @@ TEST_F(PrerenderHostRegistryTest, RegisterHostForSameURL) { ...@@ -92,41 +89,34 @@ TEST_F(PrerenderHostRegistryTest, RegisterHostForSameURL) {
auto attributes1 = blink::mojom::PrerenderAttributes::New(); auto attributes1 = blink::mojom::PrerenderAttributes::New();
attributes1->url = kPrerenderingUrl; attributes1->url = kPrerenderingUrl;
auto prerender_host1 = std::make_unique<PrerenderHost>(
std::move(attributes1), render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
PrerenderHost* prerender_host1_rawptr = prerender_host1.get();
auto attributes2 = blink::mojom::PrerenderAttributes::New(); auto attributes2 = blink::mojom::PrerenderAttributes::New();
attributes2->url = kPrerenderingUrl; attributes2->url = kPrerenderingUrl;
auto prerender_host2 = std::make_unique<PrerenderHost>(
std::move(attributes2), render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
PrerenderHost* prerender_host2_rawptr = prerender_host2.get();
PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
registry->CreateAndStartHost(std::move(attributes1),
render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
PrerenderHost* prerender_host1 =
registry->FindHostByUrlForTesting(kPrerenderingUrl);
registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host1)); // Start the prerender host for the same URL. This second host should be
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl),
prerender_host1_rawptr);
// Register the prerender host for the same URL. This second host should be
// ignored, and the first host should still be findable. // ignored, and the first host should still be findable.
registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host2)); registry->CreateAndStartHost(std::move(attributes2),
render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl),
prerender_host1_rawptr); prerender_host1);
EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl),
prerender_host2_rawptr);
// Artificially finish navigation to make the prerender host ready to activate // Artificially finish navigation to make the prerender host ready to activate
// the prerendered page. // the prerendered page.
prerender_host1_rawptr->DidFinishNavigation(nullptr); prerender_host1->DidFinishNavigation(nullptr);
EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl)); EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl));
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr); EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
} }
TEST_F(PrerenderHostRegistryTest, RegisterHostForDifferentURLs) { TEST_F(PrerenderHostRegistryTest, CreateAndStartHostForDifferentURLs) {
std::unique_ptr<TestWebContents> web_contents = std::unique_ptr<TestWebContents> web_contents =
CreateWebContents(GURL("https://example.com/")); CreateWebContents(GURL("https://example.com/"));
RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame(); RenderFrameHostImpl* render_frame_host = web_contents->GetMainFrame();
...@@ -135,40 +125,34 @@ TEST_F(PrerenderHostRegistryTest, RegisterHostForDifferentURLs) { ...@@ -135,40 +125,34 @@ TEST_F(PrerenderHostRegistryTest, RegisterHostForDifferentURLs) {
const GURL kPrerenderingUrl1("https://example.com/next1"); const GURL kPrerenderingUrl1("https://example.com/next1");
auto attributes1 = blink::mojom::PrerenderAttributes::New(); auto attributes1 = blink::mojom::PrerenderAttributes::New();
attributes1->url = kPrerenderingUrl1; attributes1->url = kPrerenderingUrl1;
auto prerender_host1 = std::make_unique<PrerenderHost>(
std::move(attributes1), render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
PrerenderHost* prerender_host1_rawptr = prerender_host1.get();
const GURL kPrerenderingUrl2("https://example.com/next2"); const GURL kPrerenderingUrl2("https://example.com/next2");
auto attributes2 = blink::mojom::PrerenderAttributes::New(); auto attributes2 = blink::mojom::PrerenderAttributes::New();
attributes2->url = kPrerenderingUrl2; attributes2->url = kPrerenderingUrl2;
auto prerender_host2 = std::make_unique<PrerenderHost>(
std::move(attributes2), render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
PrerenderHost* prerender_host2_rawptr = prerender_host2.get();
PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
registry->CreateAndStartHost(std::move(attributes1),
registry->RegisterHost(kPrerenderingUrl1, std::move(prerender_host1)); render_frame_host->GetGlobalFrameRoutingId(),
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl1), render_frame_host->GetLastCommittedOrigin());
prerender_host1_rawptr); registry->CreateAndStartHost(std::move(attributes2),
registry->RegisterHost(kPrerenderingUrl2, std::move(prerender_host2)); render_frame_host->GetGlobalFrameRoutingId(),
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2), render_frame_host->GetLastCommittedOrigin());
prerender_host2_rawptr); PrerenderHost* prerender_host1 =
registry->FindHostByUrlForTesting(kPrerenderingUrl1);
PrerenderHost* prerender_host2 =
registry->FindHostByUrlForTesting(kPrerenderingUrl2);
// Artificially finish navigation to make the prerender hosts ready to // Artificially finish navigation to make the prerender hosts ready to
// activate the prerendered pages. // activate the prerendered pages.
prerender_host1_rawptr->DidFinishNavigation(nullptr); prerender_host1->DidFinishNavigation(nullptr);
prerender_host2_rawptr->DidFinishNavigation(nullptr); prerender_host2->DidFinishNavigation(nullptr);
// Select the first host. // Select the first host.
EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl1)); EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl1));
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr); EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl1), nullptr);
// The second host should still be findable. // The second host should still be findable.
registry->RegisterHost(kPrerenderingUrl2, std::move(prerender_host2));
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2), EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl2),
prerender_host2_rawptr); prerender_host2);
// Select the second host. // Select the second host.
EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl2)); EXPECT_TRUE(registry->SelectForNavigation(kPrerenderingUrl2));
...@@ -184,20 +168,17 @@ TEST_F(PrerenderHostRegistryTest, SelectForNavigationBeforeReadyForActivation) { ...@@ -184,20 +168,17 @@ TEST_F(PrerenderHostRegistryTest, SelectForNavigationBeforeReadyForActivation) {
const GURL kPrerenderingUrl("https://example.com/next"); const GURL kPrerenderingUrl("https://example.com/next");
auto attributes = blink::mojom::PrerenderAttributes::New(); auto attributes = blink::mojom::PrerenderAttributes::New();
attributes->url = kPrerenderingUrl; attributes->url = kPrerenderingUrl;
auto prerender_host = std::make_unique<PrerenderHost>(
std::move(attributes), render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
PrerenderHost* prerender_host_rawptr = prerender_host.get();
PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
registry->CreateAndStartHost(std::move(attributes),
registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host)); render_frame_host->GetGlobalFrameRoutingId(),
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), render_frame_host->GetLastCommittedOrigin());
prerender_host_rawptr); PrerenderHost* prerender_host =
registry->FindHostByUrlForTesting(kPrerenderingUrl);
// The prerender host is not ready for activation yet, so the registry // The prerender host is not ready for activation yet, so the registry
// shouldn't select the host and instead should abandon it. // shouldn't select the host and instead should abandon it.
ASSERT_FALSE(prerender_host_rawptr->is_ready_for_activation()); ASSERT_FALSE(prerender_host->is_ready_for_activation());
EXPECT_FALSE(registry->SelectForNavigation(kPrerenderingUrl)); EXPECT_FALSE(registry->SelectForNavigation(kPrerenderingUrl));
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr); EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
} }
...@@ -211,16 +192,12 @@ TEST_F(PrerenderHostRegistryTest, AbandonHost) { ...@@ -211,16 +192,12 @@ TEST_F(PrerenderHostRegistryTest, AbandonHost) {
const GURL kPrerenderingUrl("https://example.com/next"); const GURL kPrerenderingUrl("https://example.com/next");
auto attributes = blink::mojom::PrerenderAttributes::New(); auto attributes = blink::mojom::PrerenderAttributes::New();
attributes->url = kPrerenderingUrl; attributes->url = kPrerenderingUrl;
auto prerender_host = std::make_unique<PrerenderHost>(
std::move(attributes), render_frame_host->GetGlobalFrameRoutingId(),
render_frame_host->GetLastCommittedOrigin());
PrerenderHost* prerender_host_rawptr = prerender_host.get();
PrerenderHostRegistry* registry = GetPrerenderHostRegistry(); PrerenderHostRegistry* registry = GetPrerenderHostRegistry();
registry->CreateAndStartHost(std::move(attributes),
registry->RegisterHost(kPrerenderingUrl, std::move(prerender_host)); render_frame_host->GetGlobalFrameRoutingId(),
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), render_frame_host->GetLastCommittedOrigin());
prerender_host_rawptr); EXPECT_NE(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
registry->AbandonHost(kPrerenderingUrl); registry->AbandonHost(kPrerenderingUrl);
EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr); EXPECT_EQ(registry->FindHostByUrlForTesting(kPrerenderingUrl), nullptr);
......
...@@ -49,17 +49,10 @@ void PrerenderProcessor::Start( ...@@ -49,17 +49,10 @@ void PrerenderProcessor::Start(
prerendering_url_ = attributes->url; prerendering_url_ = attributes->url;
// Start prerendering. GetPrerenderHostRegistry().CreateAndStartHost(
auto prerender_host = std::make_unique<PrerenderHost>(
std::move(attributes), std::move(attributes),
initiator_render_frame_host_.GetGlobalFrameRoutingId(), initiator_render_frame_host_.GetGlobalFrameRoutingId(),
initiator_origin_); initiator_origin_);
prerender_host->StartPrerendering();
// Register the prerender host to PrerenderHostRegistry so that navigation can
// find this prerendered contents.
GetPrerenderHostRegistry().RegisterHost(prerendering_url_,
std::move(prerender_host));
} }
void PrerenderProcessor::Cancel() { void PrerenderProcessor::Cancel() {
......
...@@ -24,8 +24,8 @@ class RenderFrameHostImpl; ...@@ -24,8 +24,8 @@ class RenderFrameHostImpl;
// request (see comments on the mojom interface for details) and owned by the // request (see comments on the mojom interface for details) and owned by the
// initiator RenderFrameHostImpl's mojo::UniqueReceiverSet. // initiator RenderFrameHostImpl's mojo::UniqueReceiverSet.
// //
// When Start() is called from a renderer process, this instantiates a new // When Start() is called from a renderer process, this asks
// PrerenderHost, and forwards the request to the prerender host. // PrerenderHostRegistry to create a PrerenderHost and start prerendering.
class CONTENT_EXPORT PrerenderProcessor final class CONTENT_EXPORT PrerenderProcessor final
: public blink::mojom::PrerenderProcessor { : public blink::mojom::PrerenderProcessor {
public: public:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment