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