• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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