1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/prerender/prerender_resource_handler.h" 6#include "content/common/resource_response.h" 7#include "net/http/http_response_headers.h" 8#include "net/url_request/url_request_test_util.h" 9#include "testing/gtest/include/gtest/gtest.h" 10 11namespace prerender { 12 13namespace { 14 15class MockResourceHandler : public ResourceHandler { 16 public: 17 MockResourceHandler() {} 18 19 virtual bool OnUploadProgress(int request_id, 20 uint64 position, 21 uint64 size) { 22 return true; 23 } 24 25 virtual bool OnRequestRedirected(int request_id, const GURL& url, 26 ResourceResponse* response, 27 bool* defer) { 28 *defer = false; 29 return true; 30 } 31 32 virtual bool OnResponseStarted(int request_id, 33 ResourceResponse* response) { 34 return true; 35 } 36 37 virtual bool OnWillStart(int request_id, const GURL& url, bool* defer) { 38 *defer = false; 39 return true; 40 } 41 42 virtual bool OnWillRead(int request_id, 43 net::IOBuffer** buf, 44 int* buf_size, 45 int min_size) { 46 return true; 47 } 48 49 virtual bool OnReadCompleted(int request_id, int* bytes_read) { 50 return true; 51 } 52 53 virtual bool OnResponseCompleted(int request_id, 54 const net::URLRequestStatus& status, 55 const std::string& security_info) { 56 return true; 57 } 58 59 virtual void OnRequestClosed() { 60 } 61 62 virtual void OnDataDownloaded(int request_id, int bytes_downloaded) {} 63}; 64 65// HttpResponseHeaders expects the raw input for it's constructor 66// to be a NUL ('\0') separated string for each line. This is a little 67// difficult to do for string literals, so this helper function accepts 68// newline-separated string literals and does the substitution. The 69// returned object is expected to be deleted by the caller. 70net::HttpResponseHeaders* CreateResponseHeaders( 71 const char* newline_separated_headers) { 72 std::string headers(newline_separated_headers); 73 std::string::iterator i = headers.begin(); 74 std::string::iterator end = headers.end(); 75 while (i != end) { 76 if (*i == '\n') 77 *i = '\0'; 78 ++i; 79 } 80 return new net::HttpResponseHeaders(headers); 81} 82 83} // namespace 84 85class PrerenderResourceHandlerTest : public testing::Test { 86 protected: 87 PrerenderResourceHandlerTest() 88 : loop_(MessageLoop::TYPE_IO), 89 ui_thread_(BrowserThread::UI, &loop_), 90 io_thread_(BrowserThread::IO, &loop_), 91 test_url_request_(GURL("http://www.referrer.com"), 92 &test_url_request_delegate_), 93 ALLOW_THIS_IN_INITIALIZER_LIST( 94 pre_handler_(new PrerenderResourceHandler( 95 test_url_request_, 96 new MockResourceHandler(), 97 NewCallback( 98 this, 99 &PrerenderResourceHandlerTest::SetLastHandledURL)))), 100 default_url_("http://www.prerender.com") { 101 } 102 103 virtual ~PrerenderResourceHandlerTest() { 104 // When a ResourceHandler's reference count drops to 0, it is not 105 // deleted immediately. Instead, a task is posted to the IO thread's 106 // message loop to delete it. 107 // So, drop the reference count to 0 and run the message loop once 108 // to ensure that all resources are cleaned up before the test exits. 109 pre_handler_ = NULL; 110 loop_.RunAllPending(); 111 } 112 113 void SetLastHandledURL(const std::pair<int, int>& child_route_id_pair, 114 const GURL& url, const std::vector<GURL>& alias_urls, 115 const GURL& referrer, bool make_pending) { 116 last_handled_url_ = url; 117 alias_urls_ = alias_urls; 118 referrer_ = referrer; 119 } 120 121 // Common logic shared by many of the tests 122 void StartPrerendering(const std::string& mime_type, 123 const char* headers) { 124 int request_id = 1; 125 bool defer = false; 126 EXPECT_TRUE(pre_handler_->OnWillStart(request_id, default_url_, &defer)); 127 EXPECT_FALSE(defer); 128 scoped_refptr<ResourceResponse> response(new ResourceResponse); 129 response->response_head.mime_type = mime_type; 130 response->response_head.headers = CreateResponseHeaders(headers); 131 EXPECT_TRUE(last_handled_url_.is_empty()); 132 133 // Start the response. If it is able to prerender, a task will 134 // be posted to the UI thread and |SetLastHandledURL| will be called. 135 EXPECT_TRUE(pre_handler_->OnResponseStarted(request_id, response)); 136 loop_.RunAllPending(); 137 } 138 139 // Test whether a given URL is part of alias_urls_. 140 bool ContainsAliasURL(const GURL& url) { 141 return std::find(alias_urls_.begin(), alias_urls_.end(), url) 142 != alias_urls_.end(); 143 } 144 145 // Must be initialized before |test_url_request_|. 146 MessageLoop loop_; 147 BrowserThread ui_thread_; 148 BrowserThread io_thread_; 149 150 TestDelegate test_url_request_delegate_; 151 TestURLRequest test_url_request_; 152 153 scoped_refptr<PrerenderResourceHandler> pre_handler_; 154 GURL last_handled_url_; 155 GURL default_url_; 156 std::vector<GURL> alias_urls_; 157 GURL referrer_; 158}; 159 160namespace { 161 162TEST_F(PrerenderResourceHandlerTest, NoOp) { 163} 164 165// Tests that a valid HTML resource will correctly get diverted 166// to the PrerenderManager. 167TEST_F(PrerenderResourceHandlerTest, Prerender) { 168 StartPrerendering("text/html", 169 "HTTP/1.1 200 OK\n"); 170 EXPECT_EQ(default_url_, last_handled_url_); 171} 172 173static const int kRequestId = 1; 174 175// Tests that the final request in a redirect chain will 176// get diverted to the PrerenderManager. 177TEST_F(PrerenderResourceHandlerTest, PrerenderRedirect) { 178 GURL url_redirect("http://www.redirect.com"); 179 bool defer = false; 180 EXPECT_TRUE(pre_handler_->OnWillStart(kRequestId, default_url_, &defer)); 181 EXPECT_FALSE(defer); 182 EXPECT_TRUE(pre_handler_->OnRequestRedirected(kRequestId, 183 url_redirect, 184 NULL, 185 &defer)); 186 EXPECT_FALSE(defer); 187 scoped_refptr<ResourceResponse> response(new ResourceResponse); 188 response->response_head.mime_type = "text/html"; 189 response->response_head.headers = CreateResponseHeaders( 190 "HTTP/1.1 200 OK\n"); 191 EXPECT_TRUE(pre_handler_->OnResponseStarted(kRequestId, response)); 192 EXPECT_TRUE(last_handled_url_.is_empty()); 193 loop_.RunAllPending(); 194 EXPECT_EQ(url_redirect, last_handled_url_); 195 EXPECT_EQ(true, ContainsAliasURL(url_redirect)); 196 EXPECT_EQ(true, ContainsAliasURL(default_url_)); 197 EXPECT_EQ(2, static_cast<int>(alias_urls_.size())); 198} 199 200// Tests that https requests will not be prerendered. 201TEST_F(PrerenderResourceHandlerTest, PrerenderHttps) { 202 GURL url_https("https://www.google.com"); 203 bool defer = false; 204 EXPECT_FALSE(pre_handler_->OnWillStart(kRequestId, url_https, &defer)); 205 EXPECT_FALSE(defer); 206} 207 208TEST_F(PrerenderResourceHandlerTest, PrerenderRedirectToHttps) { 209 bool defer = false; 210 EXPECT_TRUE(pre_handler_->OnWillStart(kRequestId, default_url_, &defer)); 211 EXPECT_FALSE(defer); 212 GURL url_https("https://www.google.com"); 213 EXPECT_FALSE(pre_handler_->OnRequestRedirected(kRequestId, 214 url_https, 215 NULL, 216 &defer)); 217 EXPECT_FALSE(defer); 218} 219 220} // namespace 221 222} // namespace prerender 223