ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / safe_browsing / database_manager.cc
blobef572f43cbc2842fea55d00609ea453fde9841ca
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/safe_browsing/database_manager.h"
7 #include <algorithm>
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/profiler/scoped_tracker.h"
16 #include "base/stl_util.h"
17 #include "base/strings/string_util.h"
18 #include "base/threading/thread.h"
19 #include "base/threading/thread_restrictions.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/prerender/prerender_field_trial.h"
23 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
24 #include "chrome/browser/safe_browsing/download_protection_service.h"
25 #include "chrome/browser/safe_browsing/malware_details.h"
26 #include "chrome/browser/safe_browsing/protocol_manager.h"
27 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
28 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
29 #include "chrome/browser/safe_browsing/ui_manager.h"
30 #include "chrome/common/chrome_constants.h"
31 #include "chrome/common/chrome_paths.h"
32 #include "chrome/common/chrome_switches.h"
33 #include "components/startup_metric_utils/startup_metric_utils.h"
34 #include "components/variations/variations_associated_data.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
37 #include "url/url_constants.h"
39 using content::BrowserThread;
41 namespace {
43 // Timeout for match checks, e.g. download URLs, hashes.
44 const int kCheckTimeoutMs = 10000;
46 // Records disposition information about the check. |hit| should be
47 // |true| if there were any prefix hits in |full_hashes|.
48 void RecordGetHashCheckStatus(
49 bool hit,
50 safe_browsing_util::ListType check_type,
51 const std::vector<SBFullHashResult>& full_hashes) {
52 SafeBrowsingProtocolManager::ResultType result;
53 if (full_hashes.empty()) {
54 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
55 } else if (hit) {
56 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
57 } else {
58 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
60 bool is_download = check_type == safe_browsing_util::BINURL;
61 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
64 bool IsExpectedThreat(
65 const SBThreatType threat_type,
66 const std::vector<SBThreatType>& expected_threats) {
67 return expected_threats.end() != std::find(expected_threats.begin(),
68 expected_threats.end(),
69 threat_type);
72 // Return the severest list id from the results in |full_hashes| which matches
73 // |hash|, or INVALID if none match.
74 safe_browsing_util::ListType GetHashSeverestThreatListType(
75 const SBFullHash& hash,
76 const std::vector<SBFullHashResult>& full_hashes,
77 size_t* index) {
78 safe_browsing_util::ListType pending_threat = safe_browsing_util::INVALID;
79 for (size_t i = 0; i < full_hashes.size(); ++i) {
80 if (SBFullHashEqual(hash, full_hashes[i].hash)) {
81 const safe_browsing_util::ListType threat =
82 static_cast<safe_browsing_util::ListType>(full_hashes[i].list_id);
83 switch (threat) {
84 case safe_browsing_util::INVALID:
85 // |full_hashes| should never contain INVALID as a |list_id|.
86 NOTREACHED();
87 break;
88 case safe_browsing_util::MALWARE: // Falls through.
89 case safe_browsing_util::PHISH: // Falls through.
90 case safe_browsing_util::BINURL: // Falls through.
91 case safe_browsing_util::CSDWHITELIST: // Falls through.
92 case safe_browsing_util::DOWNLOADWHITELIST: // Falls through.
93 case safe_browsing_util::INCLUSIONWHITELIST: // Falls through.
94 case safe_browsing_util::EXTENSIONBLACKLIST: // Falls through.
95 case safe_browsing_util::SIDEEFFECTFREEWHITELIST: // Falls through.
96 case safe_browsing_util::IPBLACKLIST:
97 if (index)
98 *index = i;
99 return threat;
100 case safe_browsing_util::UNWANTEDURL:
101 // UNWANTEDURL is considered less severe than other threats, keep
102 // looking.
103 pending_threat = threat;
104 if (index)
105 *index = i;
106 break;
110 return pending_threat;
113 // Given a URL, compare all the possible host + path full hashes to the set of
114 // provided full hashes. Returns the list id of the severest matching result
115 // from |full_hashes|, or INVALID if none match.
116 safe_browsing_util::ListType GetUrlSeverestThreatListType(
117 const GURL& url,
118 const std::vector<SBFullHashResult>& full_hashes,
119 size_t* index) {
120 if (full_hashes.empty())
121 return safe_browsing_util::INVALID;
123 std::vector<std::string> patterns;
124 safe_browsing_util::GeneratePatternsToCheck(url, &patterns);
126 safe_browsing_util::ListType pending_threat = safe_browsing_util::INVALID;
127 for (size_t i = 0; i < patterns.size(); ++i) {
128 safe_browsing_util::ListType threat = GetHashSeverestThreatListType(
129 SBFullHashForString(patterns[i]), full_hashes, index);
130 switch (threat) {
131 case safe_browsing_util::INVALID:
132 // Ignore patterns with no matching threat.
133 break;
134 case safe_browsing_util::MALWARE: // Falls through.
135 case safe_browsing_util::PHISH: // Falls through.
136 case safe_browsing_util::BINURL: // Falls through.
137 case safe_browsing_util::CSDWHITELIST: // Falls through.
138 case safe_browsing_util::DOWNLOADWHITELIST: // Falls through.
139 case safe_browsing_util::INCLUSIONWHITELIST: // Falls through.
140 case safe_browsing_util::EXTENSIONBLACKLIST: // Falls through.
141 case safe_browsing_util::SIDEEFFECTFREEWHITELIST: // Falls through.
142 case safe_browsing_util::IPBLACKLIST:
143 return threat;
144 case safe_browsing_util::UNWANTEDURL:
145 // UNWANTEDURL is considered less severe than other threats, keep
146 // looking.
147 pending_threat = threat;
148 break;
151 return pending_threat;
154 SBThreatType GetThreatTypeFromListType(safe_browsing_util::ListType list_type) {
155 switch (list_type) {
156 case safe_browsing_util::PHISH:
157 return SB_THREAT_TYPE_URL_PHISHING;
158 case safe_browsing_util::MALWARE:
159 return SB_THREAT_TYPE_URL_MALWARE;
160 case safe_browsing_util::UNWANTEDURL:
161 return SB_THREAT_TYPE_URL_UNWANTED;
162 case safe_browsing_util::BINURL:
163 return SB_THREAT_TYPE_BINARY_MALWARE_URL;
164 case safe_browsing_util::EXTENSIONBLACKLIST:
165 return SB_THREAT_TYPE_EXTENSION;
166 default:
167 DVLOG(1) << "Unknown safe browsing list id " << list_type;
168 return SB_THREAT_TYPE_SAFE;
172 } // namespace
174 // static
175 SBThreatType SafeBrowsingDatabaseManager::GetHashSeverestThreatType(
176 const SBFullHash& hash,
177 const std::vector<SBFullHashResult>& full_hashes) {
178 return GetThreatTypeFromListType(
179 GetHashSeverestThreatListType(hash, full_hashes, NULL));
182 // static
183 SBThreatType SafeBrowsingDatabaseManager::GetUrlSeverestThreatType(
184 const GURL& url,
185 const std::vector<SBFullHashResult>& full_hashes,
186 size_t* index) {
187 return GetThreatTypeFromListType(
188 GetUrlSeverestThreatListType(url, full_hashes, index));
191 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
192 const std::vector<GURL>& urls,
193 const std::vector<SBFullHash>& full_hashes,
194 Client* client,
195 safe_browsing_util::ListType check_type,
196 const std::vector<SBThreatType>& expected_threats)
197 : urls(urls),
198 url_results(urls.size(), SB_THREAT_TYPE_SAFE),
199 url_metadata(urls.size()),
200 full_hashes(full_hashes),
201 full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE),
202 client(client),
203 need_get_hash(false),
204 check_type(check_type),
205 expected_threats(expected_threats) {
206 DCHECK_EQ(urls.empty(), !full_hashes.empty())
207 << "Exactly one of urls and full_hashes must be set";
210 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
212 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
213 const SafeBrowsingCheck& check) {
214 DCHECK_CURRENTLY_ON(BrowserThread::IO);
216 DCHECK_EQ(check.urls.size(), check.url_results.size());
217 DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size());
218 if (!check.urls.empty()) {
219 DCHECK(check.full_hashes.empty());
220 switch (check.check_type) {
221 case safe_browsing_util::MALWARE:
222 case safe_browsing_util::PHISH:
223 case safe_browsing_util::UNWANTEDURL:
224 DCHECK_EQ(1u, check.urls.size());
225 OnCheckBrowseUrlResult(
226 check.urls[0], check.url_results[0], check.url_metadata[0]);
227 break;
228 case safe_browsing_util::BINURL:
229 DCHECK_EQ(check.urls.size(), check.url_results.size());
230 OnCheckDownloadUrlResult(
231 check.urls,
232 *std::max_element(check.url_results.begin(),
233 check.url_results.end()));
234 break;
235 default:
236 NOTREACHED();
238 } else if (!check.full_hashes.empty()) {
239 switch (check.check_type) {
240 case safe_browsing_util::EXTENSIONBLACKLIST: {
241 std::set<std::string> unsafe_extension_ids;
242 for (size_t i = 0; i < check.full_hashes.size(); ++i) {
243 std::string extension_id =
244 safe_browsing_util::SBFullHashToString(check.full_hashes[i]);
245 if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION)
246 unsafe_extension_ids.insert(extension_id);
248 OnCheckExtensionsResult(unsafe_extension_ids);
249 break;
251 default:
252 NOTREACHED();
254 } else {
255 NOTREACHED();
259 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
260 const scoped_refptr<SafeBrowsingService>& service)
261 : sb_service_(service),
262 database_(NULL),
263 enabled_(false),
264 enable_download_protection_(false),
265 enable_csd_whitelist_(false),
266 enable_download_whitelist_(false),
267 enable_extension_blacklist_(false),
268 enable_side_effect_free_whitelist_(false),
269 enable_ip_blacklist_(false),
270 enable_unwanted_software_blacklist_(false),
271 update_in_progress_(false),
272 database_update_in_progress_(false),
273 closing_database_(false),
274 check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) {
275 DCHECK_CURRENTLY_ON(BrowserThread::UI);
276 DCHECK(sb_service_.get() != NULL);
278 // Android only supports a subset of FULL_SAFE_BROWSING.
279 // TODO(shess): This shouldn't be OS-driven <http://crbug.com/394379>
280 #if !defined(OS_ANDROID)
281 base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
282 enable_download_protection_ =
283 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
285 // We only download the csd-whitelist if client-side phishing detection is
286 // enabled.
287 enable_csd_whitelist_ =
288 !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection);
290 // TODO(noelutz): remove this boolean variable since it should always be true
291 // if SafeBrowsing is enabled. Unfortunately, we have no test data for this
292 // list right now. This means that we need to be able to disable this list
293 // for the SafeBrowsing test to pass.
294 enable_download_whitelist_ = enable_csd_whitelist_;
296 // TODO(kalman): there really shouldn't be a flag for this.
297 enable_extension_blacklist_ =
298 !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
300 enable_side_effect_free_whitelist_ =
301 prerender::IsSideEffectFreeWhitelistEnabled() &&
302 !cmdline->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist);
304 // The client-side IP blacklist feature is tightly integrated with client-side
305 // phishing protection for now.
306 enable_ip_blacklist_ = enable_csd_whitelist_;
308 // The UwS blacklist feature is controlled by a flag for M40.
309 enable_unwanted_software_blacklist_ =
310 safe_browsing_util::GetUnwantedTrialGroup() > safe_browsing_util::UWS_OFF;
312 enum SideEffectFreeWhitelistStatus {
313 SIDE_EFFECT_FREE_WHITELIST_ENABLED,
314 SIDE_EFFECT_FREE_WHITELIST_DISABLED,
315 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
318 SideEffectFreeWhitelistStatus side_effect_free_whitelist_status =
319 enable_side_effect_free_whitelist_ ? SIDE_EFFECT_FREE_WHITELIST_ENABLED :
320 SIDE_EFFECT_FREE_WHITELIST_DISABLED;
322 UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
323 side_effect_free_whitelist_status,
324 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX);
325 #endif
328 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
329 // The DCHECK is disabled due to crbug.com/438754.
330 // DCHECK_CURRENTLY_ON(BrowserThread::UI);
332 // We should have already been shut down. If we're still enabled, then the
333 // database isn't going to be closed properly, which could lead to corruption.
334 DCHECK(!enabled_);
337 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
338 return url.SchemeIs(url::kFtpScheme) ||
339 url.SchemeIs(url::kHttpScheme) ||
340 url.SchemeIs(url::kHttpsScheme);
343 bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
344 const std::vector<GURL>& url_chain,
345 Client* client) {
346 DCHECK_CURRENTLY_ON(BrowserThread::IO);
347 if (!enabled_ || !enable_download_protection_)
348 return true;
350 // We need to check the database for url prefix, and later may fetch the url
351 // from the safebrowsing backends. These need to be asynchronous.
352 SafeBrowsingCheck* check =
353 new SafeBrowsingCheck(url_chain,
354 std::vector<SBFullHash>(),
355 client,
356 safe_browsing_util::BINURL,
357 std::vector<SBThreatType>(1,
358 SB_THREAT_TYPE_BINARY_MALWARE_URL));
359 StartSafeBrowsingCheck(
360 check,
361 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this,
362 check));
363 return false;
366 bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
367 const std::set<std::string>& extension_ids,
368 Client* client) {
369 DCHECK_CURRENTLY_ON(BrowserThread::IO);
371 if (!enabled_ || !enable_extension_blacklist_)
372 return true;
374 std::vector<SBFullHash> extension_id_hashes;
375 std::transform(extension_ids.begin(), extension_ids.end(),
376 std::back_inserter(extension_id_hashes),
377 safe_browsing_util::StringToSBFullHash);
379 SafeBrowsingCheck* check = new SafeBrowsingCheck(
380 std::vector<GURL>(),
381 extension_id_hashes,
382 client,
383 safe_browsing_util::EXTENSIONBLACKLIST,
384 std::vector<SBThreatType>(1, SB_THREAT_TYPE_EXTENSION));
386 StartSafeBrowsingCheck(
387 check,
388 base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread,
389 this,
390 check));
391 return false;
394 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
395 const GURL& url) {
396 if (!enabled_)
397 return false;
399 if (!CanCheckUrl(url))
400 return false;
402 return database_->ContainsSideEffectFreeWhitelistUrl(url);
405 bool SafeBrowsingDatabaseManager::MatchMalwareIP(
406 const std::string& ip_address) {
407 DCHECK_CURRENTLY_ON(BrowserThread::IO);
408 if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) {
409 return false; // Fail open.
411 return database_->ContainsMalwareIP(ip_address);
414 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
415 DCHECK_CURRENTLY_ON(BrowserThread::IO);
416 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
417 // There is something funky going on here -- for example, perhaps the user
418 // has not restarted since enabling metrics reporting, so we haven't
419 // enabled the csd whitelist yet. Just to be safe we return true in this
420 // case.
421 return true;
423 return database_->ContainsCsdWhitelistedUrl(url);
426 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
427 DCHECK_CURRENTLY_ON(BrowserThread::IO);
428 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
429 return true;
431 return database_->ContainsDownloadWhitelistedUrl(url);
434 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
435 const std::string& str) {
436 DCHECK_CURRENTLY_ON(BrowserThread::IO);
437 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
438 return true;
440 return database_->ContainsDownloadWhitelistedString(str);
443 bool SafeBrowsingDatabaseManager::MatchInclusionWhitelistUrl(const GURL& url) {
444 DCHECK_CURRENTLY_ON(BrowserThread::IO);
445 if (!enabled_ || !MakeDatabaseAvailable())
446 return true;
447 return database_->ContainsInclusionWhitelistedUrl(url);
450 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
451 DCHECK_CURRENTLY_ON(BrowserThread::IO);
452 if (!enabled_ || !MakeDatabaseAvailable()) {
453 return true;
455 return database_->IsMalwareIPMatchKillSwitchOn();
458 bool SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
459 DCHECK_CURRENTLY_ON(BrowserThread::IO);
460 if (!enabled_ || !MakeDatabaseAvailable()) {
461 return true;
463 return database_->IsCsdWhitelistKillSwitchOn();
466 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
467 Client* client) {
468 DCHECK_CURRENTLY_ON(BrowserThread::IO);
469 if (!enabled_)
470 return true;
472 if (!CanCheckUrl(url))
473 return true;
475 std::vector<SBThreatType> expected_threats;
476 expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE);
477 expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING);
478 expected_threats.push_back(SB_THREAT_TYPE_URL_UNWANTED);
480 const base::TimeTicks start = base::TimeTicks::Now();
481 if (!MakeDatabaseAvailable()) {
482 QueuedCheck queued_check(safe_browsing_util::MALWARE, // or PHISH
483 client,
484 url,
485 expected_threats,
486 start);
487 queued_checks_.push_back(queued_check);
488 return false;
491 // Cache hits should, in general, be the same for both (ignoring potential
492 // cache evictions in the second call for entries that were just about to be
493 // evicted in the first call).
494 // TODO(gab): Refactor SafeBrowsingDatabase to avoid depending on this here.
495 std::vector<SBFullHashResult> cache_hits;
497 std::vector<SBPrefix> browse_prefix_hits;
498 bool browse_prefix_match = database_->ContainsBrowseUrl(
499 url, &browse_prefix_hits, &cache_hits);
501 std::vector<SBPrefix> unwanted_prefix_hits;
502 std::vector<SBFullHashResult> unused_cache_hits;
503 bool unwanted_prefix_match = database_->ContainsUnwantedSoftwareUrl(
504 url, &unwanted_prefix_hits, &unused_cache_hits);
506 // Merge the two pre-sorted prefix hits lists.
507 // TODO(gab): Refactor SafeBrowsingDatabase for it to return this merged list
508 // by default rather than building it here.
509 std::vector<SBPrefix> prefix_hits(browse_prefix_hits.size() +
510 unwanted_prefix_hits.size());
511 std::merge(browse_prefix_hits.begin(),
512 browse_prefix_hits.end(),
513 unwanted_prefix_hits.begin(),
514 unwanted_prefix_hits.end(),
515 prefix_hits.begin());
516 prefix_hits.erase(std::unique(prefix_hits.begin(), prefix_hits.end()),
517 prefix_hits.end());
519 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
521 if (!browse_prefix_match && !unwanted_prefix_match)
522 return true; // URL is okay.
524 // Needs to be asynchronous, since we could be in the constructor of a
525 // ResourceDispatcherHost event handler which can't pause there.
526 // This check will ping the Safe Browsing servers and get all lists which it
527 // matches. These lists will then be filtered against the |expected_threats|
528 // and the result callback for MALWARE (which is the same as for PHISH and
529 // UNWANTEDURL) will eventually be invoked with the final decision.
530 SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url),
531 std::vector<SBFullHash>(),
532 client,
533 safe_browsing_util::MALWARE,
534 expected_threats);
535 check->need_get_hash = cache_hits.empty();
536 check->prefix_hits.swap(prefix_hits);
537 check->cache_hits.swap(cache_hits);
538 checks_.insert(check);
540 BrowserThread::PostTask(
541 BrowserThread::IO, FROM_HERE,
542 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
544 return false;
547 void SafeBrowsingDatabaseManager::CancelCheck(Client* client) {
548 DCHECK_CURRENTLY_ON(BrowserThread::IO);
549 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
550 // We can't delete matching checks here because the db thread has a copy of
551 // the pointer. Instead, we simply NULL out the client, and when the db
552 // thread calls us back, we'll clean up the check.
553 if ((*i)->client == client)
554 (*i)->client = NULL;
557 // Scan the queued clients store. Clients may be here if they requested a URL
558 // check before the database has finished loading.
559 for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
560 it != queued_checks_.end(); ) {
561 // In this case it's safe to delete matches entirely since nothing has a
562 // pointer to them.
563 if (it->client == client)
564 it = queued_checks_.erase(it);
565 else
566 ++it;
570 void SafeBrowsingDatabaseManager::HandleGetHashResults(
571 SafeBrowsingCheck* check,
572 const std::vector<SBFullHashResult>& full_hashes,
573 const base::TimeDelta& cache_lifetime) {
574 DCHECK_CURRENTLY_ON(BrowserThread::IO);
576 if (!enabled_)
577 return;
579 // If the service has been shut down, |check| should have been deleted.
580 DCHECK(checks_.find(check) != checks_.end());
582 // |start| is set before calling |GetFullHash()|, which should be
583 // the only path which gets to here.
584 DCHECK(!check->start.is_null());
585 UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
586 base::TimeTicks::Now() - check->start);
588 std::vector<SBPrefix> prefixes = check->prefix_hits;
589 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here.
591 // Cache the GetHash results.
592 if (cache_lifetime != base::TimeDelta() && MakeDatabaseAvailable())
593 database_->CacheHashResults(prefixes, full_hashes, cache_lifetime);
596 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) {
597 DCHECK_CURRENTLY_ON(BrowserThread::IO);
598 DCHECK(enabled_);
599 DCHECK(!callback.is_null());
600 safe_browsing_task_runner_->PostTask(
601 FROM_HERE,
602 base::Bind(&SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this,
603 callback));
606 void SafeBrowsingDatabaseManager::AddChunks(
607 const std::string& list,
608 scoped_ptr<ScopedVector<SBChunkData> > chunks,
609 AddChunksCallback callback) {
610 DCHECK_CURRENTLY_ON(BrowserThread::IO);
611 DCHECK(enabled_);
612 DCHECK(!callback.is_null());
613 safe_browsing_task_runner_->PostTask(
614 FROM_HERE, base::Bind(&SafeBrowsingDatabaseManager::AddDatabaseChunks,
615 this, list, base::Passed(&chunks), callback));
618 void SafeBrowsingDatabaseManager::DeleteChunks(
619 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) {
620 DCHECK_CURRENTLY_ON(BrowserThread::IO);
621 DCHECK(enabled_);
622 safe_browsing_task_runner_->PostTask(
623 FROM_HERE, base::Bind(&SafeBrowsingDatabaseManager::DeleteDatabaseChunks,
624 this, base::Passed(&chunk_deletes)));
627 void SafeBrowsingDatabaseManager::UpdateStarted() {
628 DCHECK_CURRENTLY_ON(BrowserThread::IO);
629 DCHECK(enabled_);
630 DCHECK(!update_in_progress_);
631 update_in_progress_ = true;
634 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) {
635 DCHECK_CURRENTLY_ON(BrowserThread::IO);
636 DCHECK(enabled_);
637 if (update_in_progress_) {
638 update_in_progress_ = false;
639 safe_browsing_task_runner_->PostTask(
640 FROM_HERE,
641 base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished, this,
642 update_succeeded));
646 void SafeBrowsingDatabaseManager::ResetDatabase() {
647 DCHECK_CURRENTLY_ON(BrowserThread::IO);
648 DCHECK(enabled_);
649 safe_browsing_task_runner_->PostTask(
650 FROM_HERE,
651 base::Bind(&SafeBrowsingDatabaseManager::OnResetDatabase, this));
654 void SafeBrowsingDatabaseManager::StartOnIOThread() {
655 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed.
656 tracked_objects::ScopedTracker tracking_profile1(
657 FROM_HERE_WITH_EXPLICIT_FUNCTION(
658 "455469 SafeBrowsingDatabaseManager::StartOnIOThread1"));
659 DCHECK_CURRENTLY_ON(BrowserThread::IO);
660 if (enabled_)
661 return;
663 DCHECK(!safe_browsing_task_runner_);
664 // Use the blocking pool instead of a dedicated thread for safe browsing work,
665 // if specified by an experiment.
666 const bool use_blocking_pool =
667 variations::GetVariationParamValue("LightSpeed", "SBThreadingMode") ==
668 "BlockingPool";
669 if (use_blocking_pool) {
670 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is
671 // fixed.
672 tracked_objects::ScopedTracker tracking_profile2(
673 FROM_HERE_WITH_EXPLICIT_FUNCTION(
674 "455469 SafeBrowsingDatabaseManager::StartOnIOThread2"));
675 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
676 safe_browsing_task_runner_ =
677 pool->GetSequencedTaskRunnerWithShutdownBehavior(
678 pool->GetSequenceToken(),
679 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
680 } else {
681 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is
682 // fixed.
683 tracked_objects::ScopedTracker tracking_profile3(
684 FROM_HERE_WITH_EXPLICIT_FUNCTION(
685 "455469 SafeBrowsingDatabaseManager::StartOnIOThread3"));
686 DCHECK(!safe_browsing_thread_.get());
688 safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
689 if (!safe_browsing_thread_->Start())
690 return;
691 safe_browsing_task_runner_ = safe_browsing_thread_->task_runner();
694 enabled_ = true;
696 MakeDatabaseAvailable();
699 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
700 DCHECK_CURRENTLY_ON(BrowserThread::IO);
702 DoStopOnIOThread();
703 if (shutdown) {
704 sb_service_ = NULL;
708 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
709 bool update_succeeded) {
710 DCHECK_CURRENTLY_ON(BrowserThread::UI);
711 content::NotificationService::current()->Notify(
712 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
713 content::Source<SafeBrowsingDatabaseManager>(this),
714 content::Details<bool>(&update_succeeded));
717 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
718 const safe_browsing_util::ListType check_type,
719 Client* client,
720 const GURL& url,
721 const std::vector<SBThreatType>& expected_threats,
722 const base::TimeTicks& start)
723 : check_type(check_type),
724 client(client),
725 url(url),
726 expected_threats(expected_threats),
727 start(start) {
730 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
733 void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
734 DCHECK_CURRENTLY_ON(BrowserThread::IO);
736 if (!enabled_)
737 return;
739 enabled_ = false;
741 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
742 while (!queued_checks_.empty()) {
743 QueuedCheck queued = queued_checks_.front();
744 if (queued.client) {
745 SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url),
746 std::vector<SBFullHash>(),
747 queued.client,
748 queued.check_type,
749 queued.expected_threats);
750 queued.client->OnSafeBrowsingResult(sb_check);
752 queued_checks_.pop_front();
755 // Close the database. Cases to avoid:
756 // * If |closing_database_| is true, continuing will queue up a second
757 // request, |closing_database_| will be reset after handling the first
758 // request, and if any functions on the db thread recreate the database, we
759 // could start using it on the IO thread and then have the second request
760 // handler delete it out from under us.
761 // * If |database_| is NULL, then either no creation request is in flight, in
762 // which case we don't need to do anything, or one is in flight, in which
763 // case the database will be recreated before our deletion request is
764 // handled, and could be used on the IO thread in that time period, leading
765 // to the same problem as above.
766 // Checking DatabaseAvailable() avoids both of these.
767 if (DatabaseAvailable()) {
768 closing_database_ = true;
769 safe_browsing_task_runner_->PostTask(
770 FROM_HERE,
771 base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this));
774 // Flush the database thread. Any in-progress database check results will be
775 // ignored and cleaned up below.
777 // Note that to avoid leaking the database, we rely on the fact that no new
778 // tasks will be added to the db thread between the call above and this one.
779 // See comments on the declaration of |safe_browsing_thread_|.
780 if (safe_browsing_thread_) {
781 // A ScopedAllowIO object is required to join the thread when calling Stop.
782 // See http://crbug.com/72696. Note that we call Stop() first to clear out
783 // any remaining tasks before clearing safe_browsing_thread_.
784 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
785 safe_browsing_thread_->Stop();
786 safe_browsing_thread_.reset();
788 safe_browsing_task_runner_ = nullptr;
790 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
791 // We have to do this after the db thread returns because methods on it can
792 // have copies of these pointers, so deleting them might lead to accessing
793 // garbage.
794 for (CurrentChecks::iterator it = checks_.begin();
795 it != checks_.end(); ++it) {
796 SafeBrowsingCheck* check = *it;
797 if (check->client)
798 check->client->OnSafeBrowsingResult(*check);
800 STLDeleteElements(&checks_);
802 gethash_requests_.clear();
805 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
806 base::AutoLock lock(database_lock_);
807 return !closing_database_ && (database_ != NULL);
810 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
811 DCHECK_CURRENTLY_ON(BrowserThread::IO);
812 DCHECK(enabled_);
813 if (DatabaseAvailable())
814 return true;
815 safe_browsing_task_runner_->PostTask(
816 FROM_HERE,
817 base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase),
818 this));
819 return false;
822 SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
823 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
825 if (database_)
826 return database_;
827 startup_metric_utils::ScopedSlowStartupUMA
828 scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
829 const base::TimeTicks before = base::TimeTicks::Now();
831 SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create(
832 safe_browsing_task_runner_, enable_download_protection_,
833 enable_csd_whitelist_, enable_download_whitelist_,
834 enable_extension_blacklist_, enable_side_effect_free_whitelist_,
835 enable_ip_blacklist_, enable_unwanted_software_blacklist_);
837 database->Init(SafeBrowsingService::GetBaseFilename());
839 // Acquiring the lock here guarantees correct ordering between the writes to
840 // the new database object above, and the setting of |database_| below.
841 base::AutoLock lock(database_lock_);
842 database_ = database;
845 BrowserThread::PostTask(
846 BrowserThread::IO, FROM_HERE,
847 base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this));
849 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
850 return database_;
853 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) {
854 DCHECK_CURRENTLY_ON(BrowserThread::IO);
856 if (!enabled_)
857 return;
859 // If the service has been shut down, |check| should have been deleted.
860 DCHECK(checks_.find(check) != checks_.end());
862 if (check->client && check->need_get_hash) {
863 // We have a partial match so we need to query Google for the full hash.
864 // Clean up will happen in HandleGetHashResults.
866 // See if we have a GetHash request already in progress for this particular
867 // prefix. If so, we just append ourselves to the list of interested parties
868 // when the results arrive. We only do this for checks involving one prefix,
869 // since that is the common case (multiple prefixes will issue the request
870 // as normal).
871 if (check->prefix_hits.size() == 1) {
872 SBPrefix prefix = check->prefix_hits[0];
873 GetHashRequests::iterator it = gethash_requests_.find(prefix);
874 if (it != gethash_requests_.end()) {
875 // There's already a request in progress.
876 it->second.push_back(check);
877 return;
880 // No request in progress, so we're the first for this prefix.
881 GetHashRequestors requestors;
882 requestors.push_back(check);
883 gethash_requests_[prefix] = requestors;
886 // Reset the start time so that we can measure the network time without the
887 // database time.
888 check->start = base::TimeTicks::Now();
889 // Note: If |this| is deleted or stopped, the protocol_manager will
890 // be destroyed as well - hence it's OK to do unretained in this case.
891 bool is_download = check->check_type == safe_browsing_util::BINURL;
892 sb_service_->protocol_manager()->GetFullHash(
893 check->prefix_hits,
894 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults,
895 base::Unretained(this),
896 check),
897 is_download);
898 } else {
899 // We may have cached results for previous GetHash queries. Since
900 // this data comes from cache, don't histogram hits.
901 HandleOneCheck(check, check->cache_hits);
905 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
906 GetChunksCallback callback) {
907 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
909 bool database_error = true;
910 std::vector<SBListChunkRanges> lists;
911 DCHECK(!database_update_in_progress_);
912 database_update_in_progress_ = true;
913 GetDatabase(); // This guarantees that |database_| is non-NULL.
914 if (database_->UpdateStarted(&lists)) {
915 database_error = false;
916 } else {
917 database_->UpdateFinished(false);
920 BrowserThread::PostTask(
921 BrowserThread::IO, FROM_HERE,
922 base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase,
923 this, lists, database_error, callback));
926 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
927 const std::vector<SBListChunkRanges>& lists, bool database_error,
928 GetChunksCallback callback) {
929 DCHECK_CURRENTLY_ON(BrowserThread::IO);
930 if (enabled_)
931 callback.Run(lists, database_error);
934 void SafeBrowsingDatabaseManager::OnAddChunksComplete(
935 AddChunksCallback callback) {
936 DCHECK_CURRENTLY_ON(BrowserThread::IO);
937 if (enabled_)
938 callback.Run();
941 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
942 DCHECK_CURRENTLY_ON(BrowserThread::IO);
943 if (!enabled_)
944 return;
946 LOCAL_HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
947 if (queued_checks_.empty())
948 return;
950 // If the database isn't already available, calling CheckUrl() in the loop
951 // below will add the check back to the queue, and we'll infinite-loop.
952 DCHECK(DatabaseAvailable());
953 while (!queued_checks_.empty()) {
954 QueuedCheck check = queued_checks_.front();
955 DCHECK(!check.start.is_null());
956 LOCAL_HISTOGRAM_TIMES("SB.QueueDelay",
957 base::TimeTicks::Now() - check.start);
958 // If CheckUrl() determines the URL is safe immediately, it doesn't call the
959 // client's handler function (because normally it's being directly called by
960 // the client). Since we're not the client, we have to convey this result.
961 if (check.client && CheckBrowseUrl(check.url, check.client)) {
962 SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url),
963 std::vector<SBFullHash>(),
964 check.client,
965 check.check_type,
966 check.expected_threats);
967 check.client->OnSafeBrowsingResult(sb_check);
969 queued_checks_.pop_front();
973 void SafeBrowsingDatabaseManager::AddDatabaseChunks(
974 const std::string& list_name,
975 scoped_ptr<ScopedVector<SBChunkData> > chunks,
976 AddChunksCallback callback) {
977 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
978 if (chunks)
979 GetDatabase()->InsertChunks(list_name, chunks->get());
980 BrowserThread::PostTask(
981 BrowserThread::IO, FROM_HERE,
982 base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this,
983 callback));
986 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
987 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) {
988 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
989 if (chunk_deletes)
990 GetDatabase()->DeleteChunks(*chunk_deletes);
993 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
994 bool update_succeeded) {
995 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
996 GetDatabase()->UpdateFinished(update_succeeded);
997 DCHECK(database_update_in_progress_);
998 database_update_in_progress_ = false;
999 BrowserThread::PostTask(
1000 BrowserThread::UI, FROM_HERE,
1001 base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished,
1002 this, update_succeeded));
1005 void SafeBrowsingDatabaseManager::OnCloseDatabase() {
1006 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1007 DCHECK(closing_database_);
1009 // Because |closing_database_| is true, nothing on the IO thread will be
1010 // accessing the database, so it's safe to delete and then NULL the pointer.
1011 delete database_;
1012 database_ = NULL;
1014 // Acquiring the lock here guarantees correct ordering between the resetting
1015 // of |database_| above and of |closing_database_| below, which ensures there
1016 // won't be a window during which the IO thread falsely believes the database
1017 // is available.
1018 base::AutoLock lock(database_lock_);
1019 closing_database_ = false;
1022 void SafeBrowsingDatabaseManager::OnResetDatabase() {
1023 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1025 GetDatabase()->ResetDatabase();
1028 void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
1029 SafeBrowsingCheck* check,
1030 const std::vector<SBFullHashResult>& full_hashes) {
1031 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1032 safe_browsing_util::ListType check_type = check->check_type;
1033 SBPrefix prefix = check->prefix_hits[0];
1034 GetHashRequests::iterator it = gethash_requests_.find(prefix);
1035 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
1036 const bool hit = HandleOneCheck(check, full_hashes);
1037 RecordGetHashCheckStatus(hit, check_type, full_hashes);
1038 return;
1041 // Call back all interested parties, noting if any has a hit.
1042 GetHashRequestors& requestors = it->second;
1043 bool hit = false;
1044 for (GetHashRequestors::iterator r = requestors.begin();
1045 r != requestors.end(); ++r) {
1046 if (HandleOneCheck(*r, full_hashes))
1047 hit = true;
1049 RecordGetHashCheckStatus(hit, check_type, full_hashes);
1051 gethash_requests_.erase(it);
1054 bool SafeBrowsingDatabaseManager::HandleOneCheck(
1055 SafeBrowsingCheck* check,
1056 const std::vector<SBFullHashResult>& full_hashes) {
1057 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1058 DCHECK(check);
1060 bool is_threat = false;
1062 // TODO(shess): GetHashSeverestThreadListType() contains a loop,
1063 // GetUrlSeverestThreatListType() a loop around that loop. Having another
1064 // loop out here concerns me. It is likely that SAFE is an expected outcome,
1065 // which means all of those loops run to completion. Refactoring this to
1066 // generate a set of sorted items to compare in sequence would probably
1067 // improve things.
1069 // Additionally, the set of patterns generated from the urls is very similar
1070 // to the patterns generated in ContainsBrowseUrl() and other database checks,
1071 // which are called from this code. Refactoring that across the checks could
1072 // interact well with batching the checks here.
1074 // TODO(gab): Fix the fact that Get(Url|Hash)SeverestThreatType() may return a
1075 // threat for which IsExpectedThreat() returns false even if |full_hashes|
1076 // actually contains an expected threat.
1078 for (size_t i = 0; i < check->urls.size(); ++i) {
1079 size_t threat_index;
1080 SBThreatType threat =
1081 GetUrlSeverestThreatType(check->urls[i], full_hashes, &threat_index);
1082 if (threat != SB_THREAT_TYPE_SAFE &&
1083 IsExpectedThreat(threat, check->expected_threats)) {
1084 check->url_results[i] = threat;
1085 check->url_metadata[i] = full_hashes[threat_index].metadata;
1086 is_threat = true;
1090 for (size_t i = 0; i < check->full_hashes.size(); ++i) {
1091 SBThreatType threat =
1092 GetHashSeverestThreatType(check->full_hashes[i], full_hashes);
1093 if (threat != SB_THREAT_TYPE_SAFE &&
1094 IsExpectedThreat(threat, check->expected_threats)) {
1095 check->full_hash_results[i] = threat;
1096 is_threat = true;
1100 SafeBrowsingCheckDone(check);
1101 return is_threat;
1104 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
1105 SafeBrowsingCheck* check) {
1106 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1107 DCHECK(enable_download_protection_);
1109 std::vector<SBPrefix> prefix_hits;
1111 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
1112 // Good, we don't have hash for this url prefix.
1113 BrowserThread::PostTask(
1114 BrowserThread::IO, FROM_HERE,
1115 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this,
1116 check));
1117 return;
1120 check->need_get_hash = true;
1121 check->prefix_hits.clear();
1122 check->prefix_hits = prefix_hits;
1123 BrowserThread::PostTask(
1124 BrowserThread::IO, FROM_HERE,
1125 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
1128 void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
1129 SafeBrowsingCheck* check) {
1130 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1132 std::vector<SBPrefix> prefixes;
1133 for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin();
1134 it != check->full_hashes.end(); ++it) {
1135 prefixes.push_back((*it).prefix);
1137 database_->ContainsExtensionPrefixes(prefixes, &check->prefix_hits);
1139 if (check->prefix_hits.empty()) {
1140 // No matches for any extensions.
1141 BrowserThread::PostTask(
1142 BrowserThread::IO,
1143 FROM_HERE,
1144 base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone, this,
1145 check));
1146 } else {
1147 // Some prefixes matched, we need to ask Google whether they're legit.
1148 check->need_get_hash = true;
1149 BrowserThread::PostTask(
1150 BrowserThread::IO,
1151 FROM_HERE,
1152 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
1156 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
1157 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1158 DCHECK(check);
1160 if (!enabled_)
1161 return;
1163 DCHECK(checks_.find(check) != checks_.end());
1164 if (check->client) {
1165 check->client->OnSafeBrowsingResult(*check);
1166 check->client = NULL;
1170 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone(
1171 SafeBrowsingCheck* check) {
1172 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1173 DCHECK(enable_download_protection_);
1174 SafeBrowsingCheckDone(check);
1177 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
1178 SafeBrowsingCheck* check) {
1179 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1180 DCHECK(check);
1182 if (!enabled_)
1183 return;
1185 DVLOG(1) << "SafeBrowsingCheckDone";
1186 DCHECK(checks_.find(check) != checks_.end());
1187 if (check->client)
1188 check->client->OnSafeBrowsingResult(*check);
1189 checks_.erase(check);
1190 delete check;
1193 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
1194 SafeBrowsingCheck* check,
1195 const base::Closure& task) {
1196 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1197 check->timeout_factory_.reset(
1198 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this));
1199 checks_.insert(check);
1201 safe_browsing_task_runner_->PostTask(FROM_HERE, task);
1203 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
1204 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback,
1205 check->timeout_factory_->GetWeakPtr(), check),
1206 check_timeout_);