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"
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/path_service.h"
15 #include "base/stl_util.h"
16 #include "base/strings/string_util.h"
17 #include "base/threading/thread.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chrome_notification_types.h"
21 #include "chrome/browser/metrics/metrics_service.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 "chrome/common/url_constants.h"
34 #include "components/startup_metric_utils/startup_metric_utils.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
38 using content::BrowserThread;
42 // Timeout for match checks, e.g. download URLs, hashes.
43 const int kCheckTimeoutMs = 10000;
45 // Records disposition information about the check. |hit| should be
46 // |true| if there were any prefix hits in |full_hashes|.
47 void RecordGetHashCheckStatus(
49 safe_browsing_util::ListType check_type,
50 const std::vector<SBFullHashResult>& full_hashes) {
51 SafeBrowsingProtocolManager::ResultType result;
52 if (full_hashes.empty()) {
53 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
55 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
57 result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
59 bool is_download = check_type == safe_browsing_util::BINURL;
60 SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
63 bool IsExpectedThreat(
64 const SBThreatType threat_type,
65 const std::vector<SBThreatType>& expected_threats) {
66 return expected_threats.end() != std::find(expected_threats.begin(),
67 expected_threats.end(),
73 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
74 const std::vector<GURL>& urls,
75 const std::vector<SBFullHash>& full_hashes,
77 safe_browsing_util::ListType check_type,
78 const std::vector<SBThreatType>& expected_threats)
80 url_results(urls.size(), SB_THREAT_TYPE_SAFE),
81 full_hashes(full_hashes),
82 full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE),
85 check_type(check_type),
86 expected_threats(expected_threats) {
87 DCHECK_EQ(urls.empty(), !full_hashes.empty())
88 << "Exactly one of urls and full_hashes must be set";
91 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
93 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
94 const SafeBrowsingCheck& check) {
95 DCHECK_EQ(check.urls.size(), check.url_results.size());
96 DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size());
97 if (!check.urls.empty()) {
98 DCHECK(check.full_hashes.empty());
99 switch (check.check_type) {
100 case safe_browsing_util::MALWARE:
101 case safe_browsing_util::PHISH:
102 DCHECK_EQ(1u, check.urls.size());
103 OnCheckBrowseUrlResult(check.urls[0], check.url_results[0]);
105 case safe_browsing_util::BINURL:
106 DCHECK_EQ(check.urls.size(), check.url_results.size());
107 OnCheckDownloadUrlResult(
109 *std::max_element(check.url_results.begin(),
110 check.url_results.end()));
115 } else if (!check.full_hashes.empty()) {
116 switch (check.check_type) {
117 case safe_browsing_util::EXTENSIONBLACKLIST: {
118 std::set<std::string> unsafe_extension_ids;
119 for (size_t i = 0; i < check.full_hashes.size(); ++i) {
120 std::string extension_id =
121 safe_browsing_util::SBFullHashToString(check.full_hashes[i]);
122 if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION)
123 unsafe_extension_ids.insert(extension_id);
125 OnCheckExtensionsResult(unsafe_extension_ids);
136 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
137 const scoped_refptr<SafeBrowsingService>& service)
138 : sb_service_(service),
141 enable_download_protection_(false),
142 enable_csd_whitelist_(false),
143 enable_download_whitelist_(false),
144 enable_extension_blacklist_(false),
145 enable_side_effect_free_whitelist_(false),
146 enable_ip_blacklist_(false),
147 update_in_progress_(false),
148 database_update_in_progress_(false),
149 closing_database_(false),
150 check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) {
151 DCHECK(sb_service_.get() != NULL);
153 CommandLine* cmdline = CommandLine::ForCurrentProcess();
154 enable_download_protection_ =
155 !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
157 // We only download the csd-whitelist if client-side phishing detection is
159 enable_csd_whitelist_ =
160 !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection);
162 // TODO(noelutz): remove this boolean variable since it should always be true
163 // if SafeBrowsing is enabled. Unfortunately, we have no test data for this
164 // list right now. This means that we need to be able to disable this list
165 // for the SafeBrowsing test to pass.
166 enable_download_whitelist_ = enable_csd_whitelist_;
168 // TODO(kalman): there really shouldn't be a flag for this.
169 enable_extension_blacklist_ =
170 !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
172 enable_side_effect_free_whitelist_ =
173 prerender::IsSideEffectFreeWhitelistEnabled() &&
174 !cmdline->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist);
176 // The client-side IP blacklist feature is tightly integrated with client-side
177 // phishing protection for now.
178 enable_ip_blacklist_ = enable_csd_whitelist_;
180 enum SideEffectFreeWhitelistStatus {
181 SIDE_EFFECT_FREE_WHITELIST_ENABLED,
182 SIDE_EFFECT_FREE_WHITELIST_DISABLED,
183 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
186 SideEffectFreeWhitelistStatus side_effect_free_whitelist_status =
187 enable_side_effect_free_whitelist_ ? SIDE_EFFECT_FREE_WHITELIST_ENABLED :
188 SIDE_EFFECT_FREE_WHITELIST_DISABLED;
190 UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
191 side_effect_free_whitelist_status,
192 SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX);
195 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
196 // We should have already been shut down. If we're still enabled, then the
197 // database isn't going to be closed properly, which could lead to corruption.
201 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
202 return url.SchemeIs(content::kFtpScheme) ||
203 url.SchemeIs(content::kHttpScheme) ||
204 url.SchemeIs(content::kHttpsScheme);
207 bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
208 const std::vector<GURL>& url_chain,
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
211 if (!enabled_ || !enable_download_protection_)
214 // We need to check the database for url prefix, and later may fetch the url
215 // from the safebrowsing backends. These need to be asynchronous.
216 SafeBrowsingCheck* check =
217 new SafeBrowsingCheck(url_chain,
218 std::vector<SBFullHash>(),
220 safe_browsing_util::BINURL,
221 std::vector<SBThreatType>(1,
222 SB_THREAT_TYPE_BINARY_MALWARE_URL));
223 StartSafeBrowsingCheck(
225 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this,
230 bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
231 const std::set<std::string>& extension_ids,
233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
235 if (!enabled_ || !enable_extension_blacklist_)
238 std::vector<SBFullHash> extension_id_hashes;
239 std::transform(extension_ids.begin(), extension_ids.end(),
240 std::back_inserter(extension_id_hashes),
241 safe_browsing_util::StringToSBFullHash);
243 SafeBrowsingCheck* check = new SafeBrowsingCheck(
247 safe_browsing_util::EXTENSIONBLACKLIST,
248 std::vector<SBThreatType>(1, SB_THREAT_TYPE_EXTENSION));
250 StartSafeBrowsingCheck(
252 base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread,
258 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
263 if (!CanCheckUrl(url))
266 return database_->ContainsSideEffectFreeWhitelistUrl(url);
269 bool SafeBrowsingDatabaseManager::MatchMalwareIP(
270 const std::string& ip_address) {
271 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
272 if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) {
273 return false; // Fail open.
275 return database_->ContainsMalwareIP(ip_address);
278 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
279 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
280 if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
281 // There is something funky going on here -- for example, perhaps the user
282 // has not restarted since enabling metrics reporting, so we haven't
283 // enabled the csd whitelist yet. Just to be safe we return true in this
287 return database_->ContainsCsdWhitelistedUrl(url);
290 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
291 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
292 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
295 return database_->ContainsDownloadWhitelistedUrl(url);
298 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
299 const std::string& str) {
300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
301 if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
304 return database_->ContainsDownloadWhitelistedString(str);
307 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
309 if (!enabled_ || !MakeDatabaseAvailable()) {
312 return database_->IsMalwareIPMatchKillSwitchOn();
315 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
321 if (!CanCheckUrl(url))
324 std::vector<SBThreatType> expected_threats;
325 expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE);
326 expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING);
328 const base::TimeTicks start = base::TimeTicks::Now();
329 if (!MakeDatabaseAvailable()) {
330 QueuedCheck queued_check(safe_browsing_util::MALWARE, // or PHISH
335 queued_checks_.push_back(queued_check);
340 std::vector<SBPrefix> prefix_hits;
341 std::vector<SBFullHashResult> full_hits;
344 database_->ContainsBrowseUrl(url, &list, &prefix_hits, &full_hits,
345 sb_service_->protocol_manager()->last_update());
347 UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
350 return true; // URL is okay.
352 // Needs to be asynchronous, since we could be in the constructor of a
353 // ResourceDispatcherHost event handler which can't pause there.
354 SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url),
355 std::vector<SBFullHash>(),
357 safe_browsing_util::MALWARE,
359 check->need_get_hash = full_hits.empty();
360 check->prefix_hits.swap(prefix_hits);
361 check->full_hits.swap(full_hits);
362 checks_.insert(check);
364 BrowserThread::PostTask(
365 BrowserThread::IO, FROM_HERE,
366 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
371 void SafeBrowsingDatabaseManager::CancelCheck(Client* client) {
372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
373 for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
374 // We can't delete matching checks here because the db thread has a copy of
375 // the pointer. Instead, we simply NULL out the client, and when the db
376 // thread calls us back, we'll clean up the check.
377 if ((*i)->client == client)
381 // Scan the queued clients store. Clients may be here if they requested a URL
382 // check before the database has finished loading.
383 for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
384 it != queued_checks_.end(); ) {
385 // In this case it's safe to delete matches entirely since nothing has a
387 if (it->client == client)
388 it = queued_checks_.erase(it);
394 void SafeBrowsingDatabaseManager::HandleGetHashResults(
395 SafeBrowsingCheck* check,
396 const std::vector<SBFullHashResult>& full_hashes,
398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
403 // If the service has been shut down, |check| should have been deleted.
404 DCHECK(checks_.find(check) != checks_.end());
406 // |start| is set before calling |GetFullHash()|, which should be
407 // the only path which gets to here.
408 DCHECK(!check->start.is_null());
409 UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
410 base::TimeTicks::Now() - check->start);
412 std::vector<SBPrefix> prefixes = check->prefix_hits;
413 OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here.
415 if (can_cache && MakeDatabaseAvailable()) {
416 // Cache the GetHash results in memory:
417 database_->CacheHashResults(prefixes, full_hashes);
421 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) {
422 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
424 DCHECK(!callback.is_null());
425 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
426 &SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this, callback));
429 void SafeBrowsingDatabaseManager::AddChunks(const std::string& list,
431 AddChunksCallback callback) {
432 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
434 DCHECK(!callback.is_null());
435 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
436 &SafeBrowsingDatabaseManager::AddDatabaseChunks, this, list,
440 void SafeBrowsingDatabaseManager::DeleteChunks(
441 std::vector<SBChunkDelete>* chunk_deletes) {
442 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
444 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
445 &SafeBrowsingDatabaseManager::DeleteDatabaseChunks, this, chunk_deletes));
448 void SafeBrowsingDatabaseManager::UpdateStarted() {
449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
451 DCHECK(!update_in_progress_);
452 update_in_progress_ = true;
455 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) {
456 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
458 if (update_in_progress_) {
459 update_in_progress_ = false;
460 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
461 base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished,
462 this, update_succeeded));
466 void SafeBrowsingDatabaseManager::ResetDatabase() {
467 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
469 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
470 &SafeBrowsingDatabaseManager::OnResetDatabase, this));
473 void SafeBrowsingDatabaseManager::LogPauseDelay(base::TimeDelta time) {
474 UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
477 void SafeBrowsingDatabaseManager::StartOnIOThread() {
478 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
482 DCHECK(!safe_browsing_thread_.get());
483 safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
484 if (!safe_browsing_thread_->Start())
488 MakeDatabaseAvailable();
491 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
492 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
500 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
501 bool update_succeeded) {
502 content::NotificationService::current()->Notify(
503 chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
504 content::Source<SafeBrowsingDatabaseManager>(this),
505 content::Details<bool>(&update_succeeded));
508 SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
509 const safe_browsing_util::ListType check_type,
512 const std::vector<SBThreatType>& expected_threats,
513 const base::TimeTicks& start)
514 : check_type(check_type),
517 expected_threats(expected_threats),
521 SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
524 void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
530 // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
531 while (!queued_checks_.empty()) {
532 QueuedCheck queued = queued_checks_.front();
534 SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url),
535 std::vector<SBFullHash>(),
538 queued.expected_threats);
539 queued.client->OnSafeBrowsingResult(sb_check);
541 queued_checks_.pop_front();
544 // Close the database. Cases to avoid:
545 // * If |closing_database_| is true, continuing will queue up a second
546 // request, |closing_database_| will be reset after handling the first
547 // request, and if any functions on the db thread recreate the database, we
548 // could start using it on the IO thread and then have the second request
549 // handler delete it out from under us.
550 // * If |database_| is NULL, then either no creation request is in flight, in
551 // which case we don't need to do anything, or one is in flight, in which
552 // case the database will be recreated before our deletion request is
553 // handled, and could be used on the IO thread in that time period, leading
554 // to the same problem as above.
555 // Checking DatabaseAvailable() avoids both of these.
556 if (DatabaseAvailable()) {
557 closing_database_ = true;
558 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
559 base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this));
562 // Flush the database thread. Any in-progress database check results will be
563 // ignored and cleaned up below.
565 // Note that to avoid leaking the database, we rely on the fact that no new
566 // tasks will be added to the db thread between the call above and this one.
567 // See comments on the declaration of |safe_browsing_thread_|.
569 // A ScopedAllowIO object is required to join the thread when calling Stop.
570 // See http://crbug.com/72696. Note that we call Stop() first to clear out
571 // any remaining tasks before clearing safe_browsing_thread_.
572 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
573 safe_browsing_thread_->Stop();
574 safe_browsing_thread_.reset();
577 // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
578 // We have to do this after the db thread returns because methods on it can
579 // have copies of these pointers, so deleting them might lead to accessing
581 for (CurrentChecks::iterator it = checks_.begin();
582 it != checks_.end(); ++it) {
583 SafeBrowsingCheck* check = *it;
585 check->client->OnSafeBrowsingResult(*check);
587 STLDeleteElements(&checks_);
589 gethash_requests_.clear();
592 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
593 base::AutoLock lock(database_lock_);
594 return !closing_database_ && (database_ != NULL);
597 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
598 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
600 if (DatabaseAvailable())
602 safe_browsing_thread_->message_loop()->PostTask(
604 base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase),
609 SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
610 DCHECK_EQ(base::MessageLoop::current(),
611 safe_browsing_thread_->message_loop());
614 startup_metric_utils::ScopedSlowStartupUMA
615 scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
616 const base::TimeTicks before = base::TimeTicks::Now();
618 SafeBrowsingDatabase* database =
619 SafeBrowsingDatabase::Create(enable_download_protection_,
620 enable_csd_whitelist_,
621 enable_download_whitelist_,
622 enable_extension_blacklist_,
623 enable_side_effect_free_whitelist_,
624 enable_ip_blacklist_);
626 database->Init(SafeBrowsingService::GetBaseFilename());
628 // Acquiring the lock here guarantees correct ordering between the writes to
629 // the new database object above, and the setting of |databse_| below.
630 base::AutoLock lock(database_lock_);
631 database_ = database;
634 BrowserThread::PostTask(
635 BrowserThread::IO, FROM_HERE,
636 base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this));
638 UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
642 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) {
643 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
648 // If the service has been shut down, |check| should have been deleted.
649 DCHECK(checks_.find(check) != checks_.end());
651 if (check->client && check->need_get_hash) {
652 // We have a partial match so we need to query Google for the full hash.
653 // Clean up will happen in HandleGetHashResults.
655 // See if we have a GetHash request already in progress for this particular
656 // prefix. If so, we just append ourselves to the list of interested parties
657 // when the results arrive. We only do this for checks involving one prefix,
658 // since that is the common case (multiple prefixes will issue the request
660 if (check->prefix_hits.size() == 1) {
661 SBPrefix prefix = check->prefix_hits[0];
662 GetHashRequests::iterator it = gethash_requests_.find(prefix);
663 if (it != gethash_requests_.end()) {
664 // There's already a request in progress.
665 it->second.push_back(check);
669 // No request in progress, so we're the first for this prefix.
670 GetHashRequestors requestors;
671 requestors.push_back(check);
672 gethash_requests_[prefix] = requestors;
675 // Reset the start time so that we can measure the network time without the
677 check->start = base::TimeTicks::Now();
678 // Note: If |this| is deleted or stopped, the protocol_manager will
679 // be destroyed as well - hence it's OK to do unretained in this case.
680 bool is_download = check->check_type == safe_browsing_util::BINURL;
681 sb_service_->protocol_manager()->GetFullHash(
683 base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults,
684 base::Unretained(this),
688 // We may have cached results for previous GetHash queries. Since
689 // this data comes from cache, don't histogram hits.
690 HandleOneCheck(check, check->full_hits);
694 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
695 GetChunksCallback callback) {
696 DCHECK_EQ(base::MessageLoop::current(),
697 safe_browsing_thread_->message_loop());
699 bool database_error = true;
700 std::vector<SBListChunkRanges> lists;
701 DCHECK(!database_update_in_progress_);
702 database_update_in_progress_ = true;
703 GetDatabase(); // This guarantees that |database_| is non-NULL.
704 if (database_->UpdateStarted(&lists)) {
705 database_error = false;
707 database_->UpdateFinished(false);
710 BrowserThread::PostTask(
711 BrowserThread::IO, FROM_HERE,
712 base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase,
713 this, lists, database_error, callback));
716 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
717 const std::vector<SBListChunkRanges>& lists, bool database_error,
718 GetChunksCallback callback) {
719 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
721 callback.Run(lists, database_error);
724 void SafeBrowsingDatabaseManager::OnAddChunksComplete(
725 AddChunksCallback callback) {
726 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
731 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
732 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
736 HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
737 if (queued_checks_.empty())
740 // If the database isn't already available, calling CheckUrl() in the loop
741 // below will add the check back to the queue, and we'll infinite-loop.
742 DCHECK(DatabaseAvailable());
743 while (!queued_checks_.empty()) {
744 QueuedCheck check = queued_checks_.front();
745 DCHECK(!check.start.is_null());
746 HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start);
747 // If CheckUrl() determines the URL is safe immediately, it doesn't call the
748 // client's handler function (because normally it's being directly called by
749 // the client). Since we're not the client, we have to convey this result.
750 if (check.client && CheckBrowseUrl(check.url, check.client)) {
751 SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url),
752 std::vector<SBFullHash>(),
755 check.expected_threats);
756 check.client->OnSafeBrowsingResult(sb_check);
758 queued_checks_.pop_front();
762 void SafeBrowsingDatabaseManager::AddDatabaseChunks(
763 const std::string& list_name, SBChunkList* chunks,
764 AddChunksCallback callback) {
765 DCHECK_EQ(base::MessageLoop::current(),
766 safe_browsing_thread_->message_loop());
768 GetDatabase()->InsertChunks(list_name, *chunks);
771 BrowserThread::PostTask(
772 BrowserThread::IO, FROM_HERE,
773 base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this,
777 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
778 std::vector<SBChunkDelete>* chunk_deletes) {
779 DCHECK_EQ(base::MessageLoop::current(),
780 safe_browsing_thread_->message_loop());
782 GetDatabase()->DeleteChunks(*chunk_deletes);
783 delete chunk_deletes;
787 SBThreatType SafeBrowsingDatabaseManager::GetThreatTypeFromListname(
788 const std::string& list_name) {
789 if (safe_browsing_util::IsPhishingList(list_name)) {
790 return SB_THREAT_TYPE_URL_PHISHING;
793 if (safe_browsing_util::IsMalwareList(list_name)) {
794 return SB_THREAT_TYPE_URL_MALWARE;
797 if (safe_browsing_util::IsBadbinurlList(list_name)) {
798 return SB_THREAT_TYPE_BINARY_MALWARE_URL;
801 if (safe_browsing_util::IsExtensionList(list_name)) {
802 return SB_THREAT_TYPE_EXTENSION;
805 DVLOG(1) << "Unknown safe browsing list " << list_name;
806 return SB_THREAT_TYPE_SAFE;
809 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
810 bool update_succeeded) {
811 DCHECK_EQ(base::MessageLoop::current(),
812 safe_browsing_thread_->message_loop());
813 GetDatabase()->UpdateFinished(update_succeeded);
814 DCHECK(database_update_in_progress_);
815 database_update_in_progress_ = false;
816 BrowserThread::PostTask(
817 BrowserThread::UI, FROM_HERE,
818 base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished,
819 this, update_succeeded));
822 void SafeBrowsingDatabaseManager::OnCloseDatabase() {
823 DCHECK_EQ(base::MessageLoop::current(),
824 safe_browsing_thread_->message_loop());
825 DCHECK(closing_database_);
827 // Because |closing_database_| is true, nothing on the IO thread will be
828 // accessing the database, so it's safe to delete and then NULL the pointer.
832 // Acquiring the lock here guarantees correct ordering between the resetting
833 // of |database_| above and of |closing_database_| below, which ensures there
834 // won't be a window during which the IO thread falsely believes the database
836 base::AutoLock lock(database_lock_);
837 closing_database_ = false;
840 void SafeBrowsingDatabaseManager::OnResetDatabase() {
841 DCHECK_EQ(base::MessageLoop::current(),
842 safe_browsing_thread_->message_loop());
843 GetDatabase()->ResetDatabase();
846 void SafeBrowsingDatabaseManager::CacheHashResults(
847 const std::vector<SBPrefix>& prefixes,
848 const std::vector<SBFullHashResult>& full_hashes) {
849 DCHECK_EQ(base::MessageLoop::current(),
850 safe_browsing_thread_->message_loop());
851 GetDatabase()->CacheHashResults(prefixes, full_hashes);
854 void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
855 SafeBrowsingCheck* check,
856 const std::vector<SBFullHashResult>& full_hashes) {
857 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
858 safe_browsing_util::ListType check_type = check->check_type;
859 SBPrefix prefix = check->prefix_hits[0];
860 GetHashRequests::iterator it = gethash_requests_.find(prefix);
861 if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
862 const bool hit = HandleOneCheck(check, full_hashes);
863 RecordGetHashCheckStatus(hit, check_type, full_hashes);
867 // Call back all interested parties, noting if any has a hit.
868 GetHashRequestors& requestors = it->second;
870 for (GetHashRequestors::iterator r = requestors.begin();
871 r != requestors.end(); ++r) {
872 if (HandleOneCheck(*r, full_hashes))
875 RecordGetHashCheckStatus(hit, check_type, full_hashes);
877 gethash_requests_.erase(it);
880 bool SafeBrowsingDatabaseManager::HandleOneCheck(
881 SafeBrowsingCheck* check,
882 const std::vector<SBFullHashResult>& full_hashes) {
883 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
886 bool is_threat = false;
888 for (size_t i = 0; i < check->urls.size(); ++i) {
890 safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes);
893 SBThreatType threat =
894 GetThreatTypeFromListname(full_hashes[index].list_name);
895 if (threat != SB_THREAT_TYPE_SAFE &&
896 IsExpectedThreat(threat, check->expected_threats)) {
897 check->url_results[i] = threat;
902 for (size_t i = 0; i < check->full_hashes.size(); ++i) {
904 safe_browsing_util::GetHashIndex(check->full_hashes[i], full_hashes);
907 SBThreatType threat =
908 GetThreatTypeFromListname(full_hashes[index].list_name);
909 if (threat != SB_THREAT_TYPE_SAFE &&
910 IsExpectedThreat(threat, check->expected_threats)) {
911 check->full_hash_results[i] = threat;
916 SafeBrowsingCheckDone(check);
920 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
921 SafeBrowsingCheck* check) {
922 DCHECK_EQ(base::MessageLoop::current(),
923 safe_browsing_thread_->message_loop());
924 DCHECK(enable_download_protection_);
926 std::vector<SBPrefix> prefix_hits;
928 if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
929 // Good, we don't have hash for this url prefix.
930 BrowserThread::PostTask(
931 BrowserThread::IO, FROM_HERE,
932 base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this,
937 check->need_get_hash = true;
938 check->prefix_hits.clear();
939 check->prefix_hits = prefix_hits;
940 BrowserThread::PostTask(
941 BrowserThread::IO, FROM_HERE,
942 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
945 void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
946 SafeBrowsingCheck* check) {
947 DCHECK_EQ(base::MessageLoop::current(),
948 safe_browsing_thread_->message_loop());
950 std::vector<SBPrefix> prefixes;
951 for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin();
952 it != check->full_hashes.end(); ++it) {
953 prefixes.push_back((*it).prefix);
955 database_->ContainsExtensionPrefixes(prefixes, &check->prefix_hits);
957 if (check->prefix_hits.empty()) {
958 // No matches for any extensions.
959 BrowserThread::PostTask(
962 base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone, this,
965 // Some prefixes matched, we need to ask Google whether they're legit.
966 check->need_get_hash = true;
967 BrowserThread::PostTask(
970 base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
974 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
975 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
981 DCHECK(checks_.find(check) != checks_.end());
983 check->client->OnSafeBrowsingResult(*check);
984 check->client = NULL;
988 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone(
989 SafeBrowsingCheck* check) {
990 DCHECK(enable_download_protection_);
991 SafeBrowsingCheckDone(check);
994 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
995 SafeBrowsingCheck* check) {
996 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1002 VLOG(1) << "SafeBrowsingCheckDone";
1003 DCHECK(checks_.find(check) != checks_.end());
1005 check->client->OnSafeBrowsingResult(*check);
1006 checks_.erase(check);
1010 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
1011 SafeBrowsingCheck* check,
1012 const base::Closure& task) {
1013 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1014 check->timeout_factory_.reset(
1015 new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this));
1016 checks_.insert(check);
1018 safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task);
1020 base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
1021 base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback,
1022 check->timeout_factory_->GetWeakPtr(), check),