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 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 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 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 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 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 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 107 PrerenderResourceHandler::~PrerenderResourceHandler() { 108 } 109 110 bool PrerenderResourceHandler::OnUploadProgress(int request_id, 111 uint64 position, 112 uint64 size) { 113 return next_handler_->OnUploadProgress(request_id, position, size); 114 } 115 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 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 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 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 170 bool PrerenderResourceHandler::OnReadCompleted(int request_id, 171 int* bytes_read) { 172 return next_handler_->OnReadCompleted(request_id, bytes_read); 173 } 174 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 182 void PrerenderResourceHandler::OnRequestClosed() { 183 next_handler_->OnRequestClosed(); 184 } 185 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 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