This source file includes following definitions.
- RecordGetHashCheckStatus
- IsExpectedThreat
- expected_threats
- OnSafeBrowsingResult
- check_timeout_
- CanCheckUrl
- CheckDownloadUrl
- CheckExtensionIDs
- CheckSideEffectFreeWhitelistUrl
- MatchMalwareIP
- MatchCsdWhitelistUrl
- MatchDownloadWhitelistUrl
- MatchDownloadWhitelistString
- IsMalwareKillSwitchOn
- CheckBrowseUrl
- CancelCheck
- HandleGetHashResults
- GetChunks
- AddChunks
- DeleteChunks
- UpdateStarted
- UpdateFinished
- ResetDatabase
- LogPauseDelay
- StartOnIOThread
- StopOnIOThread
- NotifyDatabaseUpdateFinished
- start
- DoStopOnIOThread
- DatabaseAvailable
- MakeDatabaseAvailable
- GetDatabase
- OnCheckDone
- GetAllChunksFromDatabase
- OnGetAllChunksFromDatabase
- OnAddChunksComplete
- DatabaseLoadComplete
- AddDatabaseChunks
- DeleteDatabaseChunks
- GetThreatTypeFromListname
- DatabaseUpdateFinished
- OnCloseDatabase
- OnResetDatabase
- CacheHashResults
- OnHandleGetHashResults
- HandleOneCheck
- CheckDownloadUrlOnSBThread
- CheckExtensionIDsOnSBThread
- TimeoutCallback
- CheckDownloadUrlDone
- SafeBrowsingCheckDone
- StartSafeBrowsingCheck
#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/path_service.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/metrics/metrics_service.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 "chrome/common/url_constants.h"
#include "components/startup_metric_utils/startup_metric_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
using content::BrowserThread;
namespace {
const int kCheckTimeoutMs = 10000;
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);
}
}
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),
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_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:
DCHECK_EQ(1u, check.urls.size());
OnCheckBrowseUrlResult(check.urls[0], check.url_results[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_side_effect_free_whitelist_(false),
enable_ip_blacklist_(false),
update_in_progress_(false),
database_update_in_progress_(false),
closing_database_(false),
check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) {
DCHECK(sb_service_.get() != NULL);
CommandLine* cmdline = CommandLine::ForCurrentProcess();
enable_download_protection_ =
!cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
enable_csd_whitelist_ =
!cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection);
enable_download_whitelist_ = enable_csd_whitelist_;
enable_extension_blacklist_ =
!cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
enable_side_effect_free_whitelist_ =
prerender::IsSideEffectFreeWhitelistEnabled() &&
!cmdline->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist);
enable_ip_blacklist_ = enable_csd_whitelist_;
enum SideEffectFreeWhitelistStatus {
SIDE_EFFECT_FREE_WHITELIST_ENABLED,
SIDE_EFFECT_FREE_WHITELIST_DISABLED,
SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
};
SideEffectFreeWhitelistStatus side_effect_free_whitelist_status =
enable_side_effect_free_whitelist_ ? SIDE_EFFECT_FREE_WHITELIST_ENABLED :
SIDE_EFFECT_FREE_WHITELIST_DISABLED;
UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
side_effect_free_whitelist_status,
SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX);
}
SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
DCHECK(!enabled_);
}
bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
return url.SchemeIs(content::kFtpScheme) ||
url.SchemeIs(content::kHttpScheme) ||
url.SchemeIs(content::kHttpsScheme);
}
bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
const std::vector<GURL>& url_chain,
Client* client) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_ || !enable_download_protection_)
return true;
SafeBrowsingCheck* check =
new SafeBrowsingCheck(url_chain,
std::vector<SBFullHash>(),
client,
safe_browsing_util::BINURL,
std::vector<SBThreatType>(1,
SB_THREAT_TYPE_BINARY_MALWARE_URL));
StartSafeBrowsingCheck(
check,
base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this,
check));
return false;
}
bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
const std::set<std::string>& extension_ids,
Client* client) {
DCHECK(BrowserThread::CurrentlyOn(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);
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,
check));
return false;
}
bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
const GURL& url) {
if (!enabled_)
return false;
if (!CanCheckUrl(url))
return false;
return database_->ContainsSideEffectFreeWhitelistUrl(url);
}
bool SafeBrowsingDatabaseManager::MatchMalwareIP(
const std::string& ip_address) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) {
return false;
}
return database_->ContainsMalwareIP(ip_address);
}
bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
return true;
}
return database_->ContainsCsdWhitelistedUrl(url);
}
bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
return true;
}
return database_->ContainsDownloadWhitelistedUrl(url);
}
bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
const std::string& str) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
return true;
}
return database_->ContainsDownloadWhitelistedString(str);
}
bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_ || !MakeDatabaseAvailable()) {
return true;
}
return database_->IsMalwareIPMatchKillSwitchOn();
}
bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
Client* client) {
DCHECK(BrowserThread::CurrentlyOn(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);
const base::TimeTicks start = base::TimeTicks::Now();
if (!MakeDatabaseAvailable()) {
QueuedCheck queued_check(safe_browsing_util::MALWARE,
client,
url,
expected_threats,
start);
queued_checks_.push_back(queued_check);
return false;
}
std::string list;
std::vector<SBPrefix> prefix_hits;
std::vector<SBFullHashResult> full_hits;
bool prefix_match =
database_->ContainsBrowseUrl(url, &list, &prefix_hits, &full_hits,
sb_service_->protocol_manager()->last_update());
UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
if (!prefix_match)
return true;
SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url),
std::vector<SBFullHash>(),
client,
safe_browsing_util::MALWARE,
expected_threats);
check->need_get_hash = full_hits.empty();
check->prefix_hits.swap(prefix_hits);
check->full_hits.swap(full_hits);
checks_.insert(check);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
return false;
}
void SafeBrowsingDatabaseManager::CancelCheck(Client* client) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
if ((*i)->client == client)
(*i)->client = NULL;
}
for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
it != queued_checks_.end(); ) {
if (it->client == client)
it = queued_checks_.erase(it);
else
++it;
}
}
void SafeBrowsingDatabaseManager::HandleGetHashResults(
SafeBrowsingCheck* check,
const std::vector<SBFullHashResult>& full_hashes,
bool can_cache) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_)
return;
DCHECK(checks_.find(check) != checks_.end());
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);
if (can_cache && MakeDatabaseAvailable()) {
database_->CacheHashResults(prefixes, full_hashes);
}
}
void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(enabled_);
DCHECK(!callback.is_null());
safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
&SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this, callback));
}
void SafeBrowsingDatabaseManager::AddChunks(const std::string& list,
SBChunkList* chunks,
AddChunksCallback callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(enabled_);
DCHECK(!callback.is_null());
safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
&SafeBrowsingDatabaseManager::AddDatabaseChunks, this, list,
chunks, callback));
}
void SafeBrowsingDatabaseManager::DeleteChunks(
std::vector<SBChunkDelete>* chunk_deletes) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(enabled_);
safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
&SafeBrowsingDatabaseManager::DeleteDatabaseChunks, this, chunk_deletes));
}
void SafeBrowsingDatabaseManager::UpdateStarted() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(enabled_);
DCHECK(!update_in_progress_);
update_in_progress_ = true;
}
void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(enabled_);
if (update_in_progress_) {
update_in_progress_ = false;
safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished,
this, update_succeeded));
}
}
void SafeBrowsingDatabaseManager::ResetDatabase() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(enabled_);
safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
&SafeBrowsingDatabaseManager::OnResetDatabase, this));
}
void SafeBrowsingDatabaseManager::LogPauseDelay(base::TimeDelta time) {
UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
}
void SafeBrowsingDatabaseManager::StartOnIOThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (enabled_)
return;
DCHECK(!safe_browsing_thread_.get());
safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
if (!safe_browsing_thread_->Start())
return;
enabled_ = true;
MakeDatabaseAvailable();
}
void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DoStopOnIOThread();
if (shutdown) {
sb_service_ = NULL;
}
}
void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
bool update_succeeded) {
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() {
if (!enabled_)
return;
enabled_ = false;
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();
}
if (DatabaseAvailable()) {
closing_database_ = true;
safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this));
}
{
base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
safe_browsing_thread_->Stop();
safe_browsing_thread_.reset();
}
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(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(enabled_);
if (DatabaseAvailable())
return true;
safe_browsing_thread_->message_loop()->PostTask(
FROM_HERE,
base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase),
this));
return false;
}
SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
if (database_)
return database_;
startup_metric_utils::ScopedSlowStartupUMA
scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
const base::TimeTicks before = base::TimeTicks::Now();
SafeBrowsingDatabase* database =
SafeBrowsingDatabase::Create(enable_download_protection_,
enable_csd_whitelist_,
enable_download_whitelist_,
enable_extension_blacklist_,
enable_side_effect_free_whitelist_,
enable_ip_blacklist_);
database->Init(SafeBrowsingService::GetBaseFilename());
{
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(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_)
return;
DCHECK(checks_.find(check) != checks_.end());
if (check->client && check->need_get_hash) {
if (check->prefix_hits.size() == 1) {
SBPrefix prefix = check->prefix_hits[0];
GetHashRequests::iterator it = gethash_requests_.find(prefix);
if (it != gethash_requests_.end()) {
it->second.push_back(check);
return;
}
GetHashRequestors requestors;
requestors.push_back(check);
gethash_requests_[prefix] = requestors;
}
check->start = base::TimeTicks::Now();
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 {
HandleOneCheck(check, check->full_hits);
}
}
void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
GetChunksCallback callback) {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
bool database_error = true;
std::vector<SBListChunkRanges> lists;
DCHECK(!database_update_in_progress_);
database_update_in_progress_ = true;
GetDatabase();
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(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (enabled_)
callback.Run(lists, database_error);
}
void SafeBrowsingDatabaseManager::OnAddChunksComplete(
AddChunksCallback callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (enabled_)
callback.Run();
}
void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!enabled_)
return;
HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
if (queued_checks_.empty())
return;
DCHECK(DatabaseAvailable());
while (!queued_checks_.empty()) {
QueuedCheck check = queued_checks_.front();
DCHECK(!check.start.is_null());
HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start);
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, SBChunkList* chunks,
AddChunksCallback callback) {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
if (chunks) {
GetDatabase()->InsertChunks(list_name, *chunks);
delete chunks;
}
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this,
callback));
}
void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
std::vector<SBChunkDelete>* chunk_deletes) {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
if (chunk_deletes) {
GetDatabase()->DeleteChunks(*chunk_deletes);
delete chunk_deletes;
}
}
SBThreatType SafeBrowsingDatabaseManager::GetThreatTypeFromListname(
const std::string& list_name) {
if (safe_browsing_util::IsPhishingList(list_name)) {
return SB_THREAT_TYPE_URL_PHISHING;
}
if (safe_browsing_util::IsMalwareList(list_name)) {
return SB_THREAT_TYPE_URL_MALWARE;
}
if (safe_browsing_util::IsBadbinurlList(list_name)) {
return SB_THREAT_TYPE_BINARY_MALWARE_URL;
}
if (safe_browsing_util::IsExtensionList(list_name)) {
return SB_THREAT_TYPE_EXTENSION;
}
DVLOG(1) << "Unknown safe browsing list " << list_name;
return SB_THREAT_TYPE_SAFE;
}
void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
bool update_succeeded) {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
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_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
DCHECK(closing_database_);
delete database_;
database_ = NULL;
base::AutoLock lock(database_lock_);
closing_database_ = false;
}
void SafeBrowsingDatabaseManager::OnResetDatabase() {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
GetDatabase()->ResetDatabase();
}
void SafeBrowsingDatabaseManager::CacheHashResults(
const std::vector<SBPrefix>& prefixes,
const std::vector<SBFullHashResult>& full_hashes) {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
GetDatabase()->CacheHashResults(prefixes, full_hashes);
}
void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
SafeBrowsingCheck* check,
const std::vector<SBFullHashResult>& full_hashes) {
DCHECK(BrowserThread::CurrentlyOn(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;
}
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(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(check);
bool is_threat = false;
for (size_t i = 0; i < check->urls.size(); ++i) {
int index =
safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes);
if (index == -1)
continue;
SBThreatType threat =
GetThreatTypeFromListname(full_hashes[index].list_name);
if (threat != SB_THREAT_TYPE_SAFE &&
IsExpectedThreat(threat, check->expected_threats)) {
check->url_results[i] = threat;
is_threat = true;
}
}
for (size_t i = 0; i < check->full_hashes.size(); ++i) {
int index =
safe_browsing_util::GetHashIndex(check->full_hashes[i], full_hashes);
if (index == -1)
continue;
SBThreatType threat =
GetThreatTypeFromListname(full_hashes[index].list_name);
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::CheckDownloadUrlOnSBThread(
SafeBrowsingCheck* check) {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
DCHECK(enable_download_protection_);
std::vector<SBPrefix> prefix_hits;
if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this,
check));
return;
}
check->need_get_hash = true;
check->prefix_hits.clear();
check->prefix_hits = prefix_hits;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
}
void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
SafeBrowsingCheck* check) {
DCHECK_EQ(base::MessageLoop::current(),
safe_browsing_thread_->message_loop());
std::vector<SBPrefix> prefixes;
for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin();
it != check->full_hashes.end(); ++it) {
prefixes.push_back((*it).prefix);
}
database_->ContainsExtensionPrefixes(prefixes, &check->prefix_hits);
if (check->prefix_hits.empty()) {
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone, this,
check));
} else {
check->need_get_hash = true;
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
}
}
void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
DCHECK(BrowserThread::CurrentlyOn(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::CheckDownloadUrlDone(
SafeBrowsingCheck* check) {
DCHECK(enable_download_protection_);
SafeBrowsingCheckDone(check);
}
void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
SafeBrowsingCheck* check) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(check);
if (!enabled_)
return;
VLOG(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::Closure& task) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
check->timeout_factory_.reset(
new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this));
checks_.insert(check);
safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task);
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback,
check->timeout_factory_->GetWeakPtr(), check),
check_timeout_);
}