Fire an error if a pref used in the UI is missing once all prefs are fetched.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / database_manager.cc
blob13c6dd6b1f654f22236365bf6691c0d3977be29e
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 std::vector<SBPrefix> prefixes;
360 SafeBrowsingDatabase::GetDownloadUrlPrefixes(url_chain, &prefixes);
361 StartSafeBrowsingCheck(
362 check,
363 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this,
364 prefixes));
365 return false;
368 bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
369 const std::set<std::string>& extension_ids,
370 Client* client) {
371 DCHECK_CURRENTLY_ON(BrowserThread::IO);
373 if (!enabled_ || !enable_extension_blacklist_)
374 return true;
376 std::vector<SBFullHash> extension_id_hashes;
377 std::transform(extension_ids.begin(), extension_ids.end(),
378 std::back_inserter(extension_id_hashes),
379 safe_browsing_util::StringToSBFullHash);
380 std::vector<SBPrefix> prefixes;
381 for (const SBFullHash& hash : extension_id_hashes)
382 prefixes.push_back(hash.prefix);
384 SafeBrowsingCheck* check = new SafeBrowsingCheck(
385 std::vector<GURL>(),
386 extension_id_hashes,
387 client,
388 safe_browsing_util::EXTENSIONBLACKLIST,
389 std::vector<SBThreatType>(1, SB_THREAT_TYPE_EXTENSION));
390 StartSafeBrowsingCheck(
391 check,
392 base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread,
393 this, prefixes));
394 return false;
397 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
398 const GURL& url) {
399 if (!enabled_)
400 return false;
402 if (!CanCheckUrl(url))
403 return false;
405 return database_->ContainsSideEffectFreeWhitelistUrl(url);
408 bool SafeBrowsingDatabaseManager::MatchMalwareIP(
409 const std::string& ip_address) {
410 DCHECK_CURRENTLY_ON(BrowserThread::IO);
411 if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) {
412 return false; // Fail open.
414 return database_->ContainsMalwareIP(ip_address);
417 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
418 DCHECK_CURRENTLY_ON(BrowserThread::IO);
419 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
420 // There is something funky going on here -- for example, perhaps the user
421 // has not restarted since enabling metrics reporting, so we haven't
422 // enabled the csd whitelist yet. Just to be safe we return true in this
423 // case.
424 return true;
426 return database_->ContainsCsdWhitelistedUrl(url);
429 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
430 DCHECK_CURRENTLY_ON(BrowserThread::IO);
431 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
432 return true;
434 return database_->ContainsDownloadWhitelistedUrl(url);
437 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
438 const std::string& str) {
439 DCHECK_CURRENTLY_ON(BrowserThread::IO);
440 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
441 return true;
443 return database_->ContainsDownloadWhitelistedString(str);
446 bool SafeBrowsingDatabaseManager::MatchInclusionWhitelistUrl(const GURL& url) {
447 DCHECK_CURRENTLY_ON(BrowserThread::IO);
448 if (!enabled_ || !MakeDatabaseAvailable())
449 return true;
450 return database_->ContainsInclusionWhitelistedUrl(url);
453 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
454 DCHECK_CURRENTLY_ON(BrowserThread::IO);
455 if (!enabled_ || !MakeDatabaseAvailable()) {
456 return true;
458 return database_->IsMalwareIPMatchKillSwitchOn();
461 bool SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
462 DCHECK_CURRENTLY_ON(BrowserThread::IO);
463 if (!enabled_ || !MakeDatabaseAvailable()) {
464 return true;
466 return database_->IsCsdWhitelistKillSwitchOn();
469 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
470 Client* client) {
471 DCHECK_CURRENTLY_ON(BrowserThread::IO);
472 if (!enabled_)
473 return true;
475 if (!CanCheckUrl(url))
476 return true;
478 std::vector<SBThreatType> expected_threats;
479 expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE);
480 expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING);
481 expected_threats.push_back(SB_THREAT_TYPE_URL_UNWANTED);
483 const base::TimeTicks start = base::TimeTicks::Now();
484 if (!MakeDatabaseAvailable()) {
485 QueuedCheck queued_check(safe_browsing_util::MALWARE, // or PHISH
486 client,
487 url,
488 expected_threats,
489 start);
490 queued_checks_.push_back(queued_check);
491 return false;
494 // Cache hits should, in general, be the same for both (ignoring potential
495 // cache evictions in the second call for entries that were just about to be
496 // evicted in the first call).
497 // TODO(gab): Refactor SafeBrowsingDatabase to avoid depending on this here.
498 std::vector<SBFullHashResult> cache_hits;
500 std::vector<SBPrefix> browse_prefix_hits;
501 bool browse_prefix_match = database_->ContainsBrowseUrl(
502 url, &browse_prefix_hits, &cache_hits);
504 std::vector<SBPrefix> unwanted_prefix_hits;
505 std::vector<SBFullHashResult> unused_cache_hits;
506 bool unwanted_prefix_match = database_->ContainsUnwantedSoftwareUrl(
507 url, &unwanted_prefix_hits, &unused_cache_hits);
509 // Merge the two pre-sorted prefix hits lists.
510 // TODO(gab): Refactor SafeBrowsingDatabase for it to return this merged list
511 // by default rather than building it here.
512 std::vector<SBPrefix> prefix_hits(browse_prefix_hits.size() +
513 unwanted_prefix_hits.size());
514 std::merge(browse_prefix_hits.begin(),
515 browse_prefix_hits.end(),
516 unwanted_prefix_hits.begin(),
517 unwanted_prefix_hits.end(),
518 prefix_hits.begin());
519 prefix_hits.erase(std::unique(prefix_hits.begin(), prefix_hits.end()),
520 prefix_hits.end());
522 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
524 if (!browse_prefix_match && !unwanted_prefix_match)
525 return true; // URL is okay.
527 // Needs to be asynchronous, since we could be in the constructor of a
528 // ResourceDispatcherHost event handler which can't pause there.
529 // This check will ping the Safe Browsing servers and get all lists which it
530 // matches. These lists will then be filtered against the |expected_threats|
531 // and the result callback for MALWARE (which is the same as for PHISH and
532 // UNWANTEDURL) will eventually be invoked with the final decision.
533 SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url),
534 std::vector<SBFullHash>(),
535 client,
536 safe_browsing_util::MALWARE,
537 expected_threats);
538 check->need_get_hash = cache_hits.empty();
539 check->prefix_hits.swap(prefix_hits);
540 check->cache_hits.swap(cache_hits);
541 checks_.insert(check);
543 BrowserThread::PostTask(
544 BrowserThread::IO, FROM_HERE,
545 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
547 return false;
550 void SafeBrowsingDatabaseManager::CancelCheck(Client* client) {
551 DCHECK_CURRENTLY_ON(BrowserThread::IO);
552 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
553 // We can't delete matching checks here because the db thread has a copy of
554 // the pointer. Instead, we simply NULL out the client, and when the db
555 // thread calls us back, we'll clean up the check.
556 if ((*i)->client == client)
557 (*i)->client = NULL;
560 // Scan the queued clients store. Clients may be here if they requested a URL
561 // check before the database has finished loading.
562 for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
563 it != queued_checks_.end(); ) {
564 // In this case it's safe to delete matches entirely since nothing has a
565 // pointer to them.
566 if (it->client == client)
567 it = queued_checks_.erase(it);
568 else
569 ++it;
573 void SafeBrowsingDatabaseManager::HandleGetHashResults(
574 SafeBrowsingCheck* check,
575 const std::vector<SBFullHashResult>& full_hashes,
576 const base::TimeDelta& cache_lifetime) {
577 DCHECK_CURRENTLY_ON(BrowserThread::IO);
579 if (!enabled_)
580 return;
582 // If the service has been shut down, |check| should have been deleted.
583 DCHECK(checks_.find(check) != checks_.end());
585 // |start| is set before calling |GetFullHash()|, which should be
586 // the only path which gets to here.
587 DCHECK(!check->start.is_null());
588 UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
589 base::TimeTicks::Now() - check->start);
591 std::vector<SBPrefix> prefixes = check->prefix_hits;
592 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here.
594 // Cache the GetHash results.
595 if (cache_lifetime != base::TimeDelta() && MakeDatabaseAvailable())
596 database_->CacheHashResults(prefixes, full_hashes, cache_lifetime);
599 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) {
600 DCHECK_CURRENTLY_ON(BrowserThread::IO);
601 DCHECK(enabled_);
602 DCHECK(!callback.is_null());
603 safe_browsing_task_runner_->PostTask(
604 FROM_HERE,
605 base::Bind(&SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this,
606 callback));
609 void SafeBrowsingDatabaseManager::AddChunks(
610 const std::string& list,
611 scoped_ptr<ScopedVector<SBChunkData> > chunks,
612 AddChunksCallback callback) {
613 DCHECK_CURRENTLY_ON(BrowserThread::IO);
614 DCHECK(enabled_);
615 DCHECK(!callback.is_null());
616 safe_browsing_task_runner_->PostTask(
617 FROM_HERE, base::Bind(&SafeBrowsingDatabaseManager::AddDatabaseChunks,
618 this, list, base::Passed(&chunks), callback));
621 void SafeBrowsingDatabaseManager::DeleteChunks(
622 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) {
623 DCHECK_CURRENTLY_ON(BrowserThread::IO);
624 DCHECK(enabled_);
625 safe_browsing_task_runner_->PostTask(
626 FROM_HERE, base::Bind(&SafeBrowsingDatabaseManager::DeleteDatabaseChunks,
627 this, base::Passed(&chunk_deletes)));
630 void SafeBrowsingDatabaseManager::UpdateStarted() {
631 DCHECK_CURRENTLY_ON(BrowserThread::IO);
632 DCHECK(enabled_);
633 DCHECK(!update_in_progress_);
634 update_in_progress_ = true;
637 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) {
638 DCHECK_CURRENTLY_ON(BrowserThread::IO);
639 DCHECK(enabled_);
640 if (update_in_progress_) {
641 update_in_progress_ = false;
642 safe_browsing_task_runner_->PostTask(
643 FROM_HERE,
644 base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished, this,
645 update_succeeded));
649 void SafeBrowsingDatabaseManager::ResetDatabase() {
650 DCHECK_CURRENTLY_ON(BrowserThread::IO);
651 DCHECK(enabled_);
652 safe_browsing_task_runner_->PostTask(
653 FROM_HERE,
654 base::Bind(&SafeBrowsingDatabaseManager::OnResetDatabase, this));
657 void SafeBrowsingDatabaseManager::StartOnIOThread() {
658 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is fixed.
659 tracked_objects::ScopedTracker tracking_profile1(
660 FROM_HERE_WITH_EXPLICIT_FUNCTION(
661 "455469 SafeBrowsingDatabaseManager::StartOnIOThread1"));
662 DCHECK_CURRENTLY_ON(BrowserThread::IO);
663 if (enabled_)
664 return;
666 // Use the blocking pool instead of a dedicated thread for safe browsing work,
667 // if specified by an experiment.
668 const bool use_blocking_pool =
669 variations::GetVariationParamValue("LightSpeed", "SBThreadingMode") ==
670 "BlockingPool2";
671 if (!use_blocking_pool) {
672 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is
673 // fixed.
674 tracked_objects::ScopedTracker tracking_profile3(
675 FROM_HERE_WITH_EXPLICIT_FUNCTION(
676 "455469 SafeBrowsingDatabaseManager::StartOnIOThread3"));
677 DCHECK(!safe_browsing_thread_.get());
679 safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
680 if (!safe_browsing_thread_->Start())
681 return;
682 safe_browsing_task_runner_ = safe_browsing_thread_->task_runner();
683 } else if (!safe_browsing_task_runner_) {
684 // Only get a new task runner if there isn't one already. If the service has
685 // previously been started and stopped, a task runner could already exist.
687 // TODO(pkasting): Remove ScopedTracker below once crbug.com/455469 is
688 // fixed.
689 tracked_objects::ScopedTracker tracking_profile2(
690 FROM_HERE_WITH_EXPLICIT_FUNCTION(
691 "455469 SafeBrowsingDatabaseManager::StartOnIOThread2"));
692 base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
693 safe_browsing_task_runner_ =
694 pool->GetSequencedTaskRunnerWithShutdownBehavior(
695 pool->GetSequenceToken(),
696 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
699 enabled_ = true;
701 MakeDatabaseAvailable();
704 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
705 DCHECK_CURRENTLY_ON(BrowserThread::IO);
707 DoStopOnIOThread();
708 if (shutdown) {
709 sb_service_ = NULL;
713 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
714 bool update_succeeded) {
715 DCHECK_CURRENTLY_ON(BrowserThread::UI);
716 content::NotificationService::current()->Notify(
717 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
718 content::Source<SafeBrowsingDatabaseManager>(this),
719 content::Details<bool>(&update_succeeded));
722 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
723 const safe_browsing_util::ListType check_type,
724 Client* client,
725 const GURL& url,
726 const std::vector<SBThreatType>& expected_threats,
727 const base::TimeTicks& start)
728 : check_type(check_type),
729 client(client),
730 url(url),
731 expected_threats(expected_threats),
732 start(start) {
735 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
738 void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
739 DCHECK_CURRENTLY_ON(BrowserThread::IO);
741 if (!enabled_)
742 return;
744 enabled_ = false;
746 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
747 while (!queued_checks_.empty()) {
748 QueuedCheck queued = queued_checks_.front();
749 if (queued.client) {
750 SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url),
751 std::vector<SBFullHash>(),
752 queued.client,
753 queued.check_type,
754 queued.expected_threats);
755 queued.client->OnSafeBrowsingResult(sb_check);
757 queued_checks_.pop_front();
760 // Close the database. Cases to avoid:
761 // * If |closing_database_| is true, continuing will queue up a second
762 // request, |closing_database_| will be reset after handling the first
763 // request, and if any functions on the db thread recreate the database, we
764 // could start using it on the IO thread and then have the second request
765 // handler delete it out from under us.
766 // * If |database_| is NULL, then either no creation request is in flight, in
767 // which case we don't need to do anything, or one is in flight, in which
768 // case the database will be recreated before our deletion request is
769 // handled, and could be used on the IO thread in that time period, leading
770 // to the same problem as above.
771 // Checking DatabaseAvailable() avoids both of these.
772 if (DatabaseAvailable()) {
773 closing_database_ = true;
774 safe_browsing_task_runner_->PostTask(
775 FROM_HERE,
776 base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this));
779 // Flush the database thread. Any in-progress database check results will be
780 // ignored and cleaned up below.
782 // Note that to avoid leaking the database, we rely on the fact that no new
783 // tasks will be added to the db thread between the call above and this one.
784 // See comments on the declaration of |safe_browsing_thread_|.
785 if (safe_browsing_thread_) {
786 // A ScopedAllowIO object is required to join the thread when calling Stop.
787 // See http://crbug.com/72696. Note that we call Stop() first to clear out
788 // any remaining tasks before clearing safe_browsing_thread_.
789 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
790 safe_browsing_thread_->Stop();
791 safe_browsing_thread_.reset();
792 safe_browsing_task_runner_ = nullptr;
795 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
796 // We have to do this after the db thread returns because methods on it can
797 // have copies of these pointers, so deleting them might lead to accessing
798 // garbage.
799 for (CurrentChecks::iterator it = checks_.begin();
800 it != checks_.end(); ++it) {
801 SafeBrowsingCheck* check = *it;
802 if (check->client)
803 check->client->OnSafeBrowsingResult(*check);
805 STLDeleteElements(&checks_);
807 gethash_requests_.clear();
810 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
811 base::AutoLock lock(database_lock_);
812 return !closing_database_ && (database_ != NULL);
815 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
816 DCHECK_CURRENTLY_ON(BrowserThread::IO);
817 DCHECK(enabled_);
818 if (DatabaseAvailable())
819 return true;
820 safe_browsing_task_runner_->PostTask(
821 FROM_HERE,
822 base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase),
823 this));
824 return false;
827 SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
828 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
830 if (database_)
831 return database_;
832 startup_metric_utils::ScopedSlowStartupUMA
833 scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
834 const base::TimeTicks before = base::TimeTicks::Now();
836 SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create(
837 safe_browsing_task_runner_, enable_download_protection_,
838 enable_csd_whitelist_, enable_download_whitelist_,
839 enable_extension_blacklist_, enable_side_effect_free_whitelist_,
840 enable_ip_blacklist_, enable_unwanted_software_blacklist_);
842 database->Init(SafeBrowsingService::GetBaseFilename());
844 // Acquiring the lock here guarantees correct ordering between the writes to
845 // the new database object above, and the setting of |database_| below.
846 base::AutoLock lock(database_lock_);
847 database_ = database;
850 BrowserThread::PostTask(
851 BrowserThread::IO, FROM_HERE,
852 base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this));
854 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
855 return database_;
858 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) {
859 DCHECK_CURRENTLY_ON(BrowserThread::IO);
861 if (!enabled_)
862 return;
864 // If the service has been shut down, |check| should have been deleted.
865 DCHECK(checks_.find(check) != checks_.end());
867 if (check->client && check->need_get_hash) {
868 // We have a partial match so we need to query Google for the full hash.
869 // Clean up will happen in HandleGetHashResults.
871 // See if we have a GetHash request already in progress for this particular
872 // prefix. If so, we just append ourselves to the list of interested parties
873 // when the results arrive. We only do this for checks involving one prefix,
874 // since that is the common case (multiple prefixes will issue the request
875 // as normal).
876 if (check->prefix_hits.size() == 1) {
877 SBPrefix prefix = check->prefix_hits[0];
878 GetHashRequests::iterator it = gethash_requests_.find(prefix);
879 if (it != gethash_requests_.end()) {
880 // There's already a request in progress.
881 it->second.push_back(check);
882 return;
885 // No request in progress, so we're the first for this prefix.
886 GetHashRequestors requestors;
887 requestors.push_back(check);
888 gethash_requests_[prefix] = requestors;
891 // Reset the start time so that we can measure the network time without the
892 // database time.
893 check->start = base::TimeTicks::Now();
894 // Note: If |this| is deleted or stopped, the protocol_manager will
895 // be destroyed as well - hence it's OK to do unretained in this case.
896 bool is_download = check->check_type == safe_browsing_util::BINURL;
897 sb_service_->protocol_manager()->GetFullHash(
898 check->prefix_hits,
899 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults,
900 base::Unretained(this),
901 check),
902 is_download);
903 } else {
904 // We may have cached results for previous GetHash queries. Since
905 // this data comes from cache, don't histogram hits.
906 HandleOneCheck(check, check->cache_hits);
910 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
911 GetChunksCallback callback) {
912 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
914 bool database_error = true;
915 std::vector<SBListChunkRanges> lists;
916 DCHECK(!database_update_in_progress_);
917 database_update_in_progress_ = true;
918 GetDatabase(); // This guarantees that |database_| is non-NULL.
919 if (database_->UpdateStarted(&lists)) {
920 database_error = false;
921 } else {
922 database_->UpdateFinished(false);
925 BrowserThread::PostTask(
926 BrowserThread::IO, FROM_HERE,
927 base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase,
928 this, lists, database_error, callback));
931 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
932 const std::vector<SBListChunkRanges>& lists, bool database_error,
933 GetChunksCallback callback) {
934 DCHECK_CURRENTLY_ON(BrowserThread::IO);
935 if (enabled_)
936 callback.Run(lists, database_error);
939 void SafeBrowsingDatabaseManager::OnAddChunksComplete(
940 AddChunksCallback callback) {
941 DCHECK_CURRENTLY_ON(BrowserThread::IO);
942 if (enabled_)
943 callback.Run();
946 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
947 DCHECK_CURRENTLY_ON(BrowserThread::IO);
948 if (!enabled_)
949 return;
951 LOCAL_HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
952 if (queued_checks_.empty())
953 return;
955 // If the database isn't already available, calling CheckUrl() in the loop
956 // below will add the check back to the queue, and we'll infinite-loop.
957 DCHECK(DatabaseAvailable());
958 while (!queued_checks_.empty()) {
959 QueuedCheck check = queued_checks_.front();
960 DCHECK(!check.start.is_null());
961 LOCAL_HISTOGRAM_TIMES("SB.QueueDelay",
962 base::TimeTicks::Now() - check.start);
963 // If CheckUrl() determines the URL is safe immediately, it doesn't call the
964 // client's handler function (because normally it's being directly called by
965 // the client). Since we're not the client, we have to convey this result.
966 if (check.client && CheckBrowseUrl(check.url, check.client)) {
967 SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url),
968 std::vector<SBFullHash>(),
969 check.client,
970 check.check_type,
971 check.expected_threats);
972 check.client->OnSafeBrowsingResult(sb_check);
974 queued_checks_.pop_front();
978 void SafeBrowsingDatabaseManager::AddDatabaseChunks(
979 const std::string& list_name,
980 scoped_ptr<ScopedVector<SBChunkData> > chunks,
981 AddChunksCallback callback) {
982 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
983 if (chunks)
984 GetDatabase()->InsertChunks(list_name, chunks->get());
985 BrowserThread::PostTask(
986 BrowserThread::IO, FROM_HERE,
987 base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this,
988 callback));
991 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
992 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) {
993 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
994 if (chunk_deletes)
995 GetDatabase()->DeleteChunks(*chunk_deletes);
998 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
999 bool update_succeeded) {
1000 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1001 GetDatabase()->UpdateFinished(update_succeeded);
1002 DCHECK(database_update_in_progress_);
1003 database_update_in_progress_ = false;
1004 BrowserThread::PostTask(
1005 BrowserThread::UI, FROM_HERE,
1006 base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished,
1007 this, update_succeeded));
1010 void SafeBrowsingDatabaseManager::OnCloseDatabase() {
1011 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1012 DCHECK(closing_database_);
1014 // Because |closing_database_| is true, nothing on the IO thread will be
1015 // accessing the database, so it's safe to delete and then NULL the pointer.
1016 delete database_;
1017 database_ = NULL;
1019 // Acquiring the lock here guarantees correct ordering between the resetting
1020 // of |database_| above and of |closing_database_| below, which ensures there
1021 // won't be a window during which the IO thread falsely believes the database
1022 // is available.
1023 base::AutoLock lock(database_lock_);
1024 closing_database_ = false;
1027 void SafeBrowsingDatabaseManager::OnResetDatabase() {
1028 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1030 GetDatabase()->ResetDatabase();
1033 void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
1034 SafeBrowsingCheck* check,
1035 const std::vector<SBFullHashResult>& full_hashes) {
1036 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1037 safe_browsing_util::ListType check_type = check->check_type;
1038 SBPrefix prefix = check->prefix_hits[0];
1039 GetHashRequests::iterator it = gethash_requests_.find(prefix);
1040 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
1041 const bool hit = HandleOneCheck(check, full_hashes);
1042 RecordGetHashCheckStatus(hit, check_type, full_hashes);
1043 return;
1046 // Call back all interested parties, noting if any has a hit.
1047 GetHashRequestors& requestors = it->second;
1048 bool hit = false;
1049 for (GetHashRequestors::iterator r = requestors.begin();
1050 r != requestors.end(); ++r) {
1051 if (HandleOneCheck(*r, full_hashes))
1052 hit = true;
1054 RecordGetHashCheckStatus(hit, check_type, full_hashes);
1056 gethash_requests_.erase(it);
1059 bool SafeBrowsingDatabaseManager::HandleOneCheck(
1060 SafeBrowsingCheck* check,
1061 const std::vector<SBFullHashResult>& full_hashes) {
1062 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1063 DCHECK(check);
1065 bool is_threat = false;
1067 // TODO(shess): GetHashSeverestThreadListType() contains a loop,
1068 // GetUrlSeverestThreatListType() a loop around that loop. Having another
1069 // loop out here concerns me. It is likely that SAFE is an expected outcome,
1070 // which means all of those loops run to completion. Refactoring this to
1071 // generate a set of sorted items to compare in sequence would probably
1072 // improve things.
1074 // Additionally, the set of patterns generated from the urls is very similar
1075 // to the patterns generated in ContainsBrowseUrl() and other database checks,
1076 // which are called from this code. Refactoring that across the checks could
1077 // interact well with batching the checks here.
1079 // TODO(gab): Fix the fact that Get(Url|Hash)SeverestThreatType() may return a
1080 // threat for which IsExpectedThreat() returns false even if |full_hashes|
1081 // actually contains an expected threat.
1083 for (size_t i = 0; i < check->urls.size(); ++i) {
1084 size_t threat_index;
1085 SBThreatType threat =
1086 GetUrlSeverestThreatType(check->urls[i], full_hashes, &threat_index);
1087 if (threat != SB_THREAT_TYPE_SAFE &&
1088 IsExpectedThreat(threat, check->expected_threats)) {
1089 check->url_results[i] = threat;
1090 check->url_metadata[i] = full_hashes[threat_index].metadata;
1091 is_threat = true;
1095 for (size_t i = 0; i < check->full_hashes.size(); ++i) {
1096 SBThreatType threat =
1097 GetHashSeverestThreatType(check->full_hashes[i], full_hashes);
1098 if (threat != SB_THREAT_TYPE_SAFE &&
1099 IsExpectedThreat(threat, check->expected_threats)) {
1100 check->full_hash_results[i] = threat;
1101 is_threat = true;
1105 SafeBrowsingCheckDone(check);
1106 return is_threat;
1109 void SafeBrowsingDatabaseManager::OnAsyncCheckDone(
1110 SafeBrowsingCheck* check,
1111 const std::vector<SBPrefix>& prefix_hits) {
1112 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1113 DCHECK(enable_download_protection_);
1115 check->prefix_hits = prefix_hits;
1116 if (check->prefix_hits.empty()) {
1117 SafeBrowsingCheckDone(check);
1118 } else {
1119 check->need_get_hash = true;
1120 OnCheckDone(check);
1124 std::vector<SBPrefix> SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
1125 const std::vector<SBPrefix>& prefixes) {
1126 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1127 DCHECK(enable_download_protection_);
1129 std::vector<SBPrefix> prefix_hits;
1130 const bool result =
1131 database_->ContainsDownloadUrlPrefixes(prefixes, &prefix_hits);
1132 DCHECK_EQ(result, !prefix_hits.empty());
1133 return prefix_hits;
1136 std::vector<SBPrefix> SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
1137 const std::vector<SBPrefix>& prefixes) {
1138 DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
1140 std::vector<SBPrefix> prefix_hits;
1141 const bool result =
1142 database_->ContainsExtensionPrefixes(prefixes, &prefix_hits);
1143 DCHECK_EQ(result, !prefix_hits.empty());
1144 return prefix_hits;
1147 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
1148 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1149 DCHECK(check);
1151 if (!enabled_)
1152 return;
1154 DCHECK(checks_.find(check) != checks_.end());
1155 if (check->client) {
1156 check->client->OnSafeBrowsingResult(*check);
1157 check->client = NULL;
1161 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
1162 SafeBrowsingCheck* check) {
1163 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1164 DCHECK(check);
1166 if (!enabled_)
1167 return;
1169 DVLOG(1) << "SafeBrowsingCheckDone";
1170 DCHECK(checks_.find(check) != checks_.end());
1171 if (check->client)
1172 check->client->OnSafeBrowsingResult(*check);
1173 checks_.erase(check);
1174 delete check;
1177 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
1178 SafeBrowsingCheck* check,
1179 const base::Callback<std::vector<SBPrefix>(void)>& task) {
1180 DCHECK_CURRENTLY_ON(BrowserThread::IO);
1181 check->weak_ptr_factory_.reset(
1182 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this));
1183 checks_.insert(check);
1185 base::PostTaskAndReplyWithResult(
1186 safe_browsing_task_runner_.get(), FROM_HERE, task,
1187 base::Bind(&SafeBrowsingDatabaseManager::OnAsyncCheckDone,
1188 check->weak_ptr_factory_->GetWeakPtr(), check));
1189 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
1190 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback,
1191 check->weak_ptr_factory_->GetWeakPtr(), check),
1192 check_timeout_);