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

Unified Diff: chrome/browser/safe_browsing/database_manager.cc

Issue 1110723002: Split to SafeBrowsingDatabaseManager into Local* and Remote*. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Respond to review. Tweak comments and list initializer. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/safe_browsing/database_manager.cc
diff --git a/chrome/browser/safe_browsing/database_manager.cc b/chrome/browser/safe_browsing/database_manager.cc
deleted file mode 100644
index 20565e811a05d382519448acde8f7a2eebb71c67..0000000000000000000000000000000000000000
--- a/chrome/browser/safe_browsing/database_manager.cc
+++ /dev/null
@@ -1,1114 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/safe_browsing/database_manager.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/debug/leak_tracker.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/prerender/prerender_field_trial.h"
-#include "chrome/browser/safe_browsing/client_side_detection_service.h"
-#include "chrome/browser/safe_browsing/download_protection_service.h"
-#include "chrome/browser/safe_browsing/malware_details.h"
-#include "chrome/browser/safe_browsing/protocol_manager.h"
-#include "chrome/browser/safe_browsing/safe_browsing_database.h"
-#include "chrome/browser/safe_browsing/safe_browsing_service.h"
-#include "chrome/browser/safe_browsing/ui_manager.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
-#include "components/startup_metric_utils/startup_metric_utils.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_service.h"
-#include "url/url_constants.h"
-
-using content::BrowserThread;
-
-namespace {
-
-// Timeout for match checks, e.g. download URLs, hashes.
-const int kCheckTimeoutMs = 10000;
-
-// Records disposition information about the check. |hit| should be
-// |true| if there were any prefix hits in |full_hashes|.
-void RecordGetHashCheckStatus(
- bool hit,
- safe_browsing_util::ListType check_type,
- const std::vector<SBFullHashResult>& full_hashes) {
- SafeBrowsingProtocolManager::ResultType result;
- if (full_hashes.empty()) {
- result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
- } else if (hit) {
- result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
- } else {
- result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
- }
- bool is_download = check_type == safe_browsing_util::BINURL;
- SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
-}
-
-bool IsExpectedThreat(
- const SBThreatType threat_type,
- const std::vector<SBThreatType>& expected_threats) {
- return expected_threats.end() != std::find(expected_threats.begin(),
- expected_threats.end(),
- threat_type);
-}
-
-// Return the severest list id from the results in |full_hashes| which matches
-// |hash|, or INVALID if none match.
-safe_browsing_util::ListType GetHashSeverestThreatListType(
- const SBFullHash& hash,
- const std::vector<SBFullHashResult>& full_hashes,
- size_t* index) {
- safe_browsing_util::ListType pending_threat = safe_browsing_util::INVALID;
- for (size_t i = 0; i < full_hashes.size(); ++i) {
- if (SBFullHashEqual(hash, full_hashes[i].hash)) {
- const safe_browsing_util::ListType threat =
- static_cast<safe_browsing_util::ListType>(full_hashes[i].list_id);
- switch (threat) {
- case safe_browsing_util::INVALID:
- // |full_hashes| should never contain INVALID as a |list_id|.
- NOTREACHED();
- break;
- case safe_browsing_util::MALWARE: // Falls through.
- case safe_browsing_util::PHISH: // Falls through.
- case safe_browsing_util::BINURL: // Falls through.
- case safe_browsing_util::CSDWHITELIST: // Falls through.
- case safe_browsing_util::DOWNLOADWHITELIST: // Falls through.
- case safe_browsing_util::INCLUSIONWHITELIST: // Falls through.
- case safe_browsing_util::EXTENSIONBLACKLIST: // Falls through.
- case safe_browsing_util::IPBLACKLIST:
- if (index)
- *index = i;
- return threat;
- case safe_browsing_util::UNWANTEDURL:
- // UNWANTEDURL is considered less severe than other threats, keep
- // looking.
- pending_threat = threat;
- if (index)
- *index = i;
- break;
- }
- }
- }
- return pending_threat;
-}
-
-// Given a URL, compare all the possible host + path full hashes to the set of
-// provided full hashes. Returns the list id of the severest matching result
-// from |full_hashes|, or INVALID if none match.
-safe_browsing_util::ListType GetUrlSeverestThreatListType(
- const GURL& url,
- const std::vector<SBFullHashResult>& full_hashes,
- size_t* index) {
- if (full_hashes.empty())
- return safe_browsing_util::INVALID;
-
- std::vector<std::string> patterns;
- safe_browsing_util::GeneratePatternsToCheck(url, &patterns);
-
- safe_browsing_util::ListType pending_threat = safe_browsing_util::INVALID;
- for (size_t i = 0; i < patterns.size(); ++i) {
- safe_browsing_util::ListType threat = GetHashSeverestThreatListType(
- SBFullHashForString(patterns[i]), full_hashes, index);
- switch (threat) {
- case safe_browsing_util::INVALID:
- // Ignore patterns with no matching threat.
- break;
- case safe_browsing_util::MALWARE: // Falls through.
- case safe_browsing_util::PHISH: // Falls through.
- case safe_browsing_util::BINURL: // Falls through.
- case safe_browsing_util::CSDWHITELIST: // Falls through.
- case safe_browsing_util::DOWNLOADWHITELIST: // Falls through.
- case safe_browsing_util::INCLUSIONWHITELIST: // Falls through.
- case safe_browsing_util::EXTENSIONBLACKLIST: // Falls through.
- case safe_browsing_util::IPBLACKLIST:
- return threat;
- case safe_browsing_util::UNWANTEDURL:
- // UNWANTEDURL is considered less severe than other threats, keep
- // looking.
- pending_threat = threat;
- break;
- }
- }
- return pending_threat;
-}
-
-SBThreatType GetThreatTypeFromListType(safe_browsing_util::ListType list_type) {
- switch (list_type) {
- case safe_browsing_util::PHISH:
- return SB_THREAT_TYPE_URL_PHISHING;
- case safe_browsing_util::MALWARE:
- return SB_THREAT_TYPE_URL_MALWARE;
- case safe_browsing_util::UNWANTEDURL:
- return SB_THREAT_TYPE_URL_UNWANTED;
- case safe_browsing_util::BINURL:
- return SB_THREAT_TYPE_BINARY_MALWARE_URL;
- case safe_browsing_util::EXTENSIONBLACKLIST:
- return SB_THREAT_TYPE_EXTENSION;
- default:
- DVLOG(1) << "Unknown safe browsing list id " << list_type;
- return SB_THREAT_TYPE_SAFE;
- }
-}
-
-} // namespace
-
-// static
-SBThreatType SafeBrowsingDatabaseManager::GetHashSeverestThreatType(
- const SBFullHash& hash,
- const std::vector<SBFullHashResult>& full_hashes) {
- return GetThreatTypeFromListType(
- GetHashSeverestThreatListType(hash, full_hashes, NULL));
-}
-
-// static
-SBThreatType SafeBrowsingDatabaseManager::GetUrlSeverestThreatType(
- const GURL& url,
- const std::vector<SBFullHashResult>& full_hashes,
- size_t* index) {
- return GetThreatTypeFromListType(
- GetUrlSeverestThreatListType(url, full_hashes, index));
-}
-
-SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
- const std::vector<GURL>& urls,
- const std::vector<SBFullHash>& full_hashes,
- Client* client,
- safe_browsing_util::ListType check_type,
- const std::vector<SBThreatType>& expected_threats)
- : urls(urls),
- url_results(urls.size(), SB_THREAT_TYPE_SAFE),
- url_metadata(urls.size()),
- full_hashes(full_hashes),
- full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE),
- client(client),
- need_get_hash(false),
- check_type(check_type),
- expected_threats(expected_threats) {
- DCHECK_EQ(urls.empty(), !full_hashes.empty())
- << "Exactly one of urls and full_hashes must be set";
-}
-
-SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
-
-void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
- const SafeBrowsingCheck& check) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- DCHECK_EQ(check.urls.size(), check.url_results.size());
- DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size());
- if (!check.urls.empty()) {
- DCHECK(check.full_hashes.empty());
- switch (check.check_type) {
- case safe_browsing_util::MALWARE:
- case safe_browsing_util::PHISH:
- case safe_browsing_util::UNWANTEDURL:
- DCHECK_EQ(1u, check.urls.size());
- OnCheckBrowseUrlResult(
- check.urls[0], check.url_results[0], check.url_metadata[0]);
- break;
- case safe_browsing_util::BINURL:
- DCHECK_EQ(check.urls.size(), check.url_results.size());
- OnCheckDownloadUrlResult(
- check.urls,
- *std::max_element(check.url_results.begin(),
- check.url_results.end()));
- break;
- default:
- NOTREACHED();
- }
- } else if (!check.full_hashes.empty()) {
- switch (check.check_type) {
- case safe_browsing_util::EXTENSIONBLACKLIST: {
- std::set<std::string> unsafe_extension_ids;
- for (size_t i = 0; i < check.full_hashes.size(); ++i) {
- std::string extension_id =
- safe_browsing_util::SBFullHashToString(check.full_hashes[i]);
- if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION)
- unsafe_extension_ids.insert(extension_id);
- }
- OnCheckExtensionsResult(unsafe_extension_ids);
- break;
- }
- default:
- NOTREACHED();
- }
- } else {
- NOTREACHED();
- }
-}
-
-SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
- const scoped_refptr<SafeBrowsingService>& service)
- : sb_service_(service),
- database_(NULL),
- enabled_(false),
- enable_download_protection_(false),
- enable_csd_whitelist_(false),
- enable_download_whitelist_(false),
- enable_extension_blacklist_(false),
- enable_ip_blacklist_(false),
- enable_unwanted_software_blacklist_(false),
- update_in_progress_(false),
- database_update_in_progress_(false),
- closing_database_(false),
- check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(sb_service_.get() != NULL);
-
- // Android only supports a subset of FULL_SAFE_BROWSING.
- // TODO(shess): This shouldn't be OS-driven <http://crbug.com/394379>
-#if !defined(OS_ANDROID)
- base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
- enable_download_protection_ =
- !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
-
- // We only download the csd-whitelist if client-side phishing detection is
- // enabled.
- enable_csd_whitelist_ =
- !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection);
-
- // TODO(noelutz): remove this boolean variable since it should always be true
- // if SafeBrowsing is enabled. Unfortunately, we have no test data for this
- // list right now. This means that we need to be able to disable this list
- // for the SafeBrowsing test to pass.
- enable_download_whitelist_ = enable_csd_whitelist_;
-
- // TODO(kalman): there really shouldn't be a flag for this.
- enable_extension_blacklist_ =
- !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
-
- // The client-side IP blacklist feature is tightly integrated with client-side
- // phishing protection for now.
- enable_ip_blacklist_ = enable_csd_whitelist_;
-
- // The UwS blacklist feature is controlled by a flag for M40.
- enable_unwanted_software_blacklist_ =
- safe_browsing_util::GetUnwantedTrialGroup() > safe_browsing_util::UWS_OFF;
-#endif
-}
-
-SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
- // The DCHECK is disabled due to crbug.com/438754.
- // DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
- // We should have already been shut down. If we're still enabled, then the
- // database isn't going to be closed properly, which could lead to corruption.
- DCHECK(!enabled_);
-}
-
-bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
- return url.SchemeIs(url::kFtpScheme) ||
- url.SchemeIs(url::kHttpScheme) ||
- url.SchemeIs(url::kHttpsScheme);
-}
-
-bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
- const std::vector<GURL>& url_chain,
- Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_ || !enable_download_protection_)
- return true;
-
- // We need to check the database for url prefix, and later may fetch the url
- // from the safebrowsing backends. These need to be asynchronous.
- SafeBrowsingCheck* check =
- new SafeBrowsingCheck(url_chain,
- std::vector<SBFullHash>(),
- client,
- safe_browsing_util::BINURL,
- std::vector<SBThreatType>(1,
- SB_THREAT_TYPE_BINARY_MALWARE_URL));
- std::vector<SBPrefix> prefixes;
- SafeBrowsingDatabase::GetDownloadUrlPrefixes(url_chain, &prefixes);
- StartSafeBrowsingCheck(
- check,
- base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this,
- prefixes));
- return false;
-}
-
-bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
- const std::set<std::string>& extension_ids,
- Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (!enabled_ || !enable_extension_blacklist_)
- return true;
-
- std::vector<SBFullHash> extension_id_hashes;
- std::transform(extension_ids.begin(), extension_ids.end(),
- std::back_inserter(extension_id_hashes),
- safe_browsing_util::StringToSBFullHash);
- std::vector<SBPrefix> prefixes;
- for (const SBFullHash& hash : extension_id_hashes)
- prefixes.push_back(hash.prefix);
-
- SafeBrowsingCheck* check = new SafeBrowsingCheck(
- std::vector<GURL>(),
- extension_id_hashes,
- client,
- safe_browsing_util::EXTENSIONBLACKLIST,
- std::vector<SBThreatType>(1, SB_THREAT_TYPE_EXTENSION));
- StartSafeBrowsingCheck(
- check,
- base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread,
- this, prefixes));
- return false;
-}
-
-bool SafeBrowsingDatabaseManager::MatchMalwareIP(
- const std::string& ip_address) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) {
- return false; // Fail open.
- }
- return database_->ContainsMalwareIP(ip_address);
-}
-
-bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
- // There is something funky going on here -- for example, perhaps the user
- // has not restarted since enabling metrics reporting, so we haven't
- // enabled the csd whitelist yet. Just to be safe we return true in this
- // case.
- return true;
- }
- return database_->ContainsCsdWhitelistedUrl(url);
-}
-
-bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
- return true;
- }
- return database_->ContainsDownloadWhitelistedUrl(url);
-}
-
-bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
- const std::string& str) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
- return true;
- }
- return database_->ContainsDownloadWhitelistedString(str);
-}
-
-bool SafeBrowsingDatabaseManager::MatchInclusionWhitelistUrl(const GURL& url) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_ || !MakeDatabaseAvailable())
- return true;
- return database_->ContainsInclusionWhitelistedUrl(url);
-}
-
-bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_ || !MakeDatabaseAvailable()) {
- return true;
- }
- return database_->IsMalwareIPMatchKillSwitchOn();
-}
-
-bool SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_ || !MakeDatabaseAvailable()) {
- return true;
- }
- return database_->IsCsdWhitelistKillSwitchOn();
-}
-
-bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
- Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_)
- return true;
-
- if (!CanCheckUrl(url))
- return true;
-
- std::vector<SBThreatType> expected_threats;
- expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE);
- expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING);
- expected_threats.push_back(SB_THREAT_TYPE_URL_UNWANTED);
-
- const base::TimeTicks start = base::TimeTicks::Now();
- if (!MakeDatabaseAvailable()) {
- QueuedCheck queued_check(safe_browsing_util::MALWARE, // or PHISH
- client,
- url,
- expected_threats,
- start);
- queued_checks_.push_back(queued_check);
- return false;
- }
-
- // Cache hits should, in general, be the same for both (ignoring potential
- // cache evictions in the second call for entries that were just about to be
- // evicted in the first call).
- // TODO(gab): Refactor SafeBrowsingDatabase to avoid depending on this here.
- std::vector<SBFullHashResult> cache_hits;
-
- std::vector<SBPrefix> browse_prefix_hits;
- bool browse_prefix_match = database_->ContainsBrowseUrl(
- url, &browse_prefix_hits, &cache_hits);
-
- std::vector<SBPrefix> unwanted_prefix_hits;
- std::vector<SBFullHashResult> unused_cache_hits;
- bool unwanted_prefix_match = database_->ContainsUnwantedSoftwareUrl(
- url, &unwanted_prefix_hits, &unused_cache_hits);
-
- // Merge the two pre-sorted prefix hits lists.
- // TODO(gab): Refactor SafeBrowsingDatabase for it to return this merged list
- // by default rather than building it here.
- std::vector<SBPrefix> prefix_hits(browse_prefix_hits.size() +
- unwanted_prefix_hits.size());
- std::merge(browse_prefix_hits.begin(),
- browse_prefix_hits.end(),
- unwanted_prefix_hits.begin(),
- unwanted_prefix_hits.end(),
- prefix_hits.begin());
- prefix_hits.erase(std::unique(prefix_hits.begin(), prefix_hits.end()),
- prefix_hits.end());
-
- UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
-
- if (!browse_prefix_match && !unwanted_prefix_match)
- return true; // URL is okay.
-
- // Needs to be asynchronous, since we could be in the constructor of a
- // ResourceDispatcherHost event handler which can't pause there.
- // This check will ping the Safe Browsing servers and get all lists which it
- // matches. These lists will then be filtered against the |expected_threats|
- // and the result callback for MALWARE (which is the same as for PHISH and
- // UNWANTEDURL) will eventually be invoked with the final decision.
- SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url),
- std::vector<SBFullHash>(),
- client,
- safe_browsing_util::MALWARE,
- expected_threats);
- check->need_get_hash = cache_hits.empty();
- check->prefix_hits.swap(prefix_hits);
- check->cache_hits.swap(cache_hits);
- checks_.insert(check);
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
-
- return false;
-}
-
-void SafeBrowsingDatabaseManager::CancelCheck(Client* client) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
- // We can't delete matching checks here because the db thread has a copy of
- // the pointer. Instead, we simply NULL out the client, and when the db
- // thread calls us back, we'll clean up the check.
- if ((*i)->client == client)
- (*i)->client = NULL;
- }
-
- // Scan the queued clients store. Clients may be here if they requested a URL
- // check before the database has finished loading.
- for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
- it != queued_checks_.end(); ) {
- // In this case it's safe to delete matches entirely since nothing has a
- // pointer to them.
- if (it->client == client)
- it = queued_checks_.erase(it);
- else
- ++it;
- }
-}
-
-void SafeBrowsingDatabaseManager::HandleGetHashResults(
- SafeBrowsingCheck* check,
- const std::vector<SBFullHashResult>& full_hashes,
- const base::TimeDelta& cache_lifetime) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (!enabled_)
- return;
-
- // If the service has been shut down, |check| should have been deleted.
- DCHECK(checks_.find(check) != checks_.end());
-
- // |start| is set before calling |GetFullHash()|, which should be
- // the only path which gets to here.
- DCHECK(!check->start.is_null());
- UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
- base::TimeTicks::Now() - check->start);
-
- std::vector<SBPrefix> prefixes = check->prefix_hits;
- OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here.
-
- // Cache the GetHash results.
- if (cache_lifetime != base::TimeDelta() && MakeDatabaseAvailable())
- database_->CacheHashResults(prefixes, full_hashes, cache_lifetime);
-}
-
-void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
- DCHECK(!callback.is_null());
- safe_browsing_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this,
- callback));
-}
-
-void SafeBrowsingDatabaseManager::AddChunks(
- const std::string& list,
- scoped_ptr<ScopedVector<SBChunkData> > chunks,
- AddChunksCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
- DCHECK(!callback.is_null());
- safe_browsing_task_runner_->PostTask(
- FROM_HERE, base::Bind(&SafeBrowsingDatabaseManager::AddDatabaseChunks,
- this, list, base::Passed(&chunks), callback));
-}
-
-void SafeBrowsingDatabaseManager::DeleteChunks(
- scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
- safe_browsing_task_runner_->PostTask(
- FROM_HERE, base::Bind(&SafeBrowsingDatabaseManager::DeleteDatabaseChunks,
- this, base::Passed(&chunk_deletes)));
-}
-
-void SafeBrowsingDatabaseManager::UpdateStarted() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
- DCHECK(!update_in_progress_);
- update_in_progress_ = true;
-}
-
-void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
- if (update_in_progress_) {
- update_in_progress_ = false;
- safe_browsing_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished, this,
- update_succeeded));
- }
-}
-
-void SafeBrowsingDatabaseManager::ResetDatabase() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
- safe_browsing_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::OnResetDatabase, this));
-}
-
-void SafeBrowsingDatabaseManager::StartOnIOThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (enabled_)
- return;
-
- // Only get a new task runner if there isn't one already. If the service has
- // previously been started and stopped, a task runner could already exist.
- if (!safe_browsing_task_runner_) {
- base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
- safe_browsing_task_runner_ =
- pool->GetSequencedTaskRunnerWithShutdownBehavior(
- pool->GetSequenceToken(),
- base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
- }
-
- enabled_ = true;
-
- MakeDatabaseAvailable();
-}
-
-void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- DoStopOnIOThread();
- if (shutdown) {
- sb_service_ = NULL;
- }
-}
-
-void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
- bool update_succeeded) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- content::NotificationService::current()->Notify(
- chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
- content::Source<SafeBrowsingDatabaseManager>(this),
- content::Details<bool>(&update_succeeded));
-}
-
-SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
- const safe_browsing_util::ListType check_type,
- Client* client,
- const GURL& url,
- const std::vector<SBThreatType>& expected_threats,
- const base::TimeTicks& start)
- : check_type(check_type),
- client(client),
- url(url),
- expected_threats(expected_threats),
- start(start) {
-}
-
-SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
-}
-
-void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (!enabled_)
- return;
-
- enabled_ = false;
-
- // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
- while (!queued_checks_.empty()) {
- QueuedCheck queued = queued_checks_.front();
- if (queued.client) {
- SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url),
- std::vector<SBFullHash>(),
- queued.client,
- queued.check_type,
- queued.expected_threats);
- queued.client->OnSafeBrowsingResult(sb_check);
- }
- queued_checks_.pop_front();
- }
-
- // Close the database. Cases to avoid:
- // * If |closing_database_| is true, continuing will queue up a second
- // request, |closing_database_| will be reset after handling the first
- // request, and if any functions on the db thread recreate the database, we
- // could start using it on the IO thread and then have the second request
- // handler delete it out from under us.
- // * If |database_| is NULL, then either no creation request is in flight, in
- // which case we don't need to do anything, or one is in flight, in which
- // case the database will be recreated before our deletion request is
- // handled, and could be used on the IO thread in that time period, leading
- // to the same problem as above.
- // Checking DatabaseAvailable() avoids both of these.
- if (DatabaseAvailable()) {
- closing_database_ = true;
- safe_browsing_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this));
- }
-
- // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
- // We have to do this after the db thread returns because methods on it can
- // have copies of these pointers, so deleting them might lead to accessing
- // garbage.
- for (CurrentChecks::iterator it = checks_.begin();
- it != checks_.end(); ++it) {
- SafeBrowsingCheck* check = *it;
- if (check->client)
- check->client->OnSafeBrowsingResult(*check);
- }
- STLDeleteElements(&checks_);
-
- gethash_requests_.clear();
-}
-
-bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
- base::AutoLock lock(database_lock_);
- return !closing_database_ && (database_ != NULL);
-}
-
-bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enabled_);
- if (DatabaseAvailable())
- return true;
- safe_browsing_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase),
- this));
- return false;
-}
-
-SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
-
- if (database_)
- return database_;
- startup_metric_utils::ScopedSlowStartupUMA
- scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
- const base::TimeTicks before = base::TimeTicks::Now();
-
- SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create(
- safe_browsing_task_runner_, enable_download_protection_,
- enable_csd_whitelist_, enable_download_whitelist_,
- enable_extension_blacklist_, enable_ip_blacklist_,
- enable_unwanted_software_blacklist_);
-
- database->Init(SafeBrowsingService::GetBaseFilename());
- {
- // Acquiring the lock here guarantees correct ordering between the writes to
- // the new database object above, and the setting of |database_| below.
- base::AutoLock lock(database_lock_);
- database_ = database;
- }
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this));
-
- UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
- return database_;
-}
-
-void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
- if (!enabled_)
- return;
-
- // If the service has been shut down, |check| should have been deleted.
- DCHECK(checks_.find(check) != checks_.end());
-
- if (check->client && check->need_get_hash) {
- // We have a partial match so we need to query Google for the full hash.
- // Clean up will happen in HandleGetHashResults.
-
- // See if we have a GetHash request already in progress for this particular
- // prefix. If so, we just append ourselves to the list of interested parties
- // when the results arrive. We only do this for checks involving one prefix,
- // since that is the common case (multiple prefixes will issue the request
- // as normal).
- if (check->prefix_hits.size() == 1) {
- SBPrefix prefix = check->prefix_hits[0];
- GetHashRequests::iterator it = gethash_requests_.find(prefix);
- if (it != gethash_requests_.end()) {
- // There's already a request in progress.
- it->second.push_back(check);
- return;
- }
-
- // No request in progress, so we're the first for this prefix.
- GetHashRequestors requestors;
- requestors.push_back(check);
- gethash_requests_[prefix] = requestors;
- }
-
- // Reset the start time so that we can measure the network time without the
- // database time.
- check->start = base::TimeTicks::Now();
- // Note: If |this| is deleted or stopped, the protocol_manager will
- // be destroyed as well - hence it's OK to do unretained in this case.
- bool is_download = check->check_type == safe_browsing_util::BINURL;
- sb_service_->protocol_manager()->GetFullHash(
- check->prefix_hits,
- base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults,
- base::Unretained(this),
- check),
- is_download);
- } else {
- // We may have cached results for previous GetHash queries. Since
- // this data comes from cache, don't histogram hits.
- HandleOneCheck(check, check->cache_hits);
- }
-}
-
-void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
- GetChunksCallback callback) {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
-
- bool database_error = true;
- std::vector<SBListChunkRanges> lists;
- DCHECK(!database_update_in_progress_);
- database_update_in_progress_ = true;
- GetDatabase(); // This guarantees that |database_| is non-NULL.
- if (database_->UpdateStarted(&lists)) {
- database_error = false;
- } else {
- database_->UpdateFinished(false);
- }
-
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase,
- this, lists, database_error, callback));
-}
-
-void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
- const std::vector<SBListChunkRanges>& lists, bool database_error,
- GetChunksCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (enabled_)
- callback.Run(lists, database_error);
-}
-
-void SafeBrowsingDatabaseManager::OnAddChunksComplete(
- AddChunksCallback callback) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (enabled_)
- callback.Run();
-}
-
-void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!enabled_)
- return;
-
- LOCAL_HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
- if (queued_checks_.empty())
- return;
-
- // If the database isn't already available, calling CheckUrl() in the loop
- // below will add the check back to the queue, and we'll infinite-loop.
- DCHECK(DatabaseAvailable());
- while (!queued_checks_.empty()) {
- QueuedCheck check = queued_checks_.front();
- DCHECK(!check.start.is_null());
- LOCAL_HISTOGRAM_TIMES("SB.QueueDelay",
- base::TimeTicks::Now() - check.start);
- // If CheckUrl() determines the URL is safe immediately, it doesn't call the
- // client's handler function (because normally it's being directly called by
- // the client). Since we're not the client, we have to convey this result.
- if (check.client && CheckBrowseUrl(check.url, check.client)) {
- SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url),
- std::vector<SBFullHash>(),
- check.client,
- check.check_type,
- check.expected_threats);
- check.client->OnSafeBrowsingResult(sb_check);
- }
- queued_checks_.pop_front();
- }
-}
-
-void SafeBrowsingDatabaseManager::AddDatabaseChunks(
- const std::string& list_name,
- scoped_ptr<ScopedVector<SBChunkData> > chunks,
- AddChunksCallback callback) {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
- if (chunks)
- GetDatabase()->InsertChunks(list_name, chunks->get());
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this,
- callback));
-}
-
-void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
- scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
- if (chunk_deletes)
- GetDatabase()->DeleteChunks(*chunk_deletes);
-}
-
-void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
- bool update_succeeded) {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
- GetDatabase()->UpdateFinished(update_succeeded);
- DCHECK(database_update_in_progress_);
- database_update_in_progress_ = false;
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished,
- this, update_succeeded));
-}
-
-void SafeBrowsingDatabaseManager::OnCloseDatabase() {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
- DCHECK(closing_database_);
-
- // Because |closing_database_| is true, nothing on the IO thread will be
- // accessing the database, so it's safe to delete and then NULL the pointer.
- delete database_;
- database_ = NULL;
-
- // Acquiring the lock here guarantees correct ordering between the resetting
- // of |database_| above and of |closing_database_| below, which ensures there
- // won't be a window during which the IO thread falsely believes the database
- // is available.
- base::AutoLock lock(database_lock_);
- closing_database_ = false;
-}
-
-void SafeBrowsingDatabaseManager::OnResetDatabase() {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
-
- GetDatabase()->ResetDatabase();
-}
-
-void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
- SafeBrowsingCheck* check,
- const std::vector<SBFullHashResult>& full_hashes) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- safe_browsing_util::ListType check_type = check->check_type;
- SBPrefix prefix = check->prefix_hits[0];
- GetHashRequests::iterator it = gethash_requests_.find(prefix);
- if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
- const bool hit = HandleOneCheck(check, full_hashes);
- RecordGetHashCheckStatus(hit, check_type, full_hashes);
- return;
- }
-
- // Call back all interested parties, noting if any has a hit.
- GetHashRequestors& requestors = it->second;
- bool hit = false;
- for (GetHashRequestors::iterator r = requestors.begin();
- r != requestors.end(); ++r) {
- if (HandleOneCheck(*r, full_hashes))
- hit = true;
- }
- RecordGetHashCheckStatus(hit, check_type, full_hashes);
-
- gethash_requests_.erase(it);
-}
-
-bool SafeBrowsingDatabaseManager::HandleOneCheck(
- SafeBrowsingCheck* check,
- const std::vector<SBFullHashResult>& full_hashes) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(check);
-
- bool is_threat = false;
-
- // TODO(shess): GetHashSeverestThreadListType() contains a loop,
- // GetUrlSeverestThreatListType() a loop around that loop. Having another
- // loop out here concerns me. It is likely that SAFE is an expected outcome,
- // which means all of those loops run to completion. Refactoring this to
- // generate a set of sorted items to compare in sequence would probably
- // improve things.
- //
- // Additionally, the set of patterns generated from the urls is very similar
- // to the patterns generated in ContainsBrowseUrl() and other database checks,
- // which are called from this code. Refactoring that across the checks could
- // interact well with batching the checks here.
-
- // TODO(gab): Fix the fact that Get(Url|Hash)SeverestThreatType() may return a
- // threat for which IsExpectedThreat() returns false even if |full_hashes|
- // actually contains an expected threat.
-
- for (size_t i = 0; i < check->urls.size(); ++i) {
- size_t threat_index;
- SBThreatType threat =
- GetUrlSeverestThreatType(check->urls[i], full_hashes, &threat_index);
- if (threat != SB_THREAT_TYPE_SAFE &&
- IsExpectedThreat(threat, check->expected_threats)) {
- check->url_results[i] = threat;
- check->url_metadata[i] = full_hashes[threat_index].metadata;
- is_threat = true;
- }
- }
-
- for (size_t i = 0; i < check->full_hashes.size(); ++i) {
- SBThreatType threat =
- GetHashSeverestThreatType(check->full_hashes[i], full_hashes);
- if (threat != SB_THREAT_TYPE_SAFE &&
- IsExpectedThreat(threat, check->expected_threats)) {
- check->full_hash_results[i] = threat;
- is_threat = true;
- }
- }
-
- SafeBrowsingCheckDone(check);
- return is_threat;
-}
-
-void SafeBrowsingDatabaseManager::OnAsyncCheckDone(
- SafeBrowsingCheck* check,
- const std::vector<SBPrefix>& prefix_hits) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(enable_download_protection_);
-
- check->prefix_hits = prefix_hits;
- if (check->prefix_hits.empty()) {
- SafeBrowsingCheckDone(check);
- } else {
- check->need_get_hash = true;
- OnCheckDone(check);
- }
-}
-
-std::vector<SBPrefix> SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
- const std::vector<SBPrefix>& prefixes) {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
- DCHECK(enable_download_protection_);
-
- std::vector<SBPrefix> prefix_hits;
- const bool result =
- database_->ContainsDownloadUrlPrefixes(prefixes, &prefix_hits);
- DCHECK_EQ(result, !prefix_hits.empty());
- return prefix_hits;
-}
-
-std::vector<SBPrefix> SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
- const std::vector<SBPrefix>& prefixes) {
- DCHECK(safe_browsing_task_runner_->RunsTasksOnCurrentThread());
-
- std::vector<SBPrefix> prefix_hits;
- const bool result =
- database_->ContainsExtensionPrefixes(prefixes, &prefix_hits);
- DCHECK_EQ(result, !prefix_hits.empty());
- return prefix_hits;
-}
-
-void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(check);
-
- if (!enabled_)
- return;
-
- DCHECK(checks_.find(check) != checks_.end());
- if (check->client) {
- check->client->OnSafeBrowsingResult(*check);
- check->client = NULL;
- }
-}
-
-void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
- SafeBrowsingCheck* check) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DCHECK(check);
-
- if (!enabled_)
- return;
-
- DVLOG(1) << "SafeBrowsingCheckDone";
- DCHECK(checks_.find(check) != checks_.end());
- if (check->client)
- check->client->OnSafeBrowsingResult(*check);
- checks_.erase(check);
- delete check;
-}
-
-void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
- SafeBrowsingCheck* check,
- const base::Callback<std::vector<SBPrefix>(void)>& task) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- check->weak_ptr_factory_.reset(
- new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this));
- checks_.insert(check);
-
- base::PostTaskAndReplyWithResult(
- safe_browsing_task_runner_.get(), FROM_HERE, task,
- base::Bind(&SafeBrowsingDatabaseManager::OnAsyncCheckDone,
- check->weak_ptr_factory_->GetWeakPtr(), check));
- base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
- base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback,
- check->weak_ptr_factory_->GetWeakPtr(), check),
- check_timeout_);
-}

Powered by Google App Engine
This is Rietveld 408576698