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/renderer_host/safe_browsing_resource_handler.h" 6 7 #include "base/logging.h" 8 #include "content/browser/renderer_host/global_request_id.h" 9 #include "content/browser/renderer_host/resource_dispatcher_host.h" 10 #include "content/browser/renderer_host/resource_message_filter.h" 11 #include "content/common/resource_response.h" 12 #include "net/base/io_buffer.h" 13 #include "net/base/load_flags.h" 14 #include "net/base/net_errors.h" 15 #include "net/url_request/url_request.h" 16 17 // Maximum time in milliseconds to wait for the safe browsing service to 18 // verify a URL. After this amount of time the outstanding check will be 19 // aborted, and the URL will be treated as if it were safe. 20 static const int kCheckUrlTimeoutMs = 5000; 21 22 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more 23 // unit test coverage. 24 25 SafeBrowsingResourceHandler::SafeBrowsingResourceHandler( 26 ResourceHandler* handler, 27 int render_process_host_id, 28 int render_view_id, 29 ResourceType::Type resource_type, 30 SafeBrowsingService* safe_browsing, 31 ResourceDispatcherHost* resource_dispatcher_host) 32 : state_(STATE_NONE), 33 defer_state_(DEFERRED_NONE), 34 safe_browsing_result_(SafeBrowsingService::SAFE), 35 deferred_request_id_(-1), 36 next_handler_(handler), 37 render_process_host_id_(render_process_host_id), 38 render_view_id_(render_view_id), 39 safe_browsing_(safe_browsing), 40 rdh_(resource_dispatcher_host), 41 resource_type_(resource_type) { 42 } 43 44 SafeBrowsingResourceHandler::~SafeBrowsingResourceHandler() { 45 } 46 47 bool SafeBrowsingResourceHandler::OnUploadProgress(int request_id, 48 uint64 position, 49 uint64 size) { 50 return next_handler_->OnUploadProgress(request_id, position, size); 51 } 52 53 bool SafeBrowsingResourceHandler::OnRequestRedirected( 54 int request_id, 55 const GURL& new_url, 56 ResourceResponse* response, 57 bool* defer) { 58 CHECK(state_ == STATE_NONE); 59 CHECK(defer_state_ == DEFERRED_NONE); 60 61 // Save the redirect urls for possible malware detail reporting later. 62 redirect_urls_.push_back(new_url); 63 64 // We need to check the new URL before following the redirect. 65 if (CheckUrl(new_url)) { 66 return next_handler_->OnRequestRedirected( 67 request_id, new_url, response, defer); 68 } 69 70 // If the URL couldn't be verified synchronously, defer following the 71 // redirect until the SafeBrowsing check is complete. Store the redirect 72 // context so we can pass it on to other handlers once we have completed 73 // our check. 74 defer_state_ = DEFERRED_REDIRECT; 75 deferred_request_id_ = request_id; 76 deferred_url_ = new_url; 77 deferred_redirect_response_ = response; 78 *defer = true; 79 80 return true; 81 } 82 83 bool SafeBrowsingResourceHandler::OnResponseStarted( 84 int request_id, ResourceResponse* response) { 85 CHECK(state_ == STATE_NONE); 86 CHECK(defer_state_ == DEFERRED_NONE); 87 return next_handler_->OnResponseStarted(request_id, response); 88 } 89 90 void SafeBrowsingResourceHandler::OnCheckUrlTimeout() { 91 CHECK(state_ == STATE_CHECKING_URL); 92 CHECK(defer_state_ != DEFERRED_NONE); 93 safe_browsing_->CancelCheck(this); 94 OnBrowseUrlCheckResult(deferred_url_, SafeBrowsingService::SAFE); 95 } 96 97 bool SafeBrowsingResourceHandler::OnWillStart(int request_id, 98 const GURL& url, 99 bool* defer) { 100 // We need to check the new URL before starting the request. 101 if (CheckUrl(url)) 102 return next_handler_->OnWillStart(request_id, url, defer); 103 104 // If the URL couldn't be verified synchronously, defer starting the 105 // request until the check has completed. 106 defer_state_ = DEFERRED_START; 107 deferred_request_id_ = request_id; 108 deferred_url_ = url; 109 *defer = true; 110 111 return true; 112 } 113 114 bool SafeBrowsingResourceHandler::OnWillRead(int request_id, 115 net::IOBuffer** buf, int* buf_size, 116 int min_size) { 117 CHECK(state_ == STATE_NONE); 118 CHECK(defer_state_ == DEFERRED_NONE); 119 return next_handler_->OnWillRead(request_id, buf, buf_size, min_size); 120 } 121 122 bool SafeBrowsingResourceHandler::OnReadCompleted(int request_id, 123 int* bytes_read) { 124 CHECK(state_ == STATE_NONE); 125 CHECK(defer_state_ == DEFERRED_NONE); 126 return next_handler_->OnReadCompleted(request_id, bytes_read); 127 } 128 129 bool SafeBrowsingResourceHandler::OnResponseCompleted( 130 int request_id, const net::URLRequestStatus& status, 131 const std::string& security_info) { 132 Shutdown(); 133 return next_handler_->OnResponseCompleted(request_id, status, security_info); 134 } 135 136 void SafeBrowsingResourceHandler::OnRequestClosed() { 137 Shutdown(); 138 next_handler_->OnRequestClosed(); 139 } 140 141 // SafeBrowsingService::Client implementation, called on the IO thread once 142 // the URL has been classified. 143 void SafeBrowsingResourceHandler::OnBrowseUrlCheckResult( 144 const GURL& url, SafeBrowsingService::UrlCheckResult result) { 145 CHECK(state_ == STATE_CHECKING_URL); 146 CHECK(defer_state_ != DEFERRED_NONE); 147 CHECK(url == deferred_url_) << "Was expecting: " << deferred_url_ 148 << " but got: " << url; 149 150 timer_.Stop(); // Cancel the timeout timer. 151 safe_browsing_result_ = result; 152 state_ = STATE_NONE; 153 154 if (result == SafeBrowsingService::SAFE) { 155 // Log how much time the safe browsing check cost us. 156 base::TimeDelta pause_delta; 157 pause_delta = base::TimeTicks::Now() - url_check_start_time_; 158 safe_browsing_->LogPauseDelay(pause_delta); 159 160 // Continue the request. 161 ResumeRequest(); 162 } else { 163 const net::URLRequest* request = rdh_->GetURLRequest( 164 GlobalRequestID(render_process_host_id_, deferred_request_id_)); 165 if (request->load_flags() & net::LOAD_PREFETCH) { 166 // Don't prefetch resources that fail safe browsing, disallow 167 // them. 168 rdh_->CancelRequest(render_process_host_id_, deferred_request_id_, false); 169 } else { 170 StartDisplayingBlockingPage(url, result); 171 } 172 } 173 174 Release(); // Balances the AddRef() in CheckingUrl(). 175 } 176 177 void SafeBrowsingResourceHandler::StartDisplayingBlockingPage( 178 const GURL& url, 179 SafeBrowsingService::UrlCheckResult result) { 180 CHECK(state_ == STATE_NONE); 181 CHECK(defer_state_ != DEFERRED_NONE); 182 CHECK(deferred_request_id_ != -1); 183 184 state_ = STATE_DISPLAYING_BLOCKING_PAGE; 185 AddRef(); // Balanced in OnBlockingPageComplete(). 186 187 // Grab the original url of this request as well. 188 GURL original_url; 189 net::URLRequest* request = rdh_->GetURLRequest( 190 GlobalRequestID(render_process_host_id_, deferred_request_id_)); 191 if (request) 192 original_url = request->original_url(); 193 else 194 original_url = url; 195 196 safe_browsing_->DisplayBlockingPage( 197 url, original_url, redirect_urls_, resource_type_, 198 result, this, render_process_host_id_, render_view_id_); 199 } 200 201 // SafeBrowsingService::Client implementation, called on the IO thread when 202 // the user has decided to proceed with the current request, or go back. 203 void SafeBrowsingResourceHandler::OnBlockingPageComplete(bool proceed) { 204 CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE); 205 state_ = STATE_NONE; 206 207 if (proceed) { 208 safe_browsing_result_ = SafeBrowsingService::SAFE; 209 net::URLRequest* request = rdh_->GetURLRequest( 210 GlobalRequestID(render_process_host_id_, deferred_request_id_)); 211 212 // The request could be canceled by renderer at this stage. 213 // As a result, click proceed will do nothing (crbug.com/76460). 214 if (request) 215 ResumeRequest(); 216 } else { 217 rdh_->CancelRequest(render_process_host_id_, deferred_request_id_, false); 218 } 219 220 Release(); // Balances the AddRef() in StartDisplayingBlockingPage(). 221 } 222 223 void SafeBrowsingResourceHandler::Shutdown() { 224 if (state_ == STATE_CHECKING_URL) { 225 timer_.Stop(); 226 safe_browsing_->CancelCheck(this); 227 state_ = STATE_NONE; 228 // Balance the AddRef() from CheckUrl() which would ordinarily be 229 // balanced by OnUrlCheckResult(). 230 Release(); 231 } 232 } 233 234 bool SafeBrowsingResourceHandler::CheckUrl(const GURL& url) { 235 CHECK(state_ == STATE_NONE); 236 bool succeeded_synchronously = safe_browsing_->CheckBrowseUrl(url, this); 237 if (succeeded_synchronously) { 238 safe_browsing_result_ = SafeBrowsingService::SAFE; 239 safe_browsing_->LogPauseDelay(base::TimeDelta()); // No delay. 240 return true; 241 } 242 243 AddRef(); // Balanced in OnUrlCheckResult(). 244 state_ = STATE_CHECKING_URL; 245 246 // Record the start time of the check. 247 url_check_start_time_ = base::TimeTicks::Now(); 248 249 // Start a timer to abort the check if it takes too long. 250 timer_.Start(base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), 251 this, &SafeBrowsingResourceHandler::OnCheckUrlTimeout); 252 253 return false; 254 } 255 256 void SafeBrowsingResourceHandler::ResumeRequest() { 257 CHECK(state_ == STATE_NONE); 258 CHECK(defer_state_ != DEFERRED_NONE); 259 260 // Resume whatever stage got paused by the safe browsing check. 261 switch (defer_state_) { 262 case DEFERRED_START: 263 ResumeStart(); 264 break; 265 case DEFERRED_REDIRECT: 266 ResumeRedirect(); 267 break; 268 case DEFERRED_NONE: 269 NOTREACHED(); 270 break; 271 } 272 } 273 274 void SafeBrowsingResourceHandler::ResumeStart() { 275 CHECK(defer_state_ == DEFERRED_START); 276 CHECK(deferred_request_id_ != -1); 277 defer_state_ = DEFERRED_NONE; 278 279 // Retrieve the details for the paused OnWillStart(). 280 int request_id = deferred_request_id_; 281 GURL url = deferred_url_; 282 283 ClearDeferredRequestInfo(); 284 285 // Give the other resource handlers a chance to defer starting. 286 bool defer = false; 287 // TODO(eroman): the return value is being lost here. Should 288 // use it to cancel the request. 289 next_handler_->OnWillStart(request_id, url, &defer); 290 if (!defer) 291 rdh_->StartDeferredRequest(render_process_host_id_, request_id); 292 } 293 294 void SafeBrowsingResourceHandler::ResumeRedirect() { 295 CHECK(defer_state_ == DEFERRED_REDIRECT); 296 defer_state_ = DEFERRED_NONE; 297 298 // Retrieve the details for the paused OnReceivedRedirect(). 299 int request_id = deferred_request_id_; 300 GURL redirect_url = deferred_url_; 301 scoped_refptr<ResourceResponse> redirect_response = 302 deferred_redirect_response_; 303 304 ClearDeferredRequestInfo(); 305 306 // Give the other resource handlers a chance to handle the redirect. 307 bool defer = false; 308 // TODO(eroman): the return value is being lost here. Should 309 // use it to cancel the request. 310 next_handler_->OnRequestRedirected(request_id, redirect_url, 311 redirect_response, &defer); 312 if (!defer) { 313 rdh_->FollowDeferredRedirect(render_process_host_id_, request_id, 314 false, GURL()); 315 } 316 } 317 318 void SafeBrowsingResourceHandler::ClearDeferredRequestInfo() { 319 deferred_request_id_ = -1; 320 deferred_url_ = GURL(); 321 deferred_redirect_response_ = NULL; 322 } 323