OLD | NEW |
| (Empty) |
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/safe_browsing/database_manager.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/callback.h" | |
12 #include "base/command_line.h" | |
13 #include "base/debug/leak_tracker.h" | |
14 #include "base/metrics/histogram_macros.h" | |
15 #include "base/stl_util.h" | |
16 #include "base/strings/string_util.h" | |
17 #include "chrome/browser/browser_process.h" | |
18 #include "chrome/browser/chrome_notification_types.h" | |
19 #include "chrome/browser/prerender/prerender_field_trial.h" | |
20 #include "chrome/browser/safe_browsing/client_side_detection_service.h" | |
21 #include "chrome/browser/safe_browsing/download_protection_service.h" | |
22 #include "chrome/browser/safe_browsing/malware_details.h" | |
23 #include "chrome/browser/safe_browsing/protocol_manager.h" | |
24 #include "chrome/browser/safe_browsing/safe_browsing_database.h" | |
25 #include "chrome/browser/safe_browsing/safe_browsing_service.h" | |
26 #include "chrome/browser/safe_browsing/ui_manager.h" | |
27 #include "chrome/common/chrome_constants.h" | |
28 #include "chrome/common/chrome_paths.h" | |
29 #include "chrome/common/chrome_switches.h" | |
30 #include "components/startup_metric_utils/startup_metric_utils.h" | |
31 #include "content/public/browser/browser_thread.h" | |
32 #include "content/public/browser/notification_service.h" | |
33 #include "url/url_constants.h" | |
34 | |
35 using content::BrowserThread; | |
36 | |
37 namespace { | |
38 | |
39 // Timeout for match checks, e.g. download URLs, hashes. | |
40 const int kCheckTimeoutMs = 10000; | |
41 | |
42 // Records disposition information about the check. |hit| should be | |
43 // |true| if there were any prefix hits in |full_hashes|. | |
44 void RecordGetHashCheckStatus( | |
45 bool hit, | |
46 safe_browsing_util::ListType check_type, | |
47 const std::vector<SBFullHashResult>& full_hashes) { | |
48 SafeBrowsingProtocolManager::ResultType result; | |
49 if (full_hashes.empty()) { | |
50 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY; | |
51 } else if (hit) { | |
52 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT; | |
53 } else { | |
54 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS; | |
55 } | |
56 bool is_download = check_type == safe_browsing_util::BINURL; | |
57 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result); | |
58 } | |
59 | |
60 bool IsExpectedThreat( | |
61 const SBThreatType threat_type, | |
62 const std::vector<SBThreatType>& expected_threats) { | |
63 return expected_threats.end() != std::find(expected_threats.begin(), | |
64 expected_threats.end(), | |
65 threat_type); | |
66 } | |
67 | |
68 // Return the severest list id from the results in |full_hashes| which matches | |
69 // |hash|, or INVALID if none match. | |
70 safe_browsing_util::ListType GetHashSeverestThreatListType( | |
71 const SBFullHash& hash, | |
72 const std::vector<SBFullHashResult>& full_hashes, | |
73 size_t* index) { | |
74 safe_browsing_util::ListType pending_threat = safe_browsing_util::INVALID; | |
75 for (size_t i = 0; i < full_hashes.size(); ++i) { | |
76 if (SBFullHashEqual(hash, full_hashes[i].hash)) { | |
77 const safe_browsing_util::ListType threat = | |
78 static_cast<safe_browsing_util::ListType>(full_hashes[i].list_id); | |
79 switch (threat) { | |
80 case safe_browsing_util::INVALID: | |
81 // |full_hashes| should never contain INVALID as a |list_id|. | |
82 NOTREACHED(); | |
83 break; | |
84 case safe_browsing_util::MALWARE: // Falls through. | |
85 case safe_browsing_util::PHISH: // Falls through. | |
86 case safe_browsing_util::BINURL: // Falls through. | |
87 case safe_browsing_util::CSDWHITELIST: // Falls through. | |
88 case safe_browsing_util::DOWNLOADWHITELIST: // Falls through. | |
89 case safe_browsing_util::INCLUSIONWHITELIST: // Falls through. | |
90 case safe_browsing_util::EXTENSIONBLACKLIST: // Falls through. | |
91 case safe_browsing_util::IPBLACKLIST: | |
92 if (index) | |
93 *index = i; | |
94 return threat; | |
95 case safe_browsing_util::UNWANTEDURL: | |
96 // UNWANTEDURL is considered less severe than other threats, keep | |
97 // looking. | |
98 pending_threat = threat; | |
99 if (index) | |
100 *index = i; | |
101 break; | |
102 } | |
103 } | |
104 } | |
105 return pending_threat; | |
106 } | |
107 | |
108 // Given a URL, compare all the possible host + path full hashes to the set of | |
109 // provided full hashes. Returns the list id of the severest matching result | |
110 // from |full_hashes|, or INVALID if none match. | |
111 safe_browsing_util::ListType GetUrlSeverestThreatListType( | |
112 const GURL& url, | |
113 const std::vector<SBFullHashResult>& full_hashes, | |
114 size_t* index) { | |
115 if (full_hashes.empty()) | |
116 return safe_browsing_util::INVALID; | |
117 | |
118 std::vector<std::string> patterns; | |
119 safe_browsing_util::GeneratePatternsToCheck(url, &patterns); | |
120 | |
121 safe_browsing_util::ListType pending_threat = safe_browsing_util::INVALID; | |
122 for (size_t i = 0; i < patterns.size(); ++i) { | |
123 safe_browsing_util::ListType threat = GetHashSeverestThreatListType( | |
124 SBFullHashForString(patterns[i]), full_hashes, index); | |
125 switch (threat) { | |
126 case safe_browsing_util::INVALID: | |
127 // Ignore patterns with no matching threat. | |
128 break; | |
129 case safe_browsing_util::MALWARE: // Falls through. | |
130 case safe_browsing_util::PHISH: // Falls through. | |
131 case safe_browsing_util::BINURL: // Falls through. | |
132 case safe_browsing_util::CSDWHITELIST: // Falls through. | |
133 case safe_browsing_util::DOWNLOADWHITELIST: // Falls through. | |
134 case safe_browsing_util::INCLUSIONWHITELIST: // Falls through. | |
135 case safe_browsing_util::EXTENSIONBLACKLIST: // Falls through. | |
136 case safe_browsing_util::IPBLACKLIST: | |
137 return threat; | |
138 case safe_browsing_util::UNWANTEDURL: | |
139 // UNWANTEDURL is considered less severe than other threats, keep | |
140 // looking. | |
141 pending_threat = threat; | |
142 break; | |
143 } | |
144 } | |
145 return pending_threat; | |
146 } | |
147 | |
148 SBThreatType GetThreatTypeFromListType(safe_browsing_util::ListType list_type) { | |
149 switch (list_type) { | |
150 case safe_browsing_util::PHISH: | |
151 return SB_THREAT_TYPE_URL_PHISHING; | |
152 case safe_browsing_util::MALWARE: | |
153 return SB_THREAT_TYPE_URL_MALWARE; | |
154 case safe_browsing_util::UNWANTEDURL: | |
155 return SB_THREAT_TYPE_URL_UNWANTED; | |
156 case safe_browsing_util::BINURL: | |
157 return SB_THREAT_TYPE_BINARY_MALWARE_URL; | |
158 case safe_browsing_util::EXTENSIONBLACKLIST: | |
159 return SB_THREAT_TYPE_EXTENSION; | |
160 default: | |
161 DVLOG(1) << "Unknown safe browsing list id " << list_type; | |
162 return SB_THREAT_TYPE_SAFE; | |
163 } | |
164 } | |
165 | |
166 } // namespace | |
167 | |
168 // static | |
169 SBThreatType SafeBrowsingDatabaseManager::GetHashSeverestThreatType( | |
170 const SBFullHash& hash, | |
171 const std::vector<SBFullHashResult>& full_hashes) { | |
172 return GetThreatTypeFromListType( | |
173 GetHashSeverestThreatListType(hash, full_hashes, NULL)); | |
174 } | |
175 | |
176 // static | |
177 SBThreatType SafeBrowsingDatabaseManager::GetUrlSeverestThreatType( | |
178 const GURL& url, | |
179 const std::vector<SBFullHashResult>& full_hashes, | |
180 size_t* index) { | |
181 return GetThreatTypeFromListType( | |
182 GetUrlSeverestThreatListType(url, full_hashes, index)); | |
183 } | |
184 | |
185 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck( | |
186 const std::vector<GURL>& urls, | |
187 const std::vector<SBFullHash>& full_hashes, | |
188 Client* client, | |
189 safe_browsing_util::ListType check_type, | |
190 const std::vector<SBThreatType>& expected_threats) | |
191 : urls(urls), | |
192 url_results(urls.size(), SB_THREAT_TYPE_SAFE), | |
193 url_metadata(urls.size()), | |
194 full_hashes(full_hashes), | |
195 full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE), | |
196 client(client), | |
197 need_get_hash(false), | |
198 check_type(check_type), | |
199 expected_threats(expected_threats) { | |
200 DCHECK_EQ(urls.empty(), !full_hashes.empty()) | |
201 << "Exactly one of urls and full_hashes must be set"; | |
202 } | |
203 | |
204 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {} | |
205 | |
206 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult( | |
207 const SafeBrowsingCheck& check) { | |
208 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
209 | |
210 DCHECK_EQ(check.urls.size(), check.url_results.size()); | |
211 DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size()); | |
212 if (!check.urls.empty()) { | |
213 DCHECK(check.full_hashes.empty()); | |
214 switch (check.check_type) { | |
215 case safe_browsing_util::MALWARE: | |
216 case safe_browsing_util::PHISH: | |
217 case safe_browsing_util::UNWANTEDURL: | |
218 DCHECK_EQ(1u, check.urls.size()); | |
219 OnCheckBrowseUrlResult( | |
220 check.urls[0], check.url_results[0], check.url_metadata[0]); | |
221 break; | |
222 case safe_browsing_util::BINURL: | |
223 DCHECK_EQ(check.urls.size(), check.url_results.size()); | |
224 OnCheckDownloadUrlResult( | |
225 check.urls, | |
226 *std::max_element(check.url_results.begin(), | |
227 check.url_results.end())); | |
228 break; | |
229 default: | |
230 NOTREACHED(); | |
231 } | |
232 } else if (!check.full_hashes.empty()) { | |
233 switch (check.check_type) { | |
234 case safe_browsing_util::EXTENSIONBLACKLIST: { | |
235 std::set<std::string> unsafe_extension_ids; | |
236 for (size_t i = 0; i < check.full_hashes.size(); ++i) { | |
237 std::string extension_id = | |
238 safe_browsing_util::SBFullHashToString(check.full_hashes[i]); | |
239 if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION) | |
240 unsafe_extension_ids.insert(extension_id); | |
241 } | |
242 OnCheckExtensionsResult(unsafe_extension_ids); | |
243 break; | |
244 } | |
245 default: | |
246 NOTREACHED(); | |
247 } | |
248 } else { | |
249 NOTREACHED(); | |
250 } | |
251 } | |
252 | |
253 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager( | |
254 const scoped_refptr<SafeBrowsingService>& service) | |
255 : sb_service_(service), | |
256 database_(NULL), | |
257 enabled_(false), | |
258 enable_download_protection_(false), | |
259 enable_csd_whitelist_(false), | |
260 enable_download_whitelist_(false), | |
261 enable_extension_blacklist_(false), | |
262 enable_ip_blacklist_(false), | |
263 enable_unwanted_software_blacklist_(false), | |
264 update_in_progress_(false), | |
265 database_update_in_progress_(false), | |
266 closing_database_(false), | |
267 check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) { | |
268 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
269 DCHECK(sb_service_.get() != NULL); | |
270 | |
271 // Android only supports a subset of FULL_SAFE_BROWSING. | |
272 // TODO(shess): This shouldn't be OS-driven <http://crbug.com/394379> | |
273 #if !defined(OS_ANDROID) | |
274 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess(); | |
275 enable_download_protection_ = | |
276 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection); | |
277 | |
278 // We only download the csd-whitelist if client-side phishing detection is | |
279 // enabled. | |
280 enable_csd_whitelist_ = | |
281 !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection); | |
282 | |
283 // TODO(noelutz): remove this boolean variable since it should always be true | |
284 // if SafeBrowsing is enabled. Unfortunately, we have no test data for this | |
285 // list right now. This means that we need to be able to disable this list | |
286 // for the SafeBrowsing test to pass. | |
287 enable_download_whitelist_ = enable_csd_whitelist_; | |
288 | |
289 // TODO(kalman): there really shouldn't be a flag for this. | |
290 enable_extension_blacklist_ = | |
291 !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist); | |
292 | |
293 // The client-side IP blacklist feature is tightly integrated with client-side | |
294 // phishing protection for now. | |
295 enable_ip_blacklist_ = enable_csd_whitelist_; | |
296 | |
297 // The UwS blacklist feature is controlled by a flag for M40. | |
298 enable_unwanted_software_blacklist_ = | |
299 safe_browsing_util::GetUnwantedTrialGroup() > safe_browsing_util::UWS_OFF; | |
300 #endif | |
301 } | |
302 | |
303 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() { | |
304 // The DCHECK is disabled due to crbug.com/438754. | |
305 // DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
306 | |
307 // We should have already been shut down. If we're still enabled, then the | |
308 // database isn't going to be closed properly, which could lead to corruption. | |
309 DCHECK(!enabled_); | |
310 } | |
311 | |
312 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const { | |
313 return url.SchemeIs(url::kFtpScheme) || | |
314 url.SchemeIs(url::kHttpScheme) || | |
315 url.SchemeIs(url::kHttpsScheme); | |
316 } | |
317 | |
318 bool SafeBrowsingDatabaseManager::CheckDownloadUrl( | |
319 const std::vector<GURL>& url_chain, | |
320 Client* client) { | |
321 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
322 if (!enabled_ || !enable_download_protection_) | |
323 return true; | |
324 | |
325 // We need to check the database for url prefix, and later may fetch the url | |
326 // from the safebrowsing backends. These need to be asynchronous. | |
327 SafeBrowsingCheck* check = | |
328 new SafeBrowsingCheck(url_chain, | |
329 std::vector<SBFullHash>(), | |
330 client, | |
331 safe_browsing_util::BINURL, | |
332 std::vector<SBThreatType>(1, | |
333 SB_THREAT_TYPE_BINARY_MALWARE_URL)); | |
334 std::vector<SBPrefix> prefixes; | |
335 SafeBrowsingDatabase::GetDownloadUrlPrefixes(url_chain, &prefixes); | |
336 StartSafeBrowsingCheck( | |
337 check, | |
338 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this, | |
339 prefixes)); | |
340 return false; | |
341 } | |
342 | |
343 bool SafeBrowsingDatabaseManager::CheckExtensionIDs( | |
344 const std::set<std::string>& extension_ids, | |
345 Client* client) { | |
346 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
347 | |
348 if (!enabled_ || !enable_extension_blacklist_) | |
349 return true; | |
350 | |
351 std::vector<SBFullHash> extension_id_hashes; | |
352 std::transform(extension_ids.begin(), extension_ids.end(), | |
353 std::back_inserter(extension_id_hashes), | |
354 safe_browsing_util::StringToSBFullHash); | |
355 std::vector<SBPrefix> prefixes; | |
356 for (const SBFullHash& hash : extension_id_hashes) | |
357 prefixes.push_back(hash.prefix); | |
358 | |
359 SafeBrowsingCheck* check = new SafeBrowsingCheck( | |
360 std::vector<GURL>(), | |
361 extension_id_hashes, | |
362 client, | |
363 safe_browsing_util::EXTENSIONBLACKLIST, | |
364 std::vector<SBThreatType>(1, SB_THREAT_TYPE_EXTENSION)); | |
365 StartSafeBrowsingCheck( | |
366 check, | |
367 base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread, | |
368 this, prefixes)); | |
369 return false; | |
370 } | |
371 | |
372 bool SafeBrowsingDatabaseManager::MatchMalwareIP( | |
373 const std::string& ip_address) { | |
374 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
375 if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) { | |
376 return false; // Fail open. | |
377 } | |
378 return database_->ContainsMalwareIP(ip_address); | |
379 } | |
380 | |
381 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) { | |
382 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
383 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) { | |
384 // There is something funky going on here -- for example, perhaps the user | |
385 // has not restarted since enabling metrics reporting, so we haven't | |
386 // enabled the csd whitelist yet. Just to be safe we return true in this | |
387 // case. | |
388 return true; | |
389 } | |
390 return database_->ContainsCsdWhitelistedUrl(url); | |
391 } | |
392 | |
393 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) { | |
394 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
395 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) { | |
396 return true; | |
397 } | |
398 return database_->ContainsDownloadWhitelistedUrl(url); | |
399 } | |
400 | |
401 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString( | |
402 const std::string& str) { | |
403 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
404 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) { | |
405 return true; | |
406 } | |
407 return database_->ContainsDownloadWhitelistedString(str); | |
408 } | |
409 | |
410 bool SafeBrowsingDatabaseManager::MatchInclusionWhitelistUrl(const GURL& url) { | |
411 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
412 if (!enabled_ || !MakeDatabaseAvailable()) | |
413 return true; | |
414 return database_->ContainsInclusionWhitelistedUrl(url); | |
415 } | |
416 | |
417 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() { | |
418 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
419 if (!enabled_ || !MakeDatabaseAvailable()) { | |
420 return true; | |
421 } | |
422 return database_->IsMalwareIPMatchKillSwitchOn(); | |
423 } | |
424 | |
425 bool SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() { | |
426 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
427 if (!enabled_ || !MakeDatabaseAvailable()) { | |
428 return true; | |
429 } | |
430 return database_->IsCsdWhitelistKillSwitchOn(); | |
431 } | |
432 | |
433 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url, | |
434 Client* client) { | |
435 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
436 if (!enabled_) | |
437 return true; | |
438 | |
439 if (!CanCheckUrl(url)) | |
440 return true; | |
441 | |
442 std::vector<SBThreatType> expected_threats; | |
443 expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE); | |
444 expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING); | |
445 expected_threats.push_back(SB_THREAT_TYPE_URL_UNWANTED); | |
446 | |
447 const base::TimeTicks start = base::TimeTicks::Now(); | |
448 if (!MakeDatabaseAvailable()) { | |
449 QueuedCheck queued_check(safe_browsing_util::MALWARE, // or PHISH | |
450 client, | |
451 url, | |
452 expected_threats, | |
453 start); | |
454 queued_checks_.push_back(queued_check); | |
455 return false; | |
456 } | |
457 | |
458 // Cache hits should, in general, be the same for both (ignoring potential | |
459 // cache evictions in the second call for entries that were just about to be | |
460 // evicted in the first call). | |
461 // TODO(gab): Refactor SafeBrowsingDatabase to avoid depending on this here. | |
462 std::vector<SBFullHashResult> cache_hits; | |
463 | |
464 std::vector<SBPrefix> browse_prefix_hits; | |
465 bool browse_prefix_match = database_->ContainsBrowseUrl( | |
466 url, &browse_prefix_hits, &cache_hits); | |
467 | |
468 std::vector<SBPrefix> unwanted_prefix_hits; | |
469 std::vector<SBFullHashResult> unused_cache_hits; | |
470 bool unwanted_prefix_match = database_->ContainsUnwantedSoftwareUrl( | |
471 url, &unwanted_prefix_hits, &unused_cache_hits); | |
472 | |
473 // Merge the two pre-sorted prefix hits lists. | |
474 // TODO(gab): Refactor SafeBrowsingDatabase for it to return this merged list | |
475 // by default rather than building it here. | |
476 std::vector<SBPrefix> prefix_hits(browse_prefix_hits.size() + | |
477 unwanted_prefix_hits.size()); | |
478 std::merge(browse_prefix_hits.begin(), | |
479 browse_prefix_hits.end(), | |
480 unwanted_prefix_hits.begin(), | |
481 unwanted_prefix_hits.end(), | |
482 prefix_hits.begin()); | |
483 prefix_hits.erase(std::unique(prefix_hits.begin(), prefix_hits.end()), | |
484 prefix_hits.end()); | |
485 | |
486 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start); | |
487 | |
488 if (!browse_prefix_match && !unwanted_prefix_match) | |
489 return true; // URL is okay. | |
490 | |
491 // Needs to be asynchronous, since we could be in the constructor of a | |
492 // ResourceDispatcherHost event handler which can't pause there. | |
493 // This check will ping the Safe Browsing servers and get all lists which it | |
494 // matches. These lists will then be filtered against the |expected_threats| | |
495 // and the result callback for MALWARE (which is the same as for PHISH and | |
496 // UNWANTEDURL) will eventually be invoked with the final decision. | |
497 SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url), | |
498 std::vector<SBFullHash>(), | |
499 client, | |
500 safe_browsing_util::MALWARE, | |
501 expected_threats); | |
502 check->need_get_hash = cache_hits.empty(); | |
503 check->prefix_hits.swap(prefix_hits); | |
504 check->cache_hits.swap(cache_hits); | |
505 checks_.insert(check); | |
506 | |
507 BrowserThread::PostTask( | |
508 BrowserThread::IO, FROM_HERE, | |
509 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check)); | |
510 | |
511 return false; | |
512 } | |
513 | |
514 void SafeBrowsingDatabaseManager::CancelCheck(Client* client) { | |
515 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
516 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) { | |
517 // We can't delete matching checks here because the db thread has a copy of | |
518 // the pointer. Instead, we simply NULL out the client, and when the db | |
519 // thread calls us back, we'll clean up the check. | |
520 if ((*i)->client == client) | |
521 (*i)->client = NULL; | |
522 } | |
523 | |
524 // Scan the queued clients store. Clients may be here if they requested a URL | |
525 // check before the database has finished loading. | |
526 for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin()); | |
527 it != queued_checks_.end(); ) { | |
528 // In this case it's safe to delete matches entirely since nothing has a | |
529 // pointer to them. | |
530 if (it->client == client) | |
531 it = queued_checks_.erase(it); | |
532 else | |
533 ++it; | |
534 } | |
535 } | |
536 | |
537 void SafeBrowsingDatabaseManager::HandleGetHashResults( | |
538 SafeBrowsingCheck* check, | |
539 const std::vector<SBFullHashResult>& full_hashes, | |
540 const base::TimeDelta& cache_lifetime) { | |
541 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
542 | |
543 if (!enabled_) | |
544 return; | |
545 | |
546 // If the service has been shut down, |check| should have been deleted. | |
547 DCHECK(checks_.find(check) != checks_.end()); | |
548 | |
549 // |start| is set before calling |GetFullHash()|, which should be | |
550 // the only path which gets to here. | |
551 DCHECK(!check->start.is_null()); | |
552 UMA_HISTOGRAM_LONG_TIMES("SB2.Network", | |
553 base::TimeTicks::Now() - check->start); | |
554 | |
555 std::vector<SBPrefix> prefixes = check->prefix_hits; | |
556 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here. | |
557 | |
558 // Cache the GetHash results. | |
559 if (cache_lifetime != base::TimeDelta() && MakeDatabaseAvailable()) | |
560 database_->CacheHashResults(prefixes, full_hashes, cache_lifetime); | |
561 } | |
562 | |
563 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) { | |
564 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
565 DCHECK(enabled_); | |
566 DCHECK(!callback.is_null()); | |
567 safe_browsing_task_runner_->PostTask( | |
568 FROM_HERE, | |
569 base::Bind(&SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this, | |
570 callback)); | |
571 } | |
572 | |
573 void SafeBrowsingDatabaseManager::AddChunks( | |
574 const std::string& list, | |
575 scoped_ptr<ScopedVector<SBChunkData> > chunks, | |
576 AddChunksCallback callback) { | |
577 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
578 DCHECK(enabled_); | |
579 DCHECK(!callback.is_null()); | |
580 safe_browsing_task_runner_->PostTask( | |
581 FROM_HERE, base::Bind(&SafeBrowsingDatabaseManager::AddDatabaseChunks, | |
582 this, list, base::Passed(&chunks), callback)); | |
583 } | |
584 | |
585 void SafeBrowsingDatabaseManager::DeleteChunks( | |
586 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) { | |
587 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
588 DCHECK(enabled_); | |
589 safe_browsing_task_runner_->PostTask( | |
590 FROM_HERE, base::Bind(&SafeBrowsingDatabaseManager::DeleteDatabaseChunks, | |
591 this, base::Passed(&chunk_deletes))); | |
592 } | |
593 | |
594 void SafeBrowsingDatabaseManager::UpdateStarted() { | |
595 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
596 DCHECK(enabled_); | |
597 DCHECK(!update_in_progress_); | |
598 update_in_progress_ = true; | |
599 } | |
600 | |
601 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) { | |
602 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
603 DCHECK(enabled_); | |
604 if (update_in_progress_) { | |
605 update_in_progress_ = false; | |
606 safe_browsing_task_runner_->PostTask( | |
607 FROM_HERE, | |
608 base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished, this, | |
609 update_succeeded)); | |
610 } | |
611 } | |
612 | |
613 void SafeBrowsingDatabaseManager::ResetDatabase() { | |
614 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
615 DCHECK(enabled_); | |
616 safe_browsing_task_runner_->PostTask( | |
617 FROM_HERE, | |
618 base::Bind(&SafeBrowsingDatabaseManager::OnResetDatabase, this)); | |
619 } | |
620 | |
621 void SafeBrowsingDatabaseManager::StartOnIOThread() { | |
622 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
623 if (enabled_) | |
624 return; | |
625 | |
626 // Only get a new task runner if there isn't one already. If the service has | |
627 // previously been started and stopped, a task runner could already exist. | |
628 if (!safe_browsing_task_runner_) { | |
629 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); | |
630 safe_browsing_task_runner_ = | |
631 pool->GetSequencedTaskRunnerWithShutdownBehavior( | |
632 pool->GetSequenceToken(), | |
633 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
634 } | |
635 | |
636 enabled_ = true; | |
637 | |
638 MakeDatabaseAvailable(); | |
639 } | |
640 | |
641 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) { | |
642 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
643 | |
644 DoStopOnIOThread(); | |
645 if (shutdown) { | |
646 sb_service_ = NULL; | |
647 } | |
648 } | |
649 | |
650 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished( | |
651 bool update_succeeded) { | |
652 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
653 content::NotificationService::current()->Notify( | |
654 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE, | |
655 content::Source<SafeBrowsingDatabaseManager>(this), | |
656 content::Details<bool>(&update_succeeded)); | |
657 } | |
658 | |
659 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck( | |
660 const safe_browsing_util::ListType check_type, | |
661 Client* client, | |
662 const GURL& url, | |
663 const std::vector<SBThreatType>& expected_threats, | |
664 const base::TimeTicks& start) | |
665 : check_type(check_type), | |
666 client(client), | |
667 url(url), | |
668 expected_threats(expected_threats), | |
669 start(start) { | |
670 } | |
671 | |
672 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() { | |
673 } | |
674 | |
675 void SafeBrowsingDatabaseManager::DoStopOnIOThread() { | |
676 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
677 | |
678 if (!enabled_) | |
679 return; | |
680 | |
681 enabled_ = false; | |
682 | |
683 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. | |
684 while (!queued_checks_.empty()) { | |
685 QueuedCheck queued = queued_checks_.front(); | |
686 if (queued.client) { | |
687 SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url), | |
688 std::vector<SBFullHash>(), | |
689 queued.client, | |
690 queued.check_type, | |
691 queued.expected_threats); | |
692 queued.client->OnSafeBrowsingResult(sb_check); | |
693 } | |
694 queued_checks_.pop_front(); | |
695 } | |
696 | |
697 // Close the database. Cases to avoid: | |
698 // * If |closing_database_| is true, continuing will queue up a second | |
699 // request, |closing_database_| will be reset after handling the first | |
700 // request, and if any functions on the db thread recreate the database, we | |
701 // could start using it on the IO thread and then have the second request | |
702 // handler delete it out from under us. | |
703 // * If |database_| is NULL, then either no creation request is in flight, in | |
704 // which case we don't need to do anything, or one is in flight, in which | |
705 // case the database will be recreated before our deletion request is | |
706 // handled, and could be used on the IO thread in that time period, leading | |
707 // to the same problem as above. | |
708 // Checking DatabaseAvailable() avoids both of these. | |
709 if (DatabaseAvailable()) { | |
710 closing_database_ = true; | |
711 safe_browsing_task_runner_->PostTask( | |
712 FROM_HERE, | |
713 base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this)); | |
714 } | |
715 | |
716 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'. | |
717 // We have to do this after the db thread returns because methods on it can | |
718 // have copies of these pointers, so deleting them might lead to accessing | |
719 // garbage. | |
720 for (CurrentChecks::iterator it = checks_.begin(); | |
721 it != checks_.end(); ++it) { | |
722 SafeBrowsingCheck* check = *it; | |
723 if (check->client) | |
724 check->client->OnSafeBrowsingResult(*check); | |
725 } | |
726 STLDeleteElements(&checks_); | |
727 | |
728 gethash_requests_.clear(); | |
729 } | |
730 | |
731 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const { | |
732 base::AutoLock lock(database_lock_); | |
733 return !closing_database_ && (database_ != NULL); | |
734 } | |
735 | |
736 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() { | |
737 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
738 DCHECK(enabled_); | |
739 if (DatabaseAvailable()) | |
740 return true; | |
741 safe_browsing_task_runner_->PostTask( | |
742 FROM_HERE, | |
743 base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase), | |
744 this)); | |
745 return false; | |
746 } | |
747 | |
748 SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() { | |
749 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
750 | |
751 if (database_) | |
752 return database_; | |
753 startup_metric_utils::ScopedSlowStartupUMA | |
754 scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase"); | |
755 const base::TimeTicks before = base::TimeTicks::Now(); | |
756 | |
757 SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create( | |
758 safe_browsing_task_runner_, enable_download_protection_, | |
759 enable_csd_whitelist_, enable_download_whitelist_, | |
760 enable_extension_blacklist_, enable_ip_blacklist_, | |
761 enable_unwanted_software_blacklist_); | |
762 | |
763 database->Init(SafeBrowsingService::GetBaseFilename()); | |
764 { | |
765 // Acquiring the lock here guarantees correct ordering between the writes to | |
766 // the new database object above, and the setting of |database_| below. | |
767 base::AutoLock lock(database_lock_); | |
768 database_ = database; | |
769 } | |
770 | |
771 BrowserThread::PostTask( | |
772 BrowserThread::IO, FROM_HERE, | |
773 base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this)); | |
774 | |
775 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before); | |
776 return database_; | |
777 } | |
778 | |
779 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) { | |
780 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
781 | |
782 if (!enabled_) | |
783 return; | |
784 | |
785 // If the service has been shut down, |check| should have been deleted. | |
786 DCHECK(checks_.find(check) != checks_.end()); | |
787 | |
788 if (check->client && check->need_get_hash) { | |
789 // We have a partial match so we need to query Google for the full hash. | |
790 // Clean up will happen in HandleGetHashResults. | |
791 | |
792 // See if we have a GetHash request already in progress for this particular | |
793 // prefix. If so, we just append ourselves to the list of interested parties | |
794 // when the results arrive. We only do this for checks involving one prefix, | |
795 // since that is the common case (multiple prefixes will issue the request | |
796 // as normal). | |
797 if (check->prefix_hits.size() == 1) { | |
798 SBPrefix prefix = check->prefix_hits[0]; | |
799 GetHashRequests::iterator it = gethash_requests_.find(prefix); | |
800 if (it != gethash_requests_.end()) { | |
801 // There's already a request in progress. | |
802 it->second.push_back(check); | |
803 return; | |
804 } | |
805 | |
806 // No request in progress, so we're the first for this prefix. | |
807 GetHashRequestors requestors; | |
808 requestors.push_back(check); | |
809 gethash_requests_[prefix] = requestors; | |
810 } | |
811 | |
812 // Reset the start time so that we can measure the network time without the | |
813 // database time. | |
814 check->start = base::TimeTicks::Now(); | |
815 // Note: If |this| is deleted or stopped, the protocol_manager will | |
816 // be destroyed as well - hence it's OK to do unretained in this case. | |
817 bool is_download = check->check_type == safe_browsing_util::BINURL; | |
818 sb_service_->protocol_manager()->GetFullHash( | |
819 check->prefix_hits, | |
820 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults, | |
821 base::Unretained(this), | |
822 check), | |
823 is_download); | |
824 } else { | |
825 // We may have cached results for previous GetHash queries. Since | |
826 // this data comes from cache, don't histogram hits. | |
827 HandleOneCheck(check, check->cache_hits); | |
828 } | |
829 } | |
830 | |
831 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase( | |
832 GetChunksCallback callback) { | |
833 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
834 | |
835 bool database_error = true; | |
836 std::vector<SBListChunkRanges> lists; | |
837 DCHECK(!database_update_in_progress_); | |
838 database_update_in_progress_ = true; | |
839 GetDatabase(); // This guarantees that |database_| is non-NULL. | |
840 if (database_->UpdateStarted(&lists)) { | |
841 database_error = false; | |
842 } else { | |
843 database_->UpdateFinished(false); | |
844 } | |
845 | |
846 BrowserThread::PostTask( | |
847 BrowserThread::IO, FROM_HERE, | |
848 base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase, | |
849 this, lists, database_error, callback)); | |
850 } | |
851 | |
852 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase( | |
853 const std::vector<SBListChunkRanges>& lists, bool database_error, | |
854 GetChunksCallback callback) { | |
855 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
856 if (enabled_) | |
857 callback.Run(lists, database_error); | |
858 } | |
859 | |
860 void SafeBrowsingDatabaseManager::OnAddChunksComplete( | |
861 AddChunksCallback callback) { | |
862 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
863 if (enabled_) | |
864 callback.Run(); | |
865 } | |
866 | |
867 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() { | |
868 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
869 if (!enabled_) | |
870 return; | |
871 | |
872 LOCAL_HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size()); | |
873 if (queued_checks_.empty()) | |
874 return; | |
875 | |
876 // If the database isn't already available, calling CheckUrl() in the loop | |
877 // below will add the check back to the queue, and we'll infinite-loop. | |
878 DCHECK(DatabaseAvailable()); | |
879 while (!queued_checks_.empty()) { | |
880 QueuedCheck check = queued_checks_.front(); | |
881 DCHECK(!check.start.is_null()); | |
882 LOCAL_HISTOGRAM_TIMES("SB.QueueDelay", | |
883 base::TimeTicks::Now() - check.start); | |
884 // If CheckUrl() determines the URL is safe immediately, it doesn't call the | |
885 // client's handler function (because normally it's being directly called by | |
886 // the client). Since we're not the client, we have to convey this result. | |
887 if (check.client && CheckBrowseUrl(check.url, check.client)) { | |
888 SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url), | |
889 std::vector<SBFullHash>(), | |
890 check.client, | |
891 check.check_type, | |
892 check.expected_threats); | |
893 check.client->OnSafeBrowsingResult(sb_check); | |
894 } | |
895 queued_checks_.pop_front(); | |
896 } | |
897 } | |
898 | |
899 void SafeBrowsingDatabaseManager::AddDatabaseChunks( | |
900 const std::string& list_name, | |
901 scoped_ptr<ScopedVector<SBChunkData> > chunks, | |
902 AddChunksCallback callback) { | |
903 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
904 if (chunks) | |
905 GetDatabase()->InsertChunks(list_name, chunks->get()); | |
906 BrowserThread::PostTask( | |
907 BrowserThread::IO, FROM_HERE, | |
908 base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this, | |
909 callback)); | |
910 } | |
911 | |
912 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks( | |
913 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) { | |
914 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
915 if (chunk_deletes) | |
916 GetDatabase()->DeleteChunks(*chunk_deletes); | |
917 } | |
918 | |
919 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished( | |
920 bool update_succeeded) { | |
921 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
922 GetDatabase()->UpdateFinished(update_succeeded); | |
923 DCHECK(database_update_in_progress_); | |
924 database_update_in_progress_ = false; | |
925 BrowserThread::PostTask( | |
926 BrowserThread::UI, FROM_HERE, | |
927 base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished, | |
928 this, update_succeeded)); | |
929 } | |
930 | |
931 void SafeBrowsingDatabaseManager::OnCloseDatabase() { | |
932 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
933 DCHECK(closing_database_); | |
934 | |
935 // Because |closing_database_| is true, nothing on the IO thread will be | |
936 // accessing the database, so it's safe to delete and then NULL the pointer. | |
937 delete database_; | |
938 database_ = NULL; | |
939 | |
940 // Acquiring the lock here guarantees correct ordering between the resetting | |
941 // of |database_| above and of |closing_database_| below, which ensures there | |
942 // won't be a window during which the IO thread falsely believes the database | |
943 // is available. | |
944 base::AutoLock lock(database_lock_); | |
945 closing_database_ = false; | |
946 } | |
947 | |
948 void SafeBrowsingDatabaseManager::OnResetDatabase() { | |
949 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
950 | |
951 GetDatabase()->ResetDatabase(); | |
952 } | |
953 | |
954 void SafeBrowsingDatabaseManager::OnHandleGetHashResults( | |
955 SafeBrowsingCheck* check, | |
956 const std::vector<SBFullHashResult>& full_hashes) { | |
957 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
958 safe_browsing_util::ListType check_type = check->check_type; | |
959 SBPrefix prefix = check->prefix_hits[0]; | |
960 GetHashRequests::iterator it = gethash_requests_.find(prefix); | |
961 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { | |
962 const bool hit = HandleOneCheck(check, full_hashes); | |
963 RecordGetHashCheckStatus(hit, check_type, full_hashes); | |
964 return; | |
965 } | |
966 | |
967 // Call back all interested parties, noting if any has a hit. | |
968 GetHashRequestors& requestors = it->second; | |
969 bool hit = false; | |
970 for (GetHashRequestors::iterator r = requestors.begin(); | |
971 r != requestors.end(); ++r) { | |
972 if (HandleOneCheck(*r, full_hashes)) | |
973 hit = true; | |
974 } | |
975 RecordGetHashCheckStatus(hit, check_type, full_hashes); | |
976 | |
977 gethash_requests_.erase(it); | |
978 } | |
979 | |
980 bool SafeBrowsingDatabaseManager::HandleOneCheck( | |
981 SafeBrowsingCheck* check, | |
982 const std::vector<SBFullHashResult>& full_hashes) { | |
983 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
984 DCHECK(check); | |
985 | |
986 bool is_threat = false; | |
987 | |
988 // TODO(shess): GetHashSeverestThreadListType() contains a loop, | |
989 // GetUrlSeverestThreatListType() a loop around that loop. Having another | |
990 // loop out here concerns me. It is likely that SAFE is an expected outcome, | |
991 // which means all of those loops run to completion. Refactoring this to | |
992 // generate a set of sorted items to compare in sequence would probably | |
993 // improve things. | |
994 // | |
995 // Additionally, the set of patterns generated from the urls is very similar | |
996 // to the patterns generated in ContainsBrowseUrl() and other database checks, | |
997 // which are called from this code. Refactoring that across the checks could | |
998 // interact well with batching the checks here. | |
999 | |
1000 // TODO(gab): Fix the fact that Get(Url|Hash)SeverestThreatType() may return a | |
1001 // threat for which IsExpectedThreat() returns false even if |full_hashes| | |
1002 // actually contains an expected threat. | |
1003 | |
1004 for (size_t i = 0; i < check->urls.size(); ++i) { | |
1005 size_t threat_index; | |
1006 SBThreatType threat = | |
1007 GetUrlSeverestThreatType(check->urls[i], full_hashes, &threat_index); | |
1008 if (threat != SB_THREAT_TYPE_SAFE && | |
1009 IsExpectedThreat(threat, check->expected_threats)) { | |
1010 check->url_results[i] = threat; | |
1011 check->url_metadata[i] = full_hashes[threat_index].metadata; | |
1012 is_threat = true; | |
1013 } | |
1014 } | |
1015 | |
1016 for (size_t i = 0; i < check->full_hashes.size(); ++i) { | |
1017 SBThreatType threat = | |
1018 GetHashSeverestThreatType(check->full_hashes[i], full_hashes); | |
1019 if (threat != SB_THREAT_TYPE_SAFE && | |
1020 IsExpectedThreat(threat, check->expected_threats)) { | |
1021 check->full_hash_results[i] = threat; | |
1022 is_threat = true; | |
1023 } | |
1024 } | |
1025 | |
1026 SafeBrowsingCheckDone(check); | |
1027 return is_threat; | |
1028 } | |
1029 | |
1030 void SafeBrowsingDatabaseManager::OnAsyncCheckDone( | |
1031 SafeBrowsingCheck* check, | |
1032 const std::vector<SBPrefix>& prefix_hits) { | |
1033 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1034 DCHECK(enable_download_protection_); | |
1035 | |
1036 check->prefix_hits = prefix_hits; | |
1037 if (check->prefix_hits.empty()) { | |
1038 SafeBrowsingCheckDone(check); | |
1039 } else { | |
1040 check->need_get_hash = true; | |
1041 OnCheckDone(check); | |
1042 } | |
1043 } | |
1044 | |
1045 std::vector<SBPrefix> SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread( | |
1046 const std::vector<SBPrefix>& prefixes) { | |
1047 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
1048 DCHECK(enable_download_protection_); | |
1049 | |
1050 std::vector<SBPrefix> prefix_hits; | |
1051 const bool result = | |
1052 database_->ContainsDownloadUrlPrefixes(prefixes, &prefix_hits); | |
1053 DCHECK_EQ(result, !prefix_hits.empty()); | |
1054 return prefix_hits; | |
1055 } | |
1056 | |
1057 std::vector<SBPrefix> SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread( | |
1058 const std::vector<SBPrefix>& prefixes) { | |
1059 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread()); | |
1060 | |
1061 std::vector<SBPrefix> prefix_hits; | |
1062 const bool result = | |
1063 database_->ContainsExtensionPrefixes(prefixes, &prefix_hits); | |
1064 DCHECK_EQ(result, !prefix_hits.empty()); | |
1065 return prefix_hits; | |
1066 } | |
1067 | |
1068 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) { | |
1069 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1070 DCHECK(check); | |
1071 | |
1072 if (!enabled_) | |
1073 return; | |
1074 | |
1075 DCHECK(checks_.find(check) != checks_.end()); | |
1076 if (check->client) { | |
1077 check->client->OnSafeBrowsingResult(*check); | |
1078 check->client = NULL; | |
1079 } | |
1080 } | |
1081 | |
1082 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone( | |
1083 SafeBrowsingCheck* check) { | |
1084 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1085 DCHECK(check); | |
1086 | |
1087 if (!enabled_) | |
1088 return; | |
1089 | |
1090 DVLOG(1) << "SafeBrowsingCheckDone"; | |
1091 DCHECK(checks_.find(check) != checks_.end()); | |
1092 if (check->client) | |
1093 check->client->OnSafeBrowsingResult(*check); | |
1094 checks_.erase(check); | |
1095 delete check; | |
1096 } | |
1097 | |
1098 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck( | |
1099 SafeBrowsingCheck* check, | |
1100 const base::Callback<std::vector<SBPrefix>(void)>& task) { | |
1101 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
1102 check->weak_ptr_factory_.reset( | |
1103 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this)); | |
1104 checks_.insert(check); | |
1105 | |
1106 base::PostTaskAndReplyWithResult( | |
1107 safe_browsing_task_runner_.get(), FROM_HERE, task, | |
1108 base::Bind(&SafeBrowsingDatabaseManager::OnAsyncCheckDone, | |
1109 check->weak_ptr_factory_->GetWeakPtr(), check)); | |
1110 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, | |
1111 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback, | |
1112 check->weak_ptr_factory_->GetWeakPtr(), check), | |
1113 check_timeout_); | |
1114 } | |
OLD | NEW |