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
11 namespace prerender {
12
13 namespace {
14
15 class MockResourceHandler : public ResourceHandler {
16 public:
MockResourceHandler()17 MockResourceHandler() {}
18
OnUploadProgress(int request_id,uint64 position,uint64 size)19 virtual bool OnUploadProgress(int request_id,
20 uint64 position,
21 uint64 size) {
22 return true;
23 }
24
OnRequestRedirected(int request_id,const GURL & url,ResourceResponse * response,bool * defer)25 virtual bool OnRequestRedirected(int request_id, const GURL& url,
26 ResourceResponse* response,
27 bool* defer) {
28 *defer = false;
29 return true;
30 }
31
OnResponseStarted(int request_id,ResourceResponse * response)32 virtual bool OnResponseStarted(int request_id,
33 ResourceResponse* response) {
34 return true;
35 }
36
OnWillStart(int request_id,const GURL & url,bool * defer)37 virtual bool OnWillStart(int request_id, const GURL& url, bool* defer) {
38 *defer = false;
39 return true;
40 }
41
OnWillRead(int request_id,net::IOBuffer ** buf,int * buf_size,int min_size)42 virtual bool OnWillRead(int request_id,
43 net::IOBuffer** buf,
44 int* buf_size,
45 int min_size) {
46 return true;
47 }
48
OnReadCompleted(int request_id,int * bytes_read)49 virtual bool OnReadCompleted(int request_id, int* bytes_read) {
50 return true;
51 }
52
OnResponseCompleted(int request_id,const net::URLRequestStatus & status,const std::string & security_info)53 virtual bool OnResponseCompleted(int request_id,
54 const net::URLRequestStatus& status,
55 const std::string& security_info) {
56 return true;
57 }
58
OnRequestClosed()59 virtual void OnRequestClosed() {
60 }
61
OnDataDownloaded(int request_id,int bytes_downloaded)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.
CreateResponseHeaders(const char * newline_separated_headers)70 net::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
85 class PrerenderResourceHandlerTest : public testing::Test {
86 protected:
PrerenderResourceHandlerTest()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
~PrerenderResourceHandlerTest()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
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)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
StartPrerendering(const std::string & mime_type,const char * headers)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_.
ContainsAliasURL(const GURL & url)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
160 namespace {
161
TEST_F(PrerenderResourceHandlerTest,NoOp)162 TEST_F(PrerenderResourceHandlerTest, NoOp) {
163 }
164
165 // Tests that a valid HTML resource will correctly get diverted
166 // to the PrerenderManager.
TEST_F(PrerenderResourceHandlerTest,Prerender)167 TEST_F(PrerenderResourceHandlerTest, Prerender) {
168 StartPrerendering("text/html",
169 "HTTP/1.1 200 OK\n");
170 EXPECT_EQ(default_url_, last_handled_url_);
171 }
172
173 static const int kRequestId = 1;
174
175 // Tests that the final request in a redirect chain will
176 // get diverted to the PrerenderManager.
TEST_F(PrerenderResourceHandlerTest,PrerenderRedirect)177 TEST_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.
TEST_F(PrerenderResourceHandlerTest,PrerenderHttps)201 TEST_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
TEST_F(PrerenderResourceHandlerTest,PrerenderRedirectToHttps)208 TEST_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