// Copyright (c) 2011 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/prerender/prerender_resource_handler.h" #include "content/common/resource_response.h" #include "net/http/http_response_headers.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace prerender { namespace { class MockResourceHandler : public ResourceHandler { public: MockResourceHandler() {} virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size) { return true; } virtual bool OnRequestRedirected(int request_id, const GURL& url, ResourceResponse* response, bool* defer) { *defer = false; return true; } virtual bool OnResponseStarted(int request_id, ResourceResponse* response) { return true; } virtual bool OnWillStart(int request_id, const GURL& url, bool* defer) { *defer = false; return true; } virtual bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size, int min_size) { return true; } virtual bool OnReadCompleted(int request_id, int* bytes_read) { return true; } virtual bool OnResponseCompleted(int request_id, const net::URLRequestStatus& status, const std::string& security_info) { return true; } virtual void OnRequestClosed() { } virtual void OnDataDownloaded(int request_id, int bytes_downloaded) {} }; // HttpResponseHeaders expects the raw input for it's constructor // to be a NUL ('\0') separated string for each line. This is a little // difficult to do for string literals, so this helper function accepts // newline-separated string literals and does the substitution. The // returned object is expected to be deleted by the caller. net::HttpResponseHeaders* CreateResponseHeaders( const char* newline_separated_headers) { std::string headers(newline_separated_headers); std::string::iterator i = headers.begin(); std::string::iterator end = headers.end(); while (i != end) { if (*i == '\n') *i = '\0'; ++i; } return new net::HttpResponseHeaders(headers); } } // namespace class PrerenderResourceHandlerTest : public testing::Test { protected: PrerenderResourceHandlerTest() : loop_(MessageLoop::TYPE_IO), ui_thread_(BrowserThread::UI, &loop_), io_thread_(BrowserThread::IO, &loop_), test_url_request_(GURL("http://www.referrer.com"), &test_url_request_delegate_), ALLOW_THIS_IN_INITIALIZER_LIST( pre_handler_(new PrerenderResourceHandler( test_url_request_, new MockResourceHandler(), NewCallback( this, &PrerenderResourceHandlerTest::SetLastHandledURL)))), default_url_("http://www.prerender.com") { } virtual ~PrerenderResourceHandlerTest() { // When a ResourceHandler's reference count drops to 0, it is not // deleted immediately. Instead, a task is posted to the IO thread's // message loop to delete it. // So, drop the reference count to 0 and run the message loop once // to ensure that all resources are cleaned up before the test exits. pre_handler_ = NULL; loop_.RunAllPending(); } void SetLastHandledURL(const std::pair<int, int>& child_route_id_pair, const GURL& url, const std::vector<GURL>& alias_urls, const GURL& referrer, bool make_pending) { last_handled_url_ = url; alias_urls_ = alias_urls; referrer_ = referrer; } // Common logic shared by many of the tests void StartPrerendering(const std::string& mime_type, const char* headers) { int request_id = 1; bool defer = false; EXPECT_TRUE(pre_handler_->OnWillStart(request_id, default_url_, &defer)); EXPECT_FALSE(defer); scoped_refptr<ResourceResponse> response(new ResourceResponse); response->response_head.mime_type = mime_type; response->response_head.headers = CreateResponseHeaders(headers); EXPECT_TRUE(last_handled_url_.is_empty()); // Start the response. If it is able to prerender, a task will // be posted to the UI thread and |SetLastHandledURL| will be called. EXPECT_TRUE(pre_handler_->OnResponseStarted(request_id, response)); 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(); } // Must be initialized before |test_url_request_|. MessageLoop loop_; BrowserThread ui_thread_; BrowserThread io_thread_; TestDelegate test_url_request_delegate_; TestURLRequest test_url_request_; scoped_refptr<PrerenderResourceHandler> pre_handler_; GURL last_handled_url_; GURL default_url_; std::vector<GURL> alias_urls_; GURL referrer_; }; namespace { TEST_F(PrerenderResourceHandlerTest, NoOp) { } // Tests that a valid HTML resource will correctly get diverted // to the PrerenderManager. TEST_F(PrerenderResourceHandlerTest, Prerender) { StartPrerendering("text/html", "HTTP/1.1 200 OK\n"); EXPECT_EQ(default_url_, last_handled_url_); } static const int kRequestId = 1; // Tests that the final request in a redirect chain will // get diverted to the PrerenderManager. TEST_F(PrerenderResourceHandlerTest, PrerenderRedirect) { GURL url_redirect("http://www.redirect.com"); bool defer = false; EXPECT_TRUE(pre_handler_->OnWillStart(kRequestId, default_url_, &defer)); EXPECT_FALSE(defer); EXPECT_TRUE(pre_handler_->OnRequestRedirected(kRequestId, url_redirect, NULL, &defer)); EXPECT_FALSE(defer); scoped_refptr<ResourceResponse> response(new ResourceResponse); response->response_head.mime_type = "text/html"; response->response_head.headers = CreateResponseHeaders( "HTTP/1.1 200 OK\n"); EXPECT_TRUE(pre_handler_->OnResponseStarted(kRequestId, response)); 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())); } // Tests that https requests will not be prerendered. TEST_F(PrerenderResourceHandlerTest, PrerenderHttps) { GURL url_https("https://www.google.com"); bool defer = false; EXPECT_FALSE(pre_handler_->OnWillStart(kRequestId, url_https, &defer)); EXPECT_FALSE(defer); } TEST_F(PrerenderResourceHandlerTest, PrerenderRedirectToHttps) { bool defer = false; EXPECT_TRUE(pre_handler_->OnWillStart(kRequestId, default_url_, &defer)); EXPECT_FALSE(defer); GURL url_https("https://www.google.com"); EXPECT_FALSE(pre_handler_->OnRequestRedirected(kRequestId, url_https, NULL, &defer)); EXPECT_FALSE(defer); } } // namespace } // namespace prerender