safe_browsing_resource_throttle.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 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_throttle.h" 6 7#include "base/logging.h" 8#include "chrome/browser/browser_process.h" 9#include "chrome/browser/prerender/prerender_tracker.h" 10#include "chrome/browser/renderer_host/chrome_url_request_user_data.h" 11#include "chrome/browser/safe_browsing/safe_browsing_service.h" 12#include "content/public/browser/resource_controller.h" 13#include "net/base/load_flags.h" 14#include "net/url_request/url_request.h" 15 16// Maximum time in milliseconds to wait for the safe browsing service to 17// verify a URL. After this amount of time the outstanding check will be 18// aborted, and the URL will be treated as if it were safe. 19static const int kCheckUrlTimeoutMs = 5000; 20 21// TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more 22// unit test coverage. 23 24SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle( 25 const net::URLRequest* request, 26 int render_process_host_id, 27 int render_view_id, 28 bool is_subresource, 29 SafeBrowsingService* safe_browsing) 30 : state_(STATE_NONE), 31 defer_state_(DEFERRED_NONE), 32 threat_type_(SB_THREAT_TYPE_SAFE), 33 render_process_host_id_(render_process_host_id), 34 render_view_id_(render_view_id), 35 database_manager_(safe_browsing->database_manager()), 36 ui_manager_(safe_browsing->ui_manager()), 37 request_(request), 38 is_subresource_(is_subresource) { 39} 40 41SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() { 42 if (state_ == STATE_CHECKING_URL) 43 database_manager_->CancelCheck(this); 44} 45 46void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) { 47 // We need to check the new URL before starting the request. 48 if (CheckUrl(request_->url())) 49 return; 50 51 // If the URL couldn't be verified synchronously, defer starting the 52 // request until the check has completed. 53 defer_state_ = DEFERRED_START; 54 *defer = true; 55} 56 57void SafeBrowsingResourceThrottle::WillRedirectRequest(const GURL& new_url, 58 bool* defer) { 59 CHECK(state_ == STATE_NONE); 60 CHECK(defer_state_ == DEFERRED_NONE); 61 62 // Save the redirect urls for possible malware detail reporting later. 63 redirect_urls_.push_back(new_url); 64 65 // We need to check the new URL before following the redirect. 66 if (CheckUrl(new_url)) 67 return; 68 69 // If the URL couldn't be verified synchronously, defer following the 70 // redirect until the SafeBrowsing check is complete. Store the redirect 71 // context so we can pass it on to other handlers once we have completed 72 // our check. 73 defer_state_ = DEFERRED_REDIRECT; 74 *defer = true; 75} 76 77// SafeBrowsingService::Client implementation, called on the IO thread once 78// the URL has been classified. 79void SafeBrowsingResourceThrottle::OnCheckBrowseUrlResult( 80 const GURL& url, SBThreatType threat_type) { 81 CHECK(state_ == STATE_CHECKING_URL); 82 CHECK(defer_state_ != DEFERRED_NONE); 83 CHECK(url == url_being_checked_) << "Was expecting: " << url_being_checked_ 84 << " but got: " << url; 85 86 timer_.Stop(); // Cancel the timeout timer. 87 threat_type_ = threat_type; 88 state_ = STATE_NONE; 89 90 if (threat_type == SB_THREAT_TYPE_SAFE) { 91 // Log how much time the safe browsing check cost us. 92 ui_manager_->LogPauseDelay(base::TimeTicks::Now() - url_check_start_time_); 93 94 // Continue the request. 95 ResumeRequest(); 96 } else { 97 bool should_show_blocking_page = true; 98 if (request_->load_flags() & net::LOAD_PREFETCH) { 99 // Don't prefetch resources that fail safe browsing, disallow 100 // them. 101 controller()->Cancel(); 102 should_show_blocking_page = false; 103 } else { 104 ChromeURLRequestUserData* user_data = 105 ChromeURLRequestUserData::Get(request_); 106 if (user_data && user_data->is_prerender()) { 107 prerender::PrerenderTracker* prerender_tracker = g_browser_process-> 108 prerender_tracker(); 109 if (prerender_tracker->TryCancelOnIOThread( 110 render_process_host_id_, 111 render_view_id_, 112 prerender::FINAL_STATUS_SAFE_BROWSING)) { 113 controller()->Cancel(); 114 should_show_blocking_page = false; 115 } 116 } 117 } 118 if (should_show_blocking_page) 119 StartDisplayingBlockingPage(url, threat_type); 120 } 121} 122 123void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage( 124 const GURL& url, SBThreatType threat_type) { 125 CHECK(state_ == STATE_NONE); 126 CHECK(defer_state_ != DEFERRED_NONE); 127 128 state_ = STATE_DISPLAYING_BLOCKING_PAGE; 129 130 ui_manager_->DisplayBlockingPage( 131 url, 132 request_->original_url(), 133 redirect_urls_, 134 is_subresource_, 135 threat_type, 136 base::Bind( 137 &SafeBrowsingResourceThrottle::OnBlockingPageComplete, AsWeakPtr()), 138 render_process_host_id_, 139 render_view_id_); 140} 141 142// SafeBrowsingService::UrlCheckCallback implementation, called on the IO 143// thread when the user has decided to proceed with the current request, or 144// go back. 145void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed) { 146 CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE); 147 state_ = STATE_NONE; 148 149 if (proceed) { 150 threat_type_ = SB_THREAT_TYPE_SAFE; 151 ResumeRequest(); 152 } else { 153 controller()->Cancel(); 154 } 155} 156 157bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) { 158 CHECK(state_ == STATE_NONE); 159 bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this); 160 if (succeeded_synchronously) { 161 threat_type_ = SB_THREAT_TYPE_SAFE; 162 ui_manager_->LogPauseDelay(base::TimeDelta()); // No delay. 163 return true; 164 } 165 166 state_ = STATE_CHECKING_URL; 167 url_being_checked_ = url; 168 169 // Record the start time of the check. 170 url_check_start_time_ = base::TimeTicks::Now(); 171 172 // Start a timer to abort the check if it takes too long. 173 timer_.Start(FROM_HERE, 174 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), 175 this, &SafeBrowsingResourceThrottle::OnCheckUrlTimeout); 176 177 return false; 178} 179 180void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() { 181 CHECK(state_ == STATE_CHECKING_URL); 182 CHECK(defer_state_ != DEFERRED_NONE); 183 184 database_manager_->CancelCheck(this); 185 OnCheckBrowseUrlResult(url_being_checked_, SB_THREAT_TYPE_SAFE); 186} 187 188void SafeBrowsingResourceThrottle::ResumeRequest() { 189 CHECK(state_ == STATE_NONE); 190 CHECK(defer_state_ != DEFERRED_NONE); 191 192 defer_state_ = DEFERRED_NONE; 193 controller()->Resume(); 194} 195