Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / renderer_host / safe_browsing_resource_throttle.cc
blobc7d53516635fa6964e38cfc745dd53d965a14acd
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.
5 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/prerender/prerender_contents.h"
11 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/render_view_host.h"
14 #include "content/public/browser/resource_controller.h"
15 #include "content/public/browser/resource_request_info.h"
16 #include "content/public/browser/web_contents.h"
17 #include "net/base/load_flags.h"
18 #include "net/url_request/redirect_info.h"
19 #include "net/url_request/url_request.h"
21 namespace {
23 // Maximum time in milliseconds to wait for the safe browsing service to
24 // verify a URL. After this amount of time the outstanding check will be
25 // aborted, and the URL will be treated as if it were safe.
26 const int kCheckUrlTimeoutMs = 5000;
28 // Return true for resource types that are very unlikely to produce a successful
29 // malware or phishing page without the main frame also being bad. This is a
30 // latency / safety trade-off, used only on mobile. We're conservative here,
31 // keeping this list small and leaving off uncommon types since they won't save
32 // us much on aggregate latency.
33 bool IsResourceTypeMostlySafe(content::ResourceType resource_type) {
34 switch (resource_type) {
35 case content::RESOURCE_TYPE_STYLESHEET:
36 case content::RESOURCE_TYPE_IMAGE:
37 case content::RESOURCE_TYPE_FONT_RESOURCE:
38 case content::RESOURCE_TYPE_FAVICON:
39 return true;
40 default:
41 return false;
45 void RecordHistogramResourceTypeSafe(content::ResourceType resource_type) {
46 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Safe", resource_type,
47 content::RESOURCE_TYPE_LAST_TYPE);
50 } // namespace
52 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
53 // unit test coverage.
55 // static
56 SafeBrowsingResourceThrottle* SafeBrowsingResourceThrottle::MaybeCreate(
57 net::URLRequest* request,
58 content::ResourceType resource_type,
59 SafeBrowsingService* sb_service) {
60 #if defined(SAFE_BROWSING_DB_LOCAL)
61 // Throttle consults a local database before starting the resource request.
62 return new SafeBrowsingResourceThrottle(
63 request, resource_type, sb_service, DEFER_AT_START,
64 SafeBrowsingService::CHECK_ALL_RESOURCE_TYPES);
65 #elif defined(SAFE_BROWSING_DB_REMOTE)
66 if (!sb_service->IsAndroidFieldTrialEnabled())
67 return nullptr;
69 // Throttle consults a remote database before processing the response.
70 return new SafeBrowsingResourceThrottle(
71 request, resource_type, sb_service, DONT_DEFER_AT_START,
72 sb_service->GetResourceTypesToCheck());
73 #else
74 #error "Incompatible compile flags for safe_browsing_resource_throttle"
75 #endif
78 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle(
79 const net::URLRequest* request,
80 content::ResourceType resource_type,
81 SafeBrowsingService* sb_service,
82 DeferAtStartSetting defer_setting,
83 SafeBrowsingService::ResourceTypesToCheck resource_types_to_check)
84 : defer_at_start_(defer_setting == DEFER_AT_START),
85 resource_types_to_check_(resource_types_to_check),
86 state_(STATE_NONE),
87 defer_state_(DEFERRED_NONE),
88 threat_type_(SB_THREAT_TYPE_SAFE),
89 database_manager_(sb_service->database_manager()),
90 ui_manager_(sb_service->ui_manager()),
91 request_(request),
92 resource_type_(resource_type) {}
94 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {
95 if (state_ == STATE_CHECKING_URL)
96 database_manager_->CancelCheck(this);
99 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) {
100 // We need to check the new URL before starting the request.
101 if (CheckUrl(request_->url()))
102 return;
104 if (!defer_at_start_)
105 return;
107 // If the URL couldn't be verified synchronously, defer starting the
108 // request until the check has completed.
109 defer_state_ = DEFERRED_START;
110 defer_start_time_ = base::TimeTicks::Now();
111 *defer = true;
114 void SafeBrowsingResourceThrottle::WillProcessResponse(bool* defer) {
115 CHECK_EQ(defer_state_, DEFERRED_NONE);
116 if (defer_at_start_)
117 return;
119 if (state_ == STATE_CHECKING_URL ||
120 state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
121 defer_state_ = DEFERRED_PROCESSING;
122 defer_start_time_ = base::TimeTicks::Now();
123 *defer = true;
127 void SafeBrowsingResourceThrottle::WillRedirectRequest(
128 const net::RedirectInfo& redirect_info,
129 bool* defer) {
130 CHECK_EQ(defer_state_, DEFERRED_NONE);
132 // Prev check completed and was safe.
133 if (state_ == STATE_NONE) {
134 // Save the redirect urls for possible malware detail reporting later.
135 redirect_urls_.push_back(redirect_info.new_url);
137 // We need to check the new URL before following the redirect.
138 if (CheckUrl(redirect_info.new_url))
139 return;
140 defer_state_ = DEFERRED_REDIRECT;
141 } else {
142 CHECK(state_ == STATE_CHECKING_URL ||
143 state_ == STATE_DISPLAYING_BLOCKING_PAGE);
144 // We can't check this new URL until we have finished checking
145 // the prev one, or resumed from the blocking page.
146 unchecked_redirect_url_ = redirect_info.new_url;
147 defer_state_ = DEFERRED_UNCHECKED_REDIRECT;
150 defer_start_time_ = base::TimeTicks::Now();
151 *defer = true;
154 const char* SafeBrowsingResourceThrottle::GetNameForLogging() const {
155 return "SafeBrowsingResourceThrottle";
158 // SafeBrowsingService::Client implementation, called on the IO thread once
159 // the URL has been classified.
160 void SafeBrowsingResourceThrottle::OnCheckBrowseUrlResult(
161 const GURL& url,
162 SBThreatType threat_type,
163 const std::string& metadata) {
164 CHECK_EQ(state_, STATE_CHECKING_URL);
165 CHECK_EQ(url, url_being_checked_);
167 timer_.Stop(); // Cancel the timeout timer.
168 threat_type_ = threat_type;
169 state_ = STATE_NONE;
171 if (threat_type == SB_THREAT_TYPE_SAFE) {
172 RecordHistogramResourceTypeSafe(resource_type_);
173 if (defer_state_ != DEFERRED_NONE) {
174 // Log how much time the safe browsing check cost us.
175 ui_manager_->LogPauseDelay(base::TimeTicks::Now() - defer_start_time_);
176 ResumeRequest();
177 } else {
178 ui_manager_->LogPauseDelay(base::TimeDelta());
180 return;
183 if (request_->load_flags() & net::LOAD_PREFETCH) {
184 // Don't prefetch resources that fail safe browsing, disallow them.
185 controller()->Cancel();
186 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.UnsafePrefetchCanceled",
187 resource_type_, content::RESOURCE_TYPE_LAST_TYPE);
188 return;
191 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Unsafe", resource_type_,
192 content::RESOURCE_TYPE_LAST_TYPE);
194 const content::ResourceRequestInfo* info =
195 content::ResourceRequestInfo::ForRequest(request_);
197 SafeBrowsingUIManager::UnsafeResource resource;
198 resource.url = url;
199 resource.original_url = request_->original_url();
200 resource.redirect_urls = redirect_urls_;
201 resource.is_subresource = resource_type_ != content::RESOURCE_TYPE_MAIN_FRAME;
202 resource.is_subframe = resource_type_ == content::RESOURCE_TYPE_SUB_FRAME;
203 resource.threat_type = threat_type;
204 resource.threat_metadata = metadata;
205 resource.callback = base::Bind(
206 &SafeBrowsingResourceThrottle::OnBlockingPageComplete, AsWeakPtr());
207 resource.render_process_host_id = info->GetChildID();
208 resource.render_view_id = info->GetRouteID();
209 resource.threat_source = SafeBrowsingUIManager::FROM_DEVICE;
211 state_ = STATE_DISPLAYING_BLOCKING_PAGE;
213 content::BrowserThread::PostTask(
214 content::BrowserThread::UI,
215 FROM_HERE,
216 base::Bind(&SafeBrowsingResourceThrottle::StartDisplayingBlockingPage,
217 AsWeakPtr(), ui_manager_, resource));
220 void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage(
221 const base::WeakPtr<SafeBrowsingResourceThrottle>& throttle,
222 scoped_refptr<SafeBrowsingUIManager> ui_manager,
223 const SafeBrowsingUIManager::UnsafeResource& resource) {
224 content::RenderViewHost* rvh = content::RenderViewHost::FromID(
225 resource.render_process_host_id, resource.render_view_id);
226 if (rvh) {
227 content::WebContents* web_contents =
228 content::WebContents::FromRenderViewHost(rvh);
229 prerender::PrerenderContents* prerender_contents =
230 prerender::PrerenderContents::FromWebContents(web_contents);
232 if (prerender_contents) {
233 prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
234 } else {
235 ui_manager->DisplayBlockingPage(resource);
236 return;
240 // Tab is gone or it's being prerendered.
241 content::BrowserThread::PostTask(
242 content::BrowserThread::IO,
243 FROM_HERE,
244 base::Bind(&SafeBrowsingResourceThrottle::Cancel, throttle));
247 void SafeBrowsingResourceThrottle::Cancel() {
248 controller()->Cancel();
251 // SafeBrowsingService::UrlCheckCallback implementation, called on the IO
252 // thread when the user has decided to proceed with the current request, or
253 // go back.
254 void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed) {
255 CHECK_EQ(state_, STATE_DISPLAYING_BLOCKING_PAGE);
256 state_ = STATE_NONE;
258 if (proceed) {
259 threat_type_ = SB_THREAT_TYPE_SAFE;
260 if (defer_state_ != DEFERRED_NONE) {
261 ResumeRequest();
263 } else {
264 controller()->Cancel();
268 bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) {
269 CHECK_EQ(state_, STATE_NONE);
270 // To reduce aggregate latency on mobile, skip checking resources that
271 // can't do much harm.
272 if (resource_types_to_check_ ==
273 SafeBrowsingService::CHECK_ONLY_DANGEROUS_TYPES &&
274 IsResourceTypeMostlySafe(resource_type_)) {
275 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Skipped", resource_type_,
276 content::RESOURCE_TYPE_LAST_TYPE);
277 return true;
280 bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this);
281 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Checked", resource_type_,
282 content::RESOURCE_TYPE_LAST_TYPE);
284 if (succeeded_synchronously) {
285 RecordHistogramResourceTypeSafe(resource_type_);
286 threat_type_ = SB_THREAT_TYPE_SAFE;
287 ui_manager_->LogPauseDelay(base::TimeDelta()); // No delay.
288 return true;
291 state_ = STATE_CHECKING_URL;
292 url_being_checked_ = url;
294 // Start a timer to abort the check if it takes too long.
295 // TODO(nparker): Set this only when we defer, based on remaining time,
296 // so we don't cancel earlier than necessary.
297 timer_.Start(FROM_HERE,
298 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
299 this, &SafeBrowsingResourceThrottle::OnCheckUrlTimeout);
301 return false;
304 void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() {
305 CHECK_EQ(state_, STATE_CHECKING_URL);
307 database_manager_->CancelCheck(this);
308 OnCheckBrowseUrlResult(
309 url_being_checked_, SB_THREAT_TYPE_SAFE, std::string());
312 void SafeBrowsingResourceThrottle::ResumeRequest() {
313 CHECK_EQ(state_, STATE_NONE);
314 CHECK_NE(defer_state_, DEFERRED_NONE);
316 bool resume = true;
317 if (defer_state_ == DEFERRED_UNCHECKED_REDIRECT) {
318 // Save the redirect urls for possible malware detail reporting later.
319 redirect_urls_.push_back(unchecked_redirect_url_);
320 if (!CheckUrl(unchecked_redirect_url_)) {
321 // We're now waiting for the unchecked_redirect_url_.
322 defer_state_ = DEFERRED_REDIRECT;
323 resume = false;
327 if (resume) {
328 defer_state_ = DEFERRED_NONE;
329 controller()->Resume();