| // 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 |