Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: chrome/browser/renderer_host/safe_browsing_resource_throttle.cc

Issue 1241583009: Async Safe Browsing check, on mobile (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Respond to reviews Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h" 5 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/prerender/prerender_contents.h" 9 #include "chrome/browser/prerender/prerender_contents.h"
10 #include "chrome/browser/safe_browsing/safe_browsing_service.h" 10 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
(...skipping 10 matching lines...) Expand all
21 // verify a URL. After this amount of time the outstanding check will be 21 // verify a URL. After this amount of time the outstanding check will be
22 // aborted, and the URL will be treated as if it were safe. 22 // aborted, and the URL will be treated as if it were safe.
23 static const int kCheckUrlTimeoutMs = 5000; 23 static const int kCheckUrlTimeoutMs = 5000;
24 24
25 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more 25 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
26 // unit test coverage. 26 // unit test coverage.
27 27
28 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle( 28 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle(
29 const net::URLRequest* request, 29 const net::URLRequest* request,
30 content::ResourceType resource_type, 30 content::ResourceType resource_type,
31 SafeBrowsingService* safe_browsing) 31 SafeBrowsingService* safe_browsing,
32 : state_(STATE_NONE), 32 bool defer_at_start)
33 : defer_at_start_(defer_at_start),
34 state_(STATE_NONE),
33 defer_state_(DEFERRED_NONE), 35 defer_state_(DEFERRED_NONE),
34 threat_type_(SB_THREAT_TYPE_SAFE), 36 threat_type_(SB_THREAT_TYPE_SAFE),
35 database_manager_(safe_browsing->database_manager()), 37 database_manager_(safe_browsing->database_manager()),
36 ui_manager_(safe_browsing->ui_manager()), 38 ui_manager_(safe_browsing->ui_manager()),
37 request_(request), 39 request_(request),
38 is_subresource_(resource_type != content::RESOURCE_TYPE_MAIN_FRAME), 40 is_subresource_(resource_type != content::RESOURCE_TYPE_MAIN_FRAME),
39 is_subframe_(resource_type == content::RESOURCE_TYPE_SUB_FRAME) { 41 is_subframe_(resource_type == content::RESOURCE_TYPE_SUB_FRAME) {
40 } 42 }
41 43
42 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() { 44 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {
43 if (state_ == STATE_CHECKING_URL) 45 if (state_ == STATE_CHECKING_URL)
44 database_manager_->CancelCheck(this); 46 database_manager_->CancelCheck(this);
45 } 47 }
46 48
47 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) { 49 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) {
48 // We need to check the new URL before starting the request. 50 // We need to check the new URL before starting the request.
49 if (CheckUrl(request_->url())) 51 if (CheckUrl(request_->url()))
50 return; 52 return;
51 53
54 if (!defer_at_start_)
55 return;
56
52 // If the URL couldn't be verified synchronously, defer starting the 57 // If the URL couldn't be verified synchronously, defer starting the
53 // request until the check has completed. 58 // request until the check has completed.
54 defer_state_ = DEFERRED_START; 59 defer_state_ = DEFERRED_START;
60 defer_start_time_ = base::TimeTicks::Now();
55 *defer = true; 61 *defer = true;
56 } 62 }
57 63
64 void SafeBrowsingResourceThrottle::WillProcessResponse(bool* defer) {
65 CHECK_EQ(defer_state_, DEFERRED_NONE);
66 if (defer_at_start_)
67 return;
68
69 if (state_ == STATE_CHECKING_URL ||
70 state_ == STATE_DISPLAYING_BLOCKING_PAGE) {
71 defer_state_ = DEFERRED_PROCESSING;
72 defer_start_time_ = base::TimeTicks::Now();
73 *defer = true;
74 }
75 }
76
58 void SafeBrowsingResourceThrottle::WillRedirectRequest( 77 void SafeBrowsingResourceThrottle::WillRedirectRequest(
59 const net::RedirectInfo& redirect_info, 78 const net::RedirectInfo& redirect_info,
60 bool* defer) { 79 bool* defer) {
61 CHECK(state_ == STATE_NONE); 80 CHECK_EQ(defer_state_, DEFERRED_NONE);
62 CHECK(defer_state_ == DEFERRED_NONE);
63 81
64 // Save the redirect urls for possible malware detail reporting later. 82 // Save the redirect urls for possible malware detail reporting later.
65 redirect_urls_.push_back(redirect_info.new_url); 83 redirect_urls_.push_back(redirect_info.new_url);
mattm 2015/07/29 19:39:58 Doing it here means that if there is an in-progres
Nathan Parker 2015/07/30 18:42:52 I switched to do it only when the check is done.
mattm 2015/07/30 19:50:15 It should be fine to do it before the check, if it
Nathan Parker 2015/07/30 19:58:19 Done.
66 84
67 // We need to check the new URL before following the redirect. 85 // Prev check completed and was safe.
68 if (CheckUrl(redirect_info.new_url)) 86 if (state_ == STATE_NONE) {
69 return; 87 // We need to check the new URL before following the redirect.
88 if (CheckUrl(redirect_info.new_url))
89 return;
90 defer_state_ = DEFERRED_REDIRECT;
91 } else {
92 CHECK(state_ == STATE_CHECKING_URL ||
93 state_ == STATE_DISPLAYING_BLOCKING_PAGE);
94 // We can't check this new URL until we have finished checking
95 // the prev one, or resumed from the blocking page.
96 unchecked_redirect_url_ = redirect_info.new_url;
97 defer_state_ = DEFERRED_UNCHECKED_REDIRECT;
98 }
70 99
71 // If the URL couldn't be verified synchronously, defer following the 100 defer_start_time_ = base::TimeTicks::Now();
72 // redirect until the SafeBrowsing check is complete. Store the redirect
73 // context so we can pass it on to other handlers once we have completed
74 // our check.
75 defer_state_ = DEFERRED_REDIRECT;
76 *defer = true; 101 *defer = true;
77 } 102 }
78 103
79 const char* SafeBrowsingResourceThrottle::GetNameForLogging() const { 104 const char* SafeBrowsingResourceThrottle::GetNameForLogging() const {
80 return "SafeBrowsingResourceThrottle"; 105 return "SafeBrowsingResourceThrottle";
81 } 106 }
82 107
83 // SafeBrowsingService::Client implementation, called on the IO thread once 108 // SafeBrowsingService::Client implementation, called on the IO thread once
84 // the URL has been classified. 109 // the URL has been classified.
85 void SafeBrowsingResourceThrottle::OnCheckBrowseUrlResult( 110 void SafeBrowsingResourceThrottle::OnCheckBrowseUrlResult(
86 const GURL& url, 111 const GURL& url,
87 SBThreatType threat_type, 112 SBThreatType threat_type,
88 const std::string& metadata) { 113 const std::string& metadata) {
89 CHECK(state_ == STATE_CHECKING_URL); 114 CHECK_EQ(state_, STATE_CHECKING_URL);
90 CHECK(defer_state_ != DEFERRED_NONE); 115 CHECK_EQ(url, url_being_checked_);
91 CHECK(url == url_being_checked_) << "Was expecting: " << url_being_checked_
92 << " but got: " << url;
93 116
94 timer_.Stop(); // Cancel the timeout timer. 117 timer_.Stop(); // Cancel the timeout timer.
95 threat_type_ = threat_type; 118 threat_type_ = threat_type;
96 state_ = STATE_NONE; 119 state_ = STATE_NONE;
97 120
98 if (threat_type == SB_THREAT_TYPE_SAFE) { 121 if (threat_type == SB_THREAT_TYPE_SAFE) {
99 // Log how much time the safe browsing check cost us. 122 if (defer_state_ != DEFERRED_NONE) {
100 ui_manager_->LogPauseDelay(base::TimeTicks::Now() - url_check_start_time_); 123 // Log how much time the safe browsing check cost us.
101 124 ui_manager_->LogPauseDelay(base::TimeTicks::Now() - defer_start_time_);
102 // Continue the request. 125 ResumeRequest();
103 ResumeRequest(); 126 } else {
127 ui_manager_->LogPauseDelay(base::TimeDelta());
128 }
104 return; 129 return;
105 } 130 }
106 131
107 if (request_->load_flags() & net::LOAD_PREFETCH) { 132 if (request_->load_flags() & net::LOAD_PREFETCH) {
108 // Don't prefetch resources that fail safe browsing, disallow 133 // Don't prefetch resources that fail safe browsing, disallow them.
109 // them.
110 controller()->Cancel(); 134 controller()->Cancel();
111 return; 135 return;
112 } 136 }
113 137
114 const content::ResourceRequestInfo* info = 138 const content::ResourceRequestInfo* info =
115 content::ResourceRequestInfo::ForRequest(request_); 139 content::ResourceRequestInfo::ForRequest(request_);
116 140
117 SafeBrowsingUIManager::UnsafeResource resource; 141 SafeBrowsingUIManager::UnsafeResource resource;
118 resource.url = url; 142 resource.url = url;
119 resource.original_url = request_->original_url(); 143 resource.original_url = request_->original_url();
(...skipping 13 matching lines...) Expand all
133 content::BrowserThread::UI, 157 content::BrowserThread::UI,
134 FROM_HERE, 158 FROM_HERE,
135 base::Bind(&SafeBrowsingResourceThrottle::StartDisplayingBlockingPage, 159 base::Bind(&SafeBrowsingResourceThrottle::StartDisplayingBlockingPage,
136 AsWeakPtr(), ui_manager_, resource)); 160 AsWeakPtr(), ui_manager_, resource));
137 } 161 }
138 162
139 void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage( 163 void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage(
140 const base::WeakPtr<SafeBrowsingResourceThrottle>& throttle, 164 const base::WeakPtr<SafeBrowsingResourceThrottle>& throttle,
141 scoped_refptr<SafeBrowsingUIManager> ui_manager, 165 scoped_refptr<SafeBrowsingUIManager> ui_manager,
142 const SafeBrowsingUIManager::UnsafeResource& resource) { 166 const SafeBrowsingUIManager::UnsafeResource& resource) {
143 bool should_show_blocking_page = true;
144
145 content::RenderViewHost* rvh = content::RenderViewHost::FromID( 167 content::RenderViewHost* rvh = content::RenderViewHost::FromID(
146 resource.render_process_host_id, resource.render_view_id); 168 resource.render_process_host_id, resource.render_view_id);
147 if (rvh) { 169 if (rvh) {
148 content::WebContents* web_contents = 170 content::WebContents* web_contents =
149 content::WebContents::FromRenderViewHost(rvh); 171 content::WebContents::FromRenderViewHost(rvh);
150 prerender::PrerenderContents* prerender_contents = 172 prerender::PrerenderContents* prerender_contents =
151 prerender::PrerenderContents::FromWebContents(web_contents); 173 prerender::PrerenderContents::FromWebContents(web_contents);
174
152 if (prerender_contents) { 175 if (prerender_contents) {
153 prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING); 176 prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
154 should_show_blocking_page = false; 177 } else {
155 }
156
157 if (should_show_blocking_page) {
158 ui_manager->DisplayBlockingPage(resource); 178 ui_manager->DisplayBlockingPage(resource);
159 return; 179 return;
160 } 180 }
161 } 181 }
162 182
163 // Tab is gone or it's being prerendered. 183 // Tab is gone or it's being prerendered.
164 content::BrowserThread::PostTask( 184 content::BrowserThread::PostTask(
165 content::BrowserThread::IO, 185 content::BrowserThread::IO,
166 FROM_HERE, 186 FROM_HERE,
167 base::Bind(&SafeBrowsingResourceThrottle::Cancel, throttle)); 187 base::Bind(&SafeBrowsingResourceThrottle::Cancel, throttle));
168 } 188 }
169 189
170 void SafeBrowsingResourceThrottle::Cancel() { 190 void SafeBrowsingResourceThrottle::Cancel() {
171 controller()->Cancel(); 191 controller()->Cancel();
172 } 192 }
173 193
174 // SafeBrowsingService::UrlCheckCallback implementation, called on the IO 194 // SafeBrowsingService::UrlCheckCallback implementation, called on the IO
175 // thread when the user has decided to proceed with the current request, or 195 // thread when the user has decided to proceed with the current request, or
176 // go back. 196 // go back.
177 void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed) { 197 void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed) {
178 CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE); 198 CHECK_EQ(state_, STATE_DISPLAYING_BLOCKING_PAGE);
179 state_ = STATE_NONE; 199 state_ = STATE_NONE;
180 200
181 if (proceed) { 201 if (proceed) {
182 threat_type_ = SB_THREAT_TYPE_SAFE; 202 threat_type_ = SB_THREAT_TYPE_SAFE;
183 ResumeRequest(); 203 if (defer_state_ != DEFERRED_NONE) {
204 ResumeRequest();
205 }
184 } else { 206 } else {
185 controller()->Cancel(); 207 controller()->Cancel();
186 } 208 }
187 } 209 }
188 210
189 bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) { 211 bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) {
190 CHECK(state_ == STATE_NONE); 212 CHECK_EQ(state_, STATE_NONE);
191 bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this); 213 bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this);
192 if (succeeded_synchronously) { 214 if (succeeded_synchronously) {
193 threat_type_ = SB_THREAT_TYPE_SAFE; 215 threat_type_ = SB_THREAT_TYPE_SAFE;
194 ui_manager_->LogPauseDelay(base::TimeDelta()); // No delay. 216 ui_manager_->LogPauseDelay(base::TimeDelta()); // No delay.
195 return true; 217 return true;
196 } 218 }
197 219
198 state_ = STATE_CHECKING_URL; 220 state_ = STATE_CHECKING_URL;
199 url_being_checked_ = url; 221 url_being_checked_ = url;
200 222
201 // Record the start time of the check.
202 url_check_start_time_ = base::TimeTicks::Now();
203
204 // Start a timer to abort the check if it takes too long. 223 // Start a timer to abort the check if it takes too long.
224 // TODO(nparker): Set this only when we defer, based on remaining time,
225 // so we don't cancel earlier than necessary.
205 timer_.Start(FROM_HERE, 226 timer_.Start(FROM_HERE,
206 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), 227 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
207 this, &SafeBrowsingResourceThrottle::OnCheckUrlTimeout); 228 this, &SafeBrowsingResourceThrottle::OnCheckUrlTimeout);
208 229
209 return false; 230 return false;
210 } 231 }
211 232
212 void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() { 233 void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() {
213 CHECK(state_ == STATE_CHECKING_URL); 234 CHECK_EQ(state_, STATE_CHECKING_URL);
214 CHECK(defer_state_ != DEFERRED_NONE);
215 235
216 database_manager_->CancelCheck(this); 236 database_manager_->CancelCheck(this);
217 OnCheckBrowseUrlResult( 237 OnCheckBrowseUrlResult(
218 url_being_checked_, SB_THREAT_TYPE_SAFE, std::string()); 238 url_being_checked_, SB_THREAT_TYPE_SAFE, std::string());
219 } 239 }
220 240
221 void SafeBrowsingResourceThrottle::ResumeRequest() { 241 void SafeBrowsingResourceThrottle::ResumeRequest() {
222 CHECK(state_ == STATE_NONE); 242 CHECK_EQ(state_, STATE_NONE);
223 CHECK(defer_state_ != DEFERRED_NONE); 243 CHECK_NE(defer_state_, DEFERRED_NONE);
224 244
225 defer_state_ = DEFERRED_NONE; 245 if (defer_state_ == DEFERRED_UNCHECKED_REDIRECT &&
226 controller()->Resume(); 246 !CheckUrl(unchecked_redirect_url_)) {
247 defer_state_ = DEFERRED_REDIRECT;
248 // We're now waiting for the unchecked_redirect_url_.
249 } else {
250 defer_state_ = DEFERRED_NONE;
251 controller()->Resume();
252 }
227 } 253 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698