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