Commit f39506a8 authored by tburkard@chromium.org's avatar tburkard@chromium.org

For prerendering, keep track of all the intermediate redirects, and hook into

the provisional load messages to catch an earlier time to substitute in the
prerendered page.
BUG=none
TEST=search for techcrunch and notice how the preloaded techcrunch.com is used despite the redirect
Review URL: http://codereview.chromium.org/6171007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71721 0039d316-1c4b-4281-b951-d872f2087c98
parent 7837be66
......@@ -16,18 +16,26 @@
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/view_types.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/render_messages_params.h"
#include "gfx/rect.h"
PrerenderContents::PrerenderContents(PrerenderManager* prerender_manager,
Profile* profile,
const GURL& url)
const GURL& url,
const std::vector<GURL>& alias_urls)
: prerender_manager_(prerender_manager),
render_view_host_(NULL),
prerender_url_(url),
profile_(profile),
page_id_(0) {
DCHECK(prerender_manager != NULL);
AddAliasURL(prerender_url_);
for (std::vector<GURL>::const_iterator it = alias_urls.begin();
it != alias_urls.end();
++it) {
AddAliasURL(*it);
}
}
void PrerenderContents::StartPrerendering() {
......@@ -87,6 +95,8 @@ void PrerenderContents::DidNavigate(
navigate_params_.reset(p);
url_ = params.url;
AddAliasURL(url_);
}
void PrerenderContents::UpdateTitle(RenderViewHost* render_view_host,
......@@ -215,3 +225,39 @@ void PrerenderContents::ShowCreatedWidget(int route_id,
void PrerenderContents::ShowCreatedFullscreenWidget(int route_id) {
NOTIMPLEMENTED();
}
bool PrerenderContents::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
bool message_is_ok = true;
IPC_BEGIN_MESSAGE_MAP_EX(PrerenderContents, message, message_is_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartProvisionalLoadForFrame,
OnDidStartProvisionalLoadForFrame)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidRedirectProvisionalLoad,
OnDidRedirectProvisionalLoad)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
return handled;
}
void PrerenderContents::OnDidStartProvisionalLoadForFrame(int64 frame_id,
bool is_main_frame,
const GURL& url) {
if (is_main_frame)
AddAliasURL(url);
}
void PrerenderContents::OnDidRedirectProvisionalLoad(int32 page_id,
const GURL& source_url,
const GURL& target_url) {
AddAliasURL(target_url);
}
void PrerenderContents::AddAliasURL(const GURL& url) {
alias_urls_.push_back(url);
}
bool PrerenderContents::MatchesURL(const GURL& url) const {
return std::find(alias_urls_.begin(), alias_urls_.end(), url)
!= alias_urls_.end();
}
......@@ -37,7 +37,7 @@ class PrerenderContents : public RenderViewHostDelegate,
public JavaScriptAppModalDialogDelegate {
public:
PrerenderContents(PrerenderManager* prerender_manager, Profile* profile,
const GURL& url);
const GURL& url, const std::vector<GURL>& alias_urls);
virtual ~PrerenderContents();
virtual void StartPrerendering();
......@@ -52,6 +52,10 @@ class PrerenderContents : public RenderViewHostDelegate,
string16 title() const { return title_; }
int32 page_id() const { return page_id_; }
// Indicates whether this prerendered page can be used for the provided
// URL, i.e. whether there is a match.
bool MatchesURL(const GURL& url) const;
// RenderViewHostDelegate implementation.
virtual RenderViewHostDelegate::View* GetViewDelegate();
virtual const GURL& GetURL() const;
......@@ -133,7 +137,21 @@ class PrerenderContents : public RenderViewHostDelegate,
const std::string& value);
virtual void ClearInspectorSettings();
protected:
// from RenderViewHostDelegate.
virtual bool OnMessageReceived(const IPC::Message& message);
private:
// Message handlers.
void OnDidStartProvisionalLoadForFrame(int64 frame_id,
bool main_frame,
const GURL& url);
void OnDidRedirectProvisionalLoad(int32 page_id,
const GURL& source_url,
const GURL& target_url);
void AddAliasURL(const GURL& url);
// The prerender manager owning this object.
PrerenderManager* prerender_manager_;
......@@ -162,6 +180,11 @@ class PrerenderContents : public RenderViewHostDelegate,
GURL url_;
NotificationRegistrar registrar_;
// A vector of URLs that this prerendered page matches against.
// This array can contain more than element as a result of redirects,
// such as HTTP redirects or javascript redirects.
std::vector<GURL> alias_urls_;
DISALLOW_COPY_AND_ASSIGN(PrerenderContents);
};
......
......@@ -39,7 +39,8 @@ PrerenderManager::~PrerenderManager() {
}
}
void PrerenderManager::AddPreload(const GURL& url) {
void PrerenderManager::AddPreload(const GURL& url,
const std::vector<GURL>& alias_urls) {
DCHECK(CalledOnValidThread());
DeleteOldEntries();
// If the URL already exists in the set of preloaded URLs, don't do anything.
......@@ -49,7 +50,7 @@ void PrerenderManager::AddPreload(const GURL& url) {
if (it->url_ == url)
return;
}
PrerenderContentsData data(CreatePrerenderContents(url),
PrerenderContentsData data(CreatePrerenderContents(url, alias_urls),
GetCurrentTime(), url);
prerender_list_.push_back(data);
data.contents_->StartPrerendering();
......@@ -75,7 +76,8 @@ PrerenderContents* PrerenderManager::GetEntry(const GURL& url) {
for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
it != prerender_list_.end();
++it) {
if (it->url_ == url) {
PrerenderContents* pc = it->contents_;
if (pc->MatchesURL(url)) {
PrerenderContents* pc = it->contents_;
prerender_list_.erase(it);
return pc;
......@@ -129,6 +131,8 @@ bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const {
return (now - start < max_prerender_age_);
}
PrerenderContents* PrerenderManager::CreatePrerenderContents(const GURL& url) {
return new PrerenderContents(this, profile_, url);
PrerenderContents* PrerenderManager::CreatePrerenderContents(
const GURL& url,
const std::vector<GURL>& alias_urls) {
return new PrerenderContents(this, profile_, url, alias_urls);
}
......@@ -7,6 +7,7 @@
#pragma once
#include <list>
#include <vector>
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
......@@ -26,8 +27,9 @@ class PrerenderManager : public base::RefCounted<PrerenderManager>,
// Owned by a Profile object for the lifetime of the profile.
explicit PrerenderManager(Profile* profile);
// Preloads the URL supplied.
void AddPreload(const GURL& url);
// Preloads the URL supplied. alias_urls indicates URLs that redirect
// to the same URL to be preloaded.
void AddPreload(const GURL& url, const std::vector<GURL>& alias_urls);
// For a given TabContents that wants to navigate to the URL supplied,
// determines whether a preloaded version of the URL can be used,
......@@ -60,7 +62,9 @@ class PrerenderManager : public base::RefCounted<PrerenderManager>,
bool IsPrerenderElementFresh(const base::Time start) const;
void DeleteOldEntries();
virtual base::Time GetCurrentTime() const;
virtual PrerenderContents* CreatePrerenderContents(const GURL& url);
virtual PrerenderContents* CreatePrerenderContents(
const GURL& url,
const std::vector<GURL>& alias_urls);
Profile* profile_;
......
......@@ -13,7 +13,14 @@ namespace {
class DummyPrerenderContents : public PrerenderContents {
public:
DummyPrerenderContents(PrerenderManager* prerender_manager, const GURL& url)
: PrerenderContents(prerender_manager, NULL, url),
: PrerenderContents(prerender_manager, NULL, url,
std::vector<GURL>()),
has_started_(false) {
}
DummyPrerenderContents(PrerenderManager* prerender_manager, const GURL& url,
const std::vector<GURL> alias_urls)
: PrerenderContents(prerender_manager, NULL, url, alias_urls),
has_started_(false) {
}
......@@ -43,6 +50,11 @@ class TestPrerenderManager : public PrerenderManager {
next_pc_.reset(pc);
}
// Shorthand to add a simple preload with no aliases.
void AddSimplePreload(const GURL& url) {
AddPreload(url, std::vector<GURL>());
}
PrerenderContents* next_pc() { return next_pc_.get(); }
protected:
......@@ -54,7 +66,9 @@ class TestPrerenderManager : public PrerenderManager {
return time_;
}
virtual PrerenderContents* CreatePrerenderContents(const GURL& url) {
virtual PrerenderContents* CreatePrerenderContents(
const GURL& url,
const std::vector<GURL>& alias_urls) {
return next_pc_.release();
}
......@@ -83,7 +97,7 @@ TEST_F(PrerenderManagerTest, FoundTest) {
DummyPrerenderContents* pc =
new DummyPrerenderContents(prerender_manager_.get(), url);
prerender_manager_->SetNextPrerenderContents(pc);
prerender_manager_->AddPreload(url);
prerender_manager_->AddSimplePreload(url);
EXPECT_TRUE(pc->has_started());
EXPECT_EQ(pc, prerender_manager_->GetEntry(url));
delete pc;
......@@ -97,13 +111,13 @@ TEST_F(PrerenderManagerTest, DropSecondRequestTest) {
new DummyPrerenderContents(prerender_manager_.get(), url);
DummyPrerenderContents* null = NULL;
prerender_manager_->SetNextPrerenderContents(pc);
prerender_manager_->AddPreload(url);
prerender_manager_->AddSimplePreload(url);
EXPECT_EQ(null, prerender_manager_->next_pc());
EXPECT_TRUE(pc->has_started());
DummyPrerenderContents* pc1 =
new DummyPrerenderContents(prerender_manager_.get(), url);
prerender_manager_->SetNextPrerenderContents(pc1);
prerender_manager_->AddPreload(url);
prerender_manager_->AddSimplePreload(url);
EXPECT_EQ(pc1, prerender_manager_->next_pc());
EXPECT_FALSE(pc1->has_started());
EXPECT_EQ(pc, prerender_manager_->GetEntry(url));
......@@ -117,7 +131,7 @@ TEST_F(PrerenderManagerTest, ExpireTest) {
new DummyPrerenderContents(prerender_manager_.get(), url);
DummyPrerenderContents* null = NULL;
prerender_manager_->SetNextPrerenderContents(pc);
prerender_manager_->AddPreload(url);
prerender_manager_->AddSimplePreload(url);
EXPECT_EQ(null, prerender_manager_->next_pc());
EXPECT_TRUE(pc->has_started());
prerender_manager_->AdvanceTime(prerender_manager_->max_prerender_age()
......@@ -133,14 +147,14 @@ TEST_F(PrerenderManagerTest, DropOldestRequestTest) {
new DummyPrerenderContents(prerender_manager_.get(), url);
DummyPrerenderContents* null = NULL;
prerender_manager_->SetNextPrerenderContents(pc);
prerender_manager_->AddPreload(url);
prerender_manager_->AddSimplePreload(url);
EXPECT_EQ(null, prerender_manager_->next_pc());
EXPECT_TRUE(pc->has_started());
GURL url1("http://news.google.com/");
DummyPrerenderContents* pc1 =
new DummyPrerenderContents(prerender_manager_.get(), url1);
prerender_manager_->SetNextPrerenderContents(pc1);
prerender_manager_->AddPreload(url1);
prerender_manager_->AddSimplePreload(url1);
EXPECT_EQ(null, prerender_manager_->next_pc());
EXPECT_TRUE(pc1->has_started());
EXPECT_EQ(null, prerender_manager_->GetEntry(url));
......@@ -157,21 +171,21 @@ TEST_F(PrerenderManagerTest, TwoElementPrerenderTest) {
new DummyPrerenderContents(prerender_manager_.get(), url);
DummyPrerenderContents* null = NULL;
prerender_manager_->SetNextPrerenderContents(pc);
prerender_manager_->AddPreload(url);
prerender_manager_->AddSimplePreload(url);
EXPECT_EQ(null, prerender_manager_->next_pc());
EXPECT_TRUE(pc->has_started());
GURL url1("http://news.google.com/");
DummyPrerenderContents* pc1 =
new DummyPrerenderContents(prerender_manager_.get(), url1);
prerender_manager_->SetNextPrerenderContents(pc1);
prerender_manager_->AddPreload(url1);
prerender_manager_->AddSimplePreload(url1);
EXPECT_EQ(null, prerender_manager_->next_pc());
EXPECT_TRUE(pc1->has_started());
GURL url2("http://images.google.com/");
DummyPrerenderContents* pc2 =
new DummyPrerenderContents(prerender_manager_.get(), url2);
prerender_manager_->SetNextPrerenderContents(pc2);
prerender_manager_->AddPreload(url2);
prerender_manager_->AddSimplePreload(url2);
EXPECT_EQ(null, prerender_manager_->next_pc());
EXPECT_TRUE(pc2->has_started());
EXPECT_EQ(null, prerender_manager_->GetEntry(url));
......@@ -180,3 +194,26 @@ TEST_F(PrerenderManagerTest, TwoElementPrerenderTest) {
delete pc1;
delete pc2;
}
TEST_F(PrerenderManagerTest, AliasURLTest) {
GURL url("http://www.google.com/");
GURL alias_url1("http://www.google.com/index.html");
GURL alias_url2("http://google.com/");
GURL not_an_alias_url("http://google.com/index.html");
std::vector<GURL> alias_urls;
alias_urls.push_back(alias_url1);
alias_urls.push_back(alias_url2);
DummyPrerenderContents* pc =
new DummyPrerenderContents(prerender_manager_.get(), url, alias_urls);
prerender_manager_->SetNextPrerenderContents(pc);
prerender_manager_->AddSimplePreload(url);
EXPECT_EQ(NULL, prerender_manager_->GetEntry(not_an_alias_url));
EXPECT_EQ(pc, prerender_manager_->GetEntry(alias_url1));
prerender_manager_->SetNextPrerenderContents(pc);
prerender_manager_->AddSimplePreload(url);
EXPECT_EQ(pc, prerender_manager_->GetEntry(alias_url2));
prerender_manager_->SetNextPrerenderContents(pc);
prerender_manager_->AddSimplePreload(url);
EXPECT_EQ(pc, prerender_manager_->GetEntry(url));
delete pc;
}
......@@ -100,8 +100,10 @@ bool PrerenderResourceHandler::OnRequestRedirected(int request_id,
bool* defer) {
bool will_redirect = next_handler_->OnRequestRedirected(
request_id, url, response, defer);
if (will_redirect)
if (will_redirect) {
alias_urls_.push_back(url);
url_ = url;
}
return will_redirect;
}
......@@ -117,7 +119,8 @@ bool PrerenderResourceHandler::OnResponseStarted(int request_id,
NewRunnableMethod(
this,
&PrerenderResourceHandler::RunCallbackFromUIThread,
url_));
url_,
alias_urls_));
}
return next_handler_->OnResponseStarted(request_id, response);
}
......@@ -126,8 +129,10 @@ bool PrerenderResourceHandler::OnWillStart(int request_id,
const GURL& url,
bool* defer) {
bool will_start = next_handler_->OnWillStart(request_id, url, defer);
if (will_start)
if (will_start) {
alias_urls_.push_back(url);
url_ = url;
}
return will_start;
}
......@@ -154,14 +159,18 @@ void PrerenderResourceHandler::OnRequestClosed() {
next_handler_->OnRequestClosed();
}
void PrerenderResourceHandler::RunCallbackFromUIThread(const GURL& url) {
void PrerenderResourceHandler::RunCallbackFromUIThread(const GURL& url,
const std::vector<GURL>&
alias_urls) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
prerender_callback_->Run(url);
prerender_callback_->Run(url, alias_urls);
}
void PrerenderResourceHandler::StartPrerender(const GURL& url) {
void PrerenderResourceHandler::StartPrerender(const GURL& url,
const std::vector<GURL>&
alias_urls) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
prerender_manager_->AddPreload(url);
prerender_manager_->AddPreload(url, alias_urls);
}
void PrerenderResourceHandler::set_prerender_duration(base::TimeDelta dt) {
......
......@@ -71,7 +71,8 @@ class PrerenderResourceHandler : public ResourceHandler {
private:
friend class PrerenderResourceHandlerTest;
typedef Callback1<const GURL&>::Type PrerenderCallback;
typedef Callback2<const GURL&, const std::vector<GURL>&>::Type
PrerenderCallback;
static const int kDefaultPrerenderDurationSeconds;
......@@ -81,11 +82,16 @@ class PrerenderResourceHandler : public ResourceHandler {
PrerenderCallback* callback);
virtual ~PrerenderResourceHandler();
void RunCallbackFromUIThread(const GURL& url);
void StartPrerender(const GURL& url);
void RunCallbackFromUIThread(const GURL& url,
const std::vector<GURL>& alias_urls);
void StartPrerender(const GURL& url,
const std::vector<GURL>& alias_urls);
void set_prerender_duration(base::TimeDelta prerender_duration);
void set_get_current_time_function(GetCurrentTimeFunction get_current_time);
// The set of URLs that are aliases to the URL to be prerendered,
// as a result of redirects.
std::vector<GURL> alias_urls_;
GURL url_;
scoped_refptr<ResourceHandler> next_handler_;
scoped_refptr<PrerenderManager> prerender_manager_;
......
......@@ -100,8 +100,9 @@ class PrerenderResourceHandlerTest : public testing::Test {
pre_handler_->set_get_current_time_function(&FixedGetCurrentTime);
}
void SetLastHandledURL(const GURL& url) {
void SetLastHandledURL(const GURL& url, const std::vector<GURL>& alias_urls) {
last_handled_url_ = url;
alias_urls_ = alias_urls;
}
// Common logic shared by many of the tests
......@@ -125,6 +126,12 @@ class PrerenderResourceHandlerTest : public testing::Test {
loop_.RunAllPending();
}
// Test whether a given URL is part of alias_urls_.
bool ContainsAliasURL(const GURL& url) {
return std::find(alias_urls_.begin(), alias_urls_.end(), url)
!= alias_urls_.end();
}
base::TimeDelta prerender_duration_;
scoped_refptr<MockResourceHandler> mock_handler_;
scoped_refptr<PrerenderResourceHandler> pre_handler_;
......@@ -132,6 +139,7 @@ class PrerenderResourceHandlerTest : public testing::Test {
BrowserThread ui_thread_;
GURL last_handled_url_;
GURL default_url_;
std::vector<GURL> alias_urls_;
};
namespace {
......@@ -208,7 +216,9 @@ TEST_F(PrerenderResourceHandlerTest, PrerenderRedirect) {
EXPECT_TRUE(last_handled_url_.is_empty());
loop_.RunAllPending();
EXPECT_EQ(url_redirect, last_handled_url_);
EXPECT_EQ(true, ContainsAliasURL(url_redirect));
EXPECT_EQ(true, ContainsAliasURL(default_url_));
EXPECT_EQ(2, static_cast<int>(alias_urls_.size()));
}
}
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