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
7 #include "chrome/browser/net/chrome_url_request_context.h"
8 #include "content/common/resource_response.h"
9 #include "net/base/load_flags.h"
10 #include "net/http/http_response_headers.h"
11 #include "net/url_request/url_request.h"
12
13 namespace prerender {
14
15 namespace {
16
ShouldPrerenderURL(const GURL & url)17 bool ShouldPrerenderURL(const GURL& url) {
18 if (!url.is_valid())
19 return false;
20 if (!url.SchemeIs("http")) {
21 RecordFinalStatus(FINAL_STATUS_HTTPS);
22 return false;
23 }
24 return true;
25 }
26
ValidateAliasURLs(const std::vector<GURL> & urls)27 bool ValidateAliasURLs(const std::vector<GURL>& urls) {
28 for (std::vector<GURL>::const_iterator it = urls.begin();
29 it != urls.end();
30 ++it) {
31 if (!ShouldPrerenderURL(*it))
32 return false;
33 }
34 return true;
35 }
36
ShouldPrerender(const ResourceResponse * response)37 bool ShouldPrerender(const ResourceResponse* response) {
38 if (!response)
39 return false;
40 const ResourceResponseHead& rrh = response->response_head;
41 if (!rrh.headers)
42 return false;
43 if (rrh.mime_type != "text/html")
44 return false;
45 if (rrh.headers->response_code() != 200)
46 return false;
47 return true;
48 }
49
50 } // namespace
51
MaybeCreate(const net::URLRequest & request,ChromeURLRequestContext * context,ResourceHandler * next_handler,bool is_from_prerender,int child_id,int route_id)52 PrerenderResourceHandler* PrerenderResourceHandler::MaybeCreate(
53 const net::URLRequest& request,
54 ChromeURLRequestContext* context,
55 ResourceHandler* next_handler,
56 bool is_from_prerender,
57 int child_id,
58 int route_id) {
59 if (!context || !context->prerender_manager())
60 return NULL;
61 if (!(request.load_flags() & net::LOAD_PREFETCH))
62 return NULL;
63 if (!ShouldPrerenderURL(request.url()))
64 return NULL;
65 if (request.method() != "GET")
66 return NULL;
67
68 return new PrerenderResourceHandler(request,
69 next_handler,
70 context->prerender_manager(),
71 is_from_prerender,
72 child_id,
73 route_id);
74 }
75
PrerenderResourceHandler(const net::URLRequest & request,ResourceHandler * next_handler,PrerenderManager * prerender_manager,bool make_pending,int child_id,int route_id)76 PrerenderResourceHandler::PrerenderResourceHandler(
77 const net::URLRequest& request,
78 ResourceHandler* next_handler,
79 PrerenderManager* prerender_manager,
80 bool make_pending,
81 int child_id,
82 int route_id)
83 : next_handler_(next_handler),
84 prerender_manager_(prerender_manager),
85 ALLOW_THIS_IN_INITIALIZER_LIST(
86 prerender_callback_(NewCallback(
87 this, &PrerenderResourceHandler::StartPrerender))),
88 request_(request),
89 child_id_(child_id),
90 route_id_(route_id),
91 make_pending_(make_pending) {
92 DCHECK(next_handler);
93 DCHECK(prerender_manager);
94 }
95
PrerenderResourceHandler(const net::URLRequest & request,ResourceHandler * next_handler,PrerenderCallback * callback)96 PrerenderResourceHandler::PrerenderResourceHandler(
97 const net::URLRequest& request,
98 ResourceHandler* next_handler,
99 PrerenderCallback* callback)
100 : next_handler_(next_handler),
101 prerender_callback_(callback),
102 request_(request) {
103 DCHECK(next_handler);
104 DCHECK(callback);
105 }
106
~PrerenderResourceHandler()107 PrerenderResourceHandler::~PrerenderResourceHandler() {
108 }
109
OnUploadProgress(int request_id,uint64 position,uint64 size)110 bool PrerenderResourceHandler::OnUploadProgress(int request_id,
111 uint64 position,
112 uint64 size) {
113 return next_handler_->OnUploadProgress(request_id, position, size);
114 }
115
OnRequestRedirected(int request_id,const GURL & url,ResourceResponse * response,bool * defer)116 bool PrerenderResourceHandler::OnRequestRedirected(int request_id,
117 const GURL& url,
118 ResourceResponse* response,
119 bool* defer) {
120 bool will_redirect = next_handler_->OnRequestRedirected(
121 request_id, url, response, defer);
122 if (will_redirect) {
123 if (!ShouldPrerenderURL(url))
124 return false;
125 alias_urls_.push_back(url);
126 url_ = url;
127 }
128 return will_redirect;
129 }
130
OnResponseStarted(int request_id,ResourceResponse * response)131 bool PrerenderResourceHandler::OnResponseStarted(int request_id,
132 ResourceResponse* response) {
133 if (ShouldPrerender(response)) {
134 DCHECK(ValidateAliasURLs(alias_urls_));
135 BrowserThread::PostTask(
136 BrowserThread::UI,
137 FROM_HERE,
138 NewRunnableMethod(
139 this,
140 &PrerenderResourceHandler::RunCallbackFromUIThread,
141 std::make_pair(child_id_, route_id_),
142 url_,
143 alias_urls_,
144 GURL(request_.referrer()),
145 make_pending_));
146 }
147 return next_handler_->OnResponseStarted(request_id, response);
148 }
149
OnWillStart(int request_id,const GURL & url,bool * defer)150 bool PrerenderResourceHandler::OnWillStart(int request_id,
151 const GURL& url,
152 bool* defer) {
153 bool will_start = next_handler_->OnWillStart(request_id, url, defer);
154 if (will_start) {
155 if (!ShouldPrerenderURL(url))
156 return false;
157 alias_urls_.push_back(url);
158 url_ = url;
159 }
160 return will_start;
161 }
162
OnWillRead(int request_id,net::IOBuffer ** buf,int * buf_size,int min_size)163 bool PrerenderResourceHandler::OnWillRead(int request_id,
164 net::IOBuffer** buf,
165 int* buf_size,
166 int min_size) {
167 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
168 }
169
OnReadCompleted(int request_id,int * bytes_read)170 bool PrerenderResourceHandler::OnReadCompleted(int request_id,
171 int* bytes_read) {
172 return next_handler_->OnReadCompleted(request_id, bytes_read);
173 }
174
OnResponseCompleted(int request_id,const net::URLRequestStatus & status,const std::string & security_info)175 bool PrerenderResourceHandler::OnResponseCompleted(
176 int request_id,
177 const net::URLRequestStatus& status,
178 const std::string& security_info) {
179 return next_handler_->OnResponseCompleted(request_id, status, security_info);
180 }
181
OnRequestClosed()182 void PrerenderResourceHandler::OnRequestClosed() {
183 next_handler_->OnRequestClosed();
184 }
185
RunCallbackFromUIThread(const std::pair<int,int> & child_route_id_pair,const GURL & url,const std::vector<GURL> & alias_urls,const GURL & referrer,bool make_pending)186 void PrerenderResourceHandler::RunCallbackFromUIThread(
187 const std::pair<int, int>& child_route_id_pair,
188 const GURL& url,
189 const std::vector<GURL>& alias_urls,
190 const GURL& referrer,
191 bool make_pending) {
192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
193 prerender_callback_->Run(child_route_id_pair,
194 url, alias_urls, referrer,
195 make_pending);
196 }
197
StartPrerender(const std::pair<int,int> & child_route_id_pair,const GURL & url,const std::vector<GURL> & alias_urls,const GURL & referrer,bool make_pending)198 void PrerenderResourceHandler::StartPrerender(
199 const std::pair<int, int>& child_route_id_pair,
200 const GURL& url,
201 const std::vector<GURL>& alias_urls,
202 const GURL& referrer,
203 bool make_pending) {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205 if (!prerender_manager_->is_enabled())
206 return;
207 if (make_pending) {
208 prerender_manager_->AddPendingPreload(child_route_id_pair,
209 url, alias_urls, referrer);
210 } else {
211 prerender_manager_->AddPreload(url, alias_urls, referrer);
212 }
213 }
214
215 } // namespace prerender
216