diff options
author | gavinp@chromium.org <gavinp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-19 19:07:40 +0000 |
---|---|---|
committer | gavinp@chromium.org <gavinp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-19 19:07:40 +0000 |
commit | 1d14ba55e2472ad65b41423a6b8ed13b32dc206d (patch) | |
tree | fcc237d57d7b8ee927afc5d60925911949b05c29 /chrome | |
parent | fc52c42d72d42558e508f6439e8dfbb9b4ea15d9 (diff) | |
download | chromium_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.cc | 9 | ||||
-rw-r--r-- | chrome/browser/io_thread.h | 3 | ||||
-rw-r--r-- | chrome/browser/net/prerender_interceptor.cc | 78 | ||||
-rw-r--r-- | chrome/browser/net/prerender_interceptor.h | 53 | ||||
-rw-r--r-- | chrome/browser/net/prerender_interceptor_unittest.cc | 100 | ||||
-rw-r--r-- | chrome/browser/renderer_host/resource_dispatcher_host.cc | 2 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/test/data/prerender/doc1.html | 3 | ||||
-rw-r--r-- | chrome/test/data/prerender/doc2.html | 3 | ||||
-rw-r--r-- | chrome/test/data/prerender/image.jpeg | 1 |
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 @@ + |