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 "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"
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.
19 static const int kCheckUrlTimeoutMs
= 5000;
21 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
22 // unit test coverage.
24 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle(
25 const net::URLRequest
* request
,
26 int render_process_host_id
,
29 SafeBrowsingService
* safe_browsing
)
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()),
38 is_subresource_(is_subresource
) {
41 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {
42 if (state_
== STATE_CHECKING_URL
)
43 database_manager_
->CancelCheck(this);
46 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer
) {
47 // We need to check the new URL before starting the request.
48 if (CheckUrl(request_
->url()))
51 // If the URL couldn't be verified synchronously, defer starting the
52 // request until the check has completed.
53 defer_state_
= DEFERRED_START
;
57 void SafeBrowsingResourceThrottle::WillRedirectRequest(const GURL
& new_url
,
59 CHECK(state_
== STATE_NONE
);
60 CHECK(defer_state_
== DEFERRED_NONE
);
62 // Save the redirect urls for possible malware detail reporting later.
63 redirect_urls_
.push_back(new_url
);
65 // We need to check the new URL before following the redirect.
66 if (CheckUrl(new_url
))
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
73 defer_state_
= DEFERRED_REDIRECT
;
77 // SafeBrowsingService::Client implementation, called on the IO thread once
78 // the URL has been classified.
79 void 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
;
86 timer_
.Stop(); // Cancel the timeout timer.
87 threat_type_
= threat_type
;
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_
);
94 // Continue the request.
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
101 controller()->Cancel();
102 should_show_blocking_page
= false;
104 ChromeURLRequestUserData
* user_data
=
105 ChromeURLRequestUserData::Get(request_
);
106 if (user_data
&& user_data
->is_prerender()) {
107 prerender::PrerenderTracker
* prerender_tracker
= g_browser_process
->
109 if (prerender_tracker
->TryCancelOnIOThread(
110 render_process_host_id_
,
112 prerender::FINAL_STATUS_SAFE_BROWSING
)) {
113 controller()->Cancel();
114 should_show_blocking_page
= false;
118 if (should_show_blocking_page
)
119 StartDisplayingBlockingPage(url
, threat_type
);
123 void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage(
124 const GURL
& url
, SBThreatType threat_type
) {
125 CHECK(state_
== STATE_NONE
);
126 CHECK(defer_state_
!= DEFERRED_NONE
);
128 state_
= STATE_DISPLAYING_BLOCKING_PAGE
;
130 ui_manager_
->DisplayBlockingPage(
132 request_
->original_url(),
137 &SafeBrowsingResourceThrottle::OnBlockingPageComplete
, AsWeakPtr()),
138 render_process_host_id_
,
142 // SafeBrowsingService::UrlCheckCallback implementation, called on the IO
143 // thread when the user has decided to proceed with the current request, or
145 void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed
) {
146 CHECK(state_
== STATE_DISPLAYING_BLOCKING_PAGE
);
150 threat_type_
= SB_THREAT_TYPE_SAFE
;
153 controller()->Cancel();
157 bool 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.
166 state_
= STATE_CHECKING_URL
;
167 url_being_checked_
= url
;
169 // Record the start time of the check.
170 url_check_start_time_
= base::TimeTicks::Now();
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
);
180 void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() {
181 CHECK(state_
== STATE_CHECKING_URL
);
182 CHECK(defer_state_
!= DEFERRED_NONE
);
184 database_manager_
->CancelCheck(this);
185 OnCheckBrowseUrlResult(url_being_checked_
, SB_THREAT_TYPE_SAFE
);
188 void SafeBrowsingResourceThrottle::ResumeRequest() {
189 CHECK(state_
== STATE_NONE
);
190 CHECK(defer_state_
!= DEFERRED_NONE
);
192 defer_state_
= DEFERRED_NONE
;
193 controller()->Resume();