summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorgavinp@chromium.org <gavinp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-19 19:07:40 +0000
committergavinp@chromium.org <gavinp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-19 19:07:40 +0000
commit1d14ba55e2472ad65b41423a6b8ed13b32dc206d (patch)
treefcc237d57d7b8ee927afc5d60925911949b05c29 /chrome
parentfc52c42d72d42558e508f6439e8dfbb9b4ea15d9 (diff)
downloadchromium_src-1d14ba55e2472ad65b41423a6b8ed13b32dc206d.zip
chromium_src-1d14ba55e2472ad65b41423a6b8ed13b32dc206d.tar.gz
chromium_src-1d14ba55e2472ad65b41423a6b8ed13b32dc206d.tar.bz2
Implement a dispatcher for prerender requests
This CL provides a dispatcher that can feed the prerender system with HTML type requests that were prefetched. One thing is missing though: this sends all requests in, and doesn't tag the origin request. Unfortunately referer information is often tossed out in resource_dispatcher_host... Is there a private place it's sent along to for this type of use? I left that undone right now but I'm open to suggestions about a good way to do it. BUG=none TEST=none Review URL: http://codereview.chromium.org/4655004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66790 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/io_thread.cc9
-rw-r--r--chrome/browser/io_thread.h3
-rw-r--r--chrome/browser/net/prerender_interceptor.cc78
-rw-r--r--chrome/browser/net/prerender_interceptor.h53
-rw-r--r--chrome/browser/net/prerender_interceptor_unittest.cc100
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc2
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/test/data/prerender/doc1.html3
-rw-r--r--chrome/test/data/prerender/doc2.html3
-rw-r--r--chrome/test/data/prerender/image.jpeg1
11 files changed, 255 insertions, 0 deletions
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 65be41e..788c339 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -23,6 +23,7 @@
#include "chrome/browser/net/connect_interceptor.h"
#include "chrome/browser/net/passive_log_collector.h"
#include "chrome/browser/net/predictor_api.h"
+#include "chrome/browser/net/prerender_interceptor.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/net/raw_host_resolver_proc.h"
@@ -332,6 +333,12 @@ void IOThread::Init() {
globals_->dnsrr_resolver.reset(new net::DnsRRResolver);
globals_->http_auth_handler_factory.reset(CreateDefaultAuthHandlerFactory(
globals_->host_resolver.get()));
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnablePagePrerender)) {
+ prerender_interceptor_.reset(
+ new chrome_browser_net::PrerenderInterceptor());
+ }
}
void IOThread::CleanUp() {
@@ -386,6 +393,8 @@ void IOThread::CleanUp() {
delete speculative_interceptor_;
speculative_interceptor_ = NULL;
+ prerender_interceptor_.reset();
+
// TODO(eroman): hack for http://crbug.com/15513
if (globals_->host_resolver->GetAsHostResolverImpl()) {
globals_->host_resolver.get()->GetAsHostResolverImpl()->Shutdown();
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index d7ba9db..a2dad58 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -26,6 +26,7 @@ class URLRequestContext;
namespace chrome_browser_net {
class ConnectInterceptor;
class Predictor;
+class PrerenderInterceptor;
} // namespace chrome_browser_net
namespace net {
@@ -155,6 +156,8 @@ class IOThread : public BrowserProcessSubThread {
// down.
chrome_browser_net::ConnectInterceptor* speculative_interceptor_;
chrome_browser_net::Predictor* predictor_;
+ scoped_ptr<chrome_browser_net::PrerenderInterceptor>
+ prerender_interceptor_;
// List of live ProxyScriptFetchers.
ProxyScriptFetchers fetchers_;
diff --git a/chrome/browser/net/prerender_interceptor.cc b/chrome/browser/net/prerender_interceptor.cc
new file mode 100644
index 0000000..f4df5b4
--- /dev/null
+++ b/chrome/browser/net/prerender_interceptor.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/net/prerender_interceptor.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "chrome/browser/browser_thread.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/io_thread.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/load_flags.h"
+
+DISABLE_RUNNABLE_METHOD_REFCOUNT(chrome_browser_net::PrerenderInterceptor);
+
+namespace chrome_browser_net {
+
+PrerenderInterceptor::PrerenderInterceptor()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(
+ callback_(NewCallback(this,
+ &PrerenderInterceptor::PrerenderDispatch))) {
+ URLRequest::RegisterRequestInterceptor(this);
+}
+
+PrerenderInterceptor::PrerenderInterceptor(
+ PrerenderInterceptorCallback* callback)
+ : callback_(callback) {
+ URLRequest::RegisterRequestInterceptor(this);
+}
+
+PrerenderInterceptor::~PrerenderInterceptor() {
+ URLRequest::UnregisterRequestInterceptor(this);
+}
+
+URLRequestJob* PrerenderInterceptor::MaybeIntercept(URLRequest* request) {
+ return NULL;
+}
+
+URLRequestJob* PrerenderInterceptor::MaybeInterceptResponse(
+ URLRequest* request) {
+ // TODO(gavinp): unfortunately, we can't figure out the origin
+ // of this request here on systems where the referrer is blocked by
+ // configuration.
+
+ // TODO(gavinp): note that the response still might be intercepted
+ // by a later interceptor. Should we write an interposing delegate
+ // and only prerender dispatch on requests that aren't intercepted?
+ // Or is this a slippery slope?
+
+ if (request->load_flags() & net::LOAD_PREFETCH) {
+ std::string mime_type;
+ request->GetMimeType(&mime_type);
+ if (mime_type == "text/html")
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ NewRunnableMethod(this,
+ &PrerenderInterceptor::RunCallbackFromUIThread,
+ request->url()));
+ }
+ return NULL;
+}
+
+void PrerenderInterceptor::RunCallbackFromUIThread(const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ callback_->Run(url);
+}
+
+void PrerenderInterceptor::PrerenderDispatch(
+ const GURL& url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DVLOG(2) << "PrerenderDispatchOnUIThread: url=" << url;
+}
+
+} // namespace chrome_browser_net
+
diff --git a/chrome/browser/net/prerender_interceptor.h b/chrome/browser/net/prerender_interceptor.h
new file mode 100644
index 0000000..3c0f262
--- /dev/null
+++ b/chrome/browser/net/prerender_interceptor.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_NET_PRERENDER_INTERCEPTOR_H_
+#define CHROME_BROWSER_NET_PRERENDER_INTERCEPTOR_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/scoped_ptr.h"
+#include "base/task.h"
+#include "net/url_request/url_request.h"
+
+class GURL;
+
+namespace chrome_browser_net {
+
+// The PrerenderInterceptor watches prefetch requests, and when
+// they are for type text/html, notifies the prerendering
+// system about the fetch so it may consider the URL.
+class PrerenderInterceptor : public URLRequest::Interceptor {
+ public:
+ PrerenderInterceptor();
+ virtual ~PrerenderInterceptor();
+
+ // URLRequest::Interceptor overrides. We only care about
+ // MaybeInterceptResponse, but must capture MaybeIntercept since
+ // it is pure virtual.
+ virtual URLRequestJob* MaybeIntercept(URLRequest* request);
+ virtual URLRequestJob* MaybeInterceptResponse(URLRequest* request);
+
+ private:
+ friend class PrerenderInterceptorTest;
+
+ typedef Callback1<const GURL&>::Type PrerenderInterceptorCallback;
+
+ // This constructor is provided for the unit test only, to provide
+ // an an alternative dispatch target for the test only. The callback
+ // parameter is owned and deleted by this object.
+ explicit PrerenderInterceptor(PrerenderInterceptorCallback* callback);
+
+ void RunCallbackFromUIThread(const GURL& url);
+ void PrerenderDispatch(const GURL& url);
+
+ scoped_ptr<PrerenderInterceptorCallback> callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrerenderInterceptor);
+};
+
+} // namespace chrome_browser_net
+
+#endif // CHROME_BROWSER_NET_PRERENDER_INTERCEPTOR_H_
+
diff --git a/chrome/browser/net/prerender_interceptor_unittest.cc b/chrome/browser/net/prerender_interceptor_unittest.cc
new file mode 100644
index 0000000..9c2200b
--- /dev/null
+++ b/chrome/browser/net/prerender_interceptor_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/net/prerender_interceptor.h"
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/file_path.h"
+#include "base/message_loop_proxy.h"
+#include "base/scoped_ptr.h"
+#include "chrome/browser/browser_thread.h"
+#include "googleurl/src/gurl.h"
+#include "net/base/load_flags.h"
+#include "net/test/test_server.h"
+#include "net/url_request/url_request_unittest.h"
+
+namespace chrome_browser_net {
+
+class PrerenderInterceptorTest : public testing::Test {
+ public:
+ PrerenderInterceptorTest();
+
+ void MakeTestUrl(const std::string& base);
+ virtual void SetUp();
+
+ net::TestServer test_server_;
+ GURL gurl_;
+ GURL last_intercepted_gurl_;
+ scoped_ptr<URLRequest> req_;
+ private:
+ void SetLastInterceptedGurl(const GURL& url);
+
+ PrerenderInterceptor prerender_interceptor_;
+ MessageLoopForIO io_loop_;
+ scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_;
+ BrowserThread ui_thread_;
+};
+
+PrerenderInterceptorTest::PrerenderInterceptorTest()
+ : test_server_(net::TestServer::TYPE_HTTP,
+ FilePath(FILE_PATH_LITERAL("chrome/test/data"))),
+ last_intercepted_gurl_("http://not.initialized/"),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ prerender_interceptor_(
+ NewCallback(this,
+ &PrerenderInterceptorTest::SetLastInterceptedGurl))),
+ ui_thread_(BrowserThread::UI, &io_loop_) {
+}
+
+void PrerenderInterceptorTest::SetUp() {
+ testing::Test::SetUp();
+ last_intercepted_gurl_ = GURL("http://nothing.intercepted/");
+
+ io_message_loop_proxy_ = base::MessageLoopProxy::CreateForCurrentThread();
+ ASSERT_TRUE(test_server_.Start());
+}
+
+void PrerenderInterceptorTest::MakeTestUrl(const std::string& base) {
+ gurl_ = test_server_.GetURL(base);
+ req_.reset(new TestURLRequest(gurl_, new TestDelegate()));
+}
+
+void PrerenderInterceptorTest::SetLastInterceptedGurl(const GURL& url) {
+ last_intercepted_gurl_ = url;
+}
+
+TEST_F(PrerenderInterceptorTest, Interception) {
+ MakeTestUrl("files/prerender/doc1.html");
+ req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
+ req_->Start();
+
+ MessageLoop::current()->Run();
+ EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
+ EXPECT_EQ(gurl_, last_intercepted_gurl_);
+}
+
+TEST_F(PrerenderInterceptorTest, NotAPrefetch) {
+ MakeTestUrl("files/prerender/doc2.html");
+ req_->set_load_flags(req_->load_flags() & ~net::LOAD_PREFETCH);
+ req_->Start();
+
+ MessageLoop::current()->Run();
+ EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
+ EXPECT_NE(gurl_, last_intercepted_gurl_);
+}
+
+TEST_F(PrerenderInterceptorTest, WrongMimeType) {
+ MakeTestUrl("files/prerender/image.jpeg");
+ req_->set_load_flags(req_->load_flags() | net::LOAD_PREFETCH);
+ req_->Start();
+
+ MessageLoop::current()->Run();
+ EXPECT_EQ(URLRequestStatus::SUCCESS, req_->status().status());
+ EXPECT_NE(gurl_, last_intercepted_gurl_);
+}
+
+} // namespace chrome_browser_net
+
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index c88e558..b2610d5 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -449,6 +449,8 @@ void ResourceDispatcherHost::BeginRequest(
load_flags |= net::LOAD_MAIN_FRAME;
} else if (request_data.resource_type == ResourceType::SUB_FRAME) {
load_flags |= net::LOAD_SUB_FRAME;
+ } else if (request_data.resource_type == ResourceType::PREFETCH) {
+ load_flags |= net::LOAD_PREFETCH;
}
// Raw headers are sensitive, as they inclide Cookie/Set-Cookie, so only
// allow requesting them if requestor has ReadRawCookies permission.
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index ae9ad86..960411c 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2254,6 +2254,8 @@
'browser/net/predictor.h',
'browser/net/predictor_api.cc',
'browser/net/predictor_api.h',
+ 'browser/net/prerender_interceptor.cc',
+ 'browser/net/prerender_interceptor.h',
'browser/net/referrer.cc',
'browser/net/referrer.h',
'browser/net/resolve_proxy_msg_helper.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 4362fb6..9249b66 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1370,6 +1370,7 @@
'browser/net/load_timing_observer_unittest.cc',
'browser/net/passive_log_collector_unittest.cc',
'browser/net/predictor_unittest.cc',
+ 'browser/net/prerender_interceptor_unittest.cc',
'browser/net/resolve_proxy_msg_helper_unittest.cc',
'browser/net/url_fixer_upper_unittest.cc',
'browser/net/url_info_unittest.cc',
diff --git a/chrome/test/data/prerender/doc1.html b/chrome/test/data/prerender/doc1.html
new file mode 100644
index 0000000..1d60f48
--- /dev/null
+++ b/chrome/test/data/prerender/doc1.html
@@ -0,0 +1,3 @@
+<html>
+hi mom
+</html>
diff --git a/chrome/test/data/prerender/doc2.html b/chrome/test/data/prerender/doc2.html
new file mode 100644
index 0000000..453f935
--- /dev/null
+++ b/chrome/test/data/prerender/doc2.html
@@ -0,0 +1,3 @@
+<html>
+hi dad
+</html>
diff --git a/chrome/test/data/prerender/image.jpeg b/chrome/test/data/prerender/image.jpeg
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/chrome/test/data/prerender/image.jpeg
@@ -0,0 +1 @@
+