From 90a3b24080e8432726dde4b4f72821e49416180e Mon Sep 17 00:00:00 2001 From: "pkasting@chromium.org" Date: Fri, 13 Nov 2009 00:28:54 +0000 Subject: Minor cleanup to safe_browsing_service.*; no code change. * Eliminate header files that aren't needed * Eliminate function declarations that are never defined * Reorder header slightly for Google C++ Style Guide compliance and to make more functions private * Move above-function comments like "Called on IO thread" from definitions to declarations for added visibility * Reorder function definitions to match declaration order BUG=none TEST=none Review URL: http://codereview.chromium.org/391039 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@31863 0039d316-1c4b-4281-b951-d872f2087c98 --- .../browser/safe_browsing/safe_browsing_service.cc | 825 ++++++++++----------- 1 file changed, 404 insertions(+), 421 deletions(-) (limited to 'chrome/browser/safe_browsing/safe_browsing_service.cc') diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc index 164547e..3f2d7d8 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service.cc @@ -5,31 +5,25 @@ #include "chrome/browser/safe_browsing/safe_browsing_service.h" -#include "base/command_line.h" -#include "base/histogram.h" -#include "base/logging.h" -#include "base/message_loop.h" #include "base/path_service.h" #include "base/string_util.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chrome_thread.h" #include "chrome/browser/net/url_request_context_getter.h" #include "chrome/browser/profile_manager.h" #include "chrome/browser/safe_browsing/protocol_manager.h" #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h" #include "chrome/browser/safe_browsing/safe_browsing_database.h" -#include "chrome/browser/tab_contents/navigation_entry.h" #include "chrome/browser/tab_contents/tab_util.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/pref_names.h" -#include "chrome/common/pref_service.h" #include "chrome/common/url_constants.h" +#include "net/base/registry_controlled_domain.h" + #if defined(OS_WIN) #include "chrome/installer/util/browser_distribution.h" #endif -#include "net/base/registry_controlled_domain.h" using base::Time; using base::TimeDelta; @@ -50,10 +44,6 @@ SafeBrowsingService::SafeBrowsingService() update_in_progress_(false) { } -SafeBrowsingService::~SafeBrowsingService() { -} - -// Only called on the UI thread. void SafeBrowsingService::Initialize() { // Get the profile's preference for SafeBrowsing. PrefService* pref_service = GetDefaultProfile()->GetPrefs(); @@ -61,138 +51,12 @@ void SafeBrowsingService::Initialize() { Start(); } -// Start up SafeBrowsing objects. This can be called at browser start, or when -// the user checks the "Enable SafeBrowsing" option in the Advanced options UI. -void SafeBrowsingService::Start() { - DCHECK(!safe_browsing_thread_.get()); - safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread")); - if (!safe_browsing_thread_->Start()) - return; - - // Retrieve client MAC keys. - PrefService* local_state = g_browser_process->local_state(); - std::string client_key, wrapped_key; - if (local_state) { - client_key = - WideToASCII(local_state->GetString(prefs::kSafeBrowsingClientKey)); - wrapped_key = - WideToASCII(local_state->GetString(prefs::kSafeBrowsingWrappedKey)); - } - - // We will issue network fetches using the default profile's request context. - URLRequestContextGetter* request_context_getter = - GetDefaultProfile()->GetRequestContext(); - request_context_getter->AddRef(); // Balanced in OnIOInitialize. - - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod( - this, &SafeBrowsingService::OnIOInitialize, client_key, wrapped_key, - request_context_getter)); - - safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &SafeBrowsingService::OnDBInitialize)); -} - void SafeBrowsingService::ShutDown() { ChromeThread::PostTask( ChromeThread::IO, FROM_HERE, NewRunnableMethod(this, &SafeBrowsingService::OnIOShutdown)); } -void SafeBrowsingService::OnIOInitialize( - const std::string& client_key, - const std::string& wrapped_key, - URLRequestContextGetter* request_context_getter) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - enabled_ = true; - - // On Windows, get the safe browsing client name from the browser - // distribution classes in installer util. These classes don't yet have - // an analog on non-Windows builds so just keep the name specified here. -#if defined(OS_WIN) - BrowserDistribution* dist = BrowserDistribution::GetDistribution(); - std::string client_name(dist->GetSafeBrowsingName()); -#else -#if defined(GOOGLE_CHROME_BUILD) - std::string client_name("googlechrome"); -#else - std::string client_name("chromium"); -#endif -#endif - - protocol_manager_ = new SafeBrowsingProtocolManager(this, - client_name, - client_key, - wrapped_key, - request_context_getter); - - // Balance the reference added by Start(). - request_context_getter->Release(); - - // We want to initialize the protocol manager only after the database has - // loaded, which we'll receive asynchronously (DatabaseLoadComplete). If - // database_loaded_ isn't true, we'll wait for that notification to do the - // init. - if (database_loaded_) - protocol_manager_->Initialize(); -} - -void SafeBrowsingService::OnDBInitialize() { - DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - GetDatabase(); -} - -void SafeBrowsingService::OnIOShutdown() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - if (!enabled_) - return; - - enabled_ = false; - resetting_ = false; - - // This cancels all in-flight GetHash requests. - delete protocol_manager_; - protocol_manager_ = NULL; - - if (safe_browsing_thread_.get()) - safe_browsing_thread_->message_loop()->DeleteSoon(FROM_HERE, database_); - - // Flush the database thread. Any in-progress database check results will be - // ignored and cleaned up below. - safe_browsing_thread_.reset(NULL); - - database_ = NULL; - database_loaded_ = false; - - // Delete queued and pending checks once the database thread is done, calling - // back any clients with 'URL_SAFE'. - while (!queued_checks_.empty()) { - QueuedCheck check = queued_checks_.front(); - if (check.client) - check.client->OnUrlCheckResult(check.url, URL_SAFE); - queued_checks_.pop_front(); - } - - for (CurrentChecks::iterator it = checks_.begin(); - it != checks_.end(); ++it) { - if ((*it)->client) - (*it)->client->OnUrlCheckResult((*it)->url, URL_SAFE); - delete *it; - } - checks_.clear(); - - gethash_requests_.clear(); -} - -// Runs on the UI thread. -void SafeBrowsingService::OnEnable(bool enabled) { - if (enabled) - Start(); - else - ShutDown(); -} - bool SafeBrowsingService::CanCheckUrl(const GURL& url) const { return url.SchemeIs(chrome::kHttpScheme) || url.SchemeIs(chrome::kHttpsScheme); @@ -242,6 +106,25 @@ bool SafeBrowsingService::CheckUrl(const GURL& url, Client* client) { return false; } +void SafeBrowsingService::CancelCheck(Client* client) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + + for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) { + 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 or resetting. + if (!database_loaded_ || resetting_) { + std::deque::iterator it = queued_checks_.begin(); + for (; it != queued_checks_.end(); ++it) { + if (it->client == client) + it->client = NULL; + } + } +} + void SafeBrowsingService::DisplayBlockingPage(const GURL& url, ResourceType::Type resource_type, UrlCheckResult result, @@ -279,112 +162,205 @@ void SafeBrowsingService::DisplayBlockingPage(const GURL& url, this, &SafeBrowsingService::DoDisplayBlockingPage, resource)); } -// Invoked on the UI thread. -void SafeBrowsingService::DoDisplayBlockingPage( - const UnsafeResource& resource) { - // The tab might have been closed. - TabContents* wc = - tab_util::GetTabContentsByID(resource.render_process_host_id, - resource.render_view_id); - - if (!wc) { - // The tab is gone and we did not have a chance at showing the interstitial. - // Just act as "Don't Proceed" was chosen. - std::vector resources; - resources.push_back(resource); - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod( - this, &SafeBrowsingService::OnBlockingPageDone, resources, false)); +void SafeBrowsingService::HandleGetHashResults( + SafeBrowsingCheck* check, + const std::vector& full_hashes, + bool can_cache) { + if (checks_.find(check) == checks_.end()) return; - } - // Report the malware sub-resource to the SafeBrowsing servers if we have a - // malware sub-resource on a safe page and only if the user has opted in to - // reporting statistics. - PrefService* prefs = g_browser_process->local_state(); - DCHECK(prefs); - if (prefs && prefs->GetBoolean(prefs::kMetricsReportingEnabled) && - resource.resource_type != ResourceType::MAIN_FRAME && - resource.threat_type == SafeBrowsingService::URL_MALWARE) { - GURL page_url = wc->GetURL(); - GURL referrer_url; - NavigationEntry* entry = wc->controller().GetActiveEntry(); - if (entry) - referrer_url = entry->referrer(); - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod(this, - &SafeBrowsingService::ReportMalware, - resource.url, - page_url, - referrer_url)); - } + DCHECK(enabled_); - SafeBrowsingBlockingPage::ShowBlockingPage(this, resource); -} + UMA_HISTOGRAM_LONG_TIMES("SB2.Network", Time::Now() - check->start); -void SafeBrowsingService::CancelCheck(Client* client) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + std::vector prefixes = check->prefix_hits; + OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here. - for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) { - if ((*i)->client == client) - (*i)->client = NULL; + if (can_cache && database_) { + // Cache the GetHash results in memory: + database_->CacheHashResults(prefixes, full_hashes); } +} - // Scan the queued clients store. Clients may be here if they requested a URL - // check before the database has finished loading or resetting. - if (!database_loaded_ || resetting_) { - std::deque::iterator it = queued_checks_.begin(); - for (; it != queued_checks_.end(); ++it) { - if (it->client == client) - it->client = NULL; - } - } +void SafeBrowsingService::HandleChunk(const std::string& list, + std::deque* chunks) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(enabled_); + safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks)); } -void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) { +void SafeBrowsingService::HandleChunkDelete( + std::vector* chunk_deletes) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(enabled_); + safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SafeBrowsingService::DeleteChunks, chunk_deletes)); +} - // If we've been shutdown during the database lookup, this check will already - // have been deleted (in OnIOShutdown). - if (!enabled_ || checks_.find(check) == checks_.end()) - return; +void SafeBrowsingService::UpdateStarted() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(enabled_); + DCHECK(!update_in_progress_); + update_in_progress_ = true; + safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SafeBrowsingService::GetAllChunksFromDatabase)); +} - 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. +void SafeBrowsingService::UpdateFinished(bool update_succeeded) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(enabled_); + if (update_in_progress_) { + update_in_progress_ = false; + safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(this, + &SafeBrowsingService::DatabaseUpdateFinished, + update_succeeded)); + } +} - // 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; - } +void SafeBrowsingService::OnBlockingPageDone( + const std::vector& resources, + bool proceed) { + for (std::vector::const_iterator iter = resources.begin(); + iter != resources.end(); ++iter) { + const UnsafeResource& resource = *iter; + NotifyClientBlockingComplete(resource.client, proceed); - // No request in progress, so we're the first for this prefix. - GetHashRequestors requestors; - requestors.push_back(check); - gethash_requests_[prefix] = requestors; + if (proceed) { + // Whitelist this domain and warning type for the given tab. + WhiteListedEntry entry; + entry.render_process_host_id = resource.render_process_host_id; + entry.render_view_id = resource.render_view_id; + entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry( + resource.url); + entry.result = resource.threat_type; + white_listed_entries_.push_back(entry); } + } +} - // Reset the start time so that we can measure the network time without the - // database time. - check->start = Time::Now(); - protocol_manager_->GetFullHash(check, check->prefix_hits); - } else { - // We may have cached results for previous GetHash queries. - HandleOneCheck(check, check->full_hits); +void SafeBrowsingService::OnNewMacKeys(const std::string& client_key, + const std::string& wrapped_key) { + PrefService* prefs = g_browser_process->local_state(); + if (prefs) { + prefs->SetString(prefs::kSafeBrowsingClientKey, ASCIIToWide(client_key)); + prefs->SetString(prefs::kSafeBrowsingWrappedKey, ASCIIToWide(wrapped_key)); } } +void SafeBrowsingService::OnEnable(bool enabled) { + if (enabled) + Start(); + else + ShutDown(); +} + +// static +void SafeBrowsingService::RegisterPrefs(PrefService* prefs) { + prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, L""); + prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, L""); +} + +void SafeBrowsingService::ResetDatabase() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + resetting_ = true; + safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SafeBrowsingService::OnResetDatabase)); +} + +void SafeBrowsingService::LogPauseDelay(TimeDelta time) { + UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time); +} + +SafeBrowsingService::~SafeBrowsingService() { +} + +void SafeBrowsingService::OnIOInitialize( + const std::string& client_key, + const std::string& wrapped_key, + URLRequestContextGetter* request_context_getter) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + enabled_ = true; + + // On Windows, get the safe browsing client name from the browser + // distribution classes in installer util. These classes don't yet have + // an analog on non-Windows builds so just keep the name specified here. +#if defined(OS_WIN) + BrowserDistribution* dist = BrowserDistribution::GetDistribution(); + std::string client_name(dist->GetSafeBrowsingName()); +#else +#if defined(GOOGLE_CHROME_BUILD) + std::string client_name("googlechrome"); +#else + std::string client_name("chromium"); +#endif +#endif + + protocol_manager_ = new SafeBrowsingProtocolManager(this, + client_name, + client_key, + wrapped_key, + request_context_getter); + + // Balance the reference added by Start(). + request_context_getter->Release(); + + // We want to initialize the protocol manager only after the database has + // loaded, which we'll receive asynchronously (DatabaseLoadComplete). If + // database_loaded_ isn't true, we'll wait for that notification to do the + // init. + if (database_loaded_) + protocol_manager_->Initialize(); +} + +void SafeBrowsingService::OnDBInitialize() { + DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + GetDatabase(); +} + +void SafeBrowsingService::OnIOShutdown() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (!enabled_) + return; + + enabled_ = false; + resetting_ = false; + + // This cancels all in-flight GetHash requests. + delete protocol_manager_; + protocol_manager_ = NULL; + + if (safe_browsing_thread_.get()) + safe_browsing_thread_->message_loop()->DeleteSoon(FROM_HERE, database_); + + // Flush the database thread. Any in-progress database check results will be + // ignored and cleaned up below. + safe_browsing_thread_.reset(NULL); + + database_ = NULL; + database_loaded_ = false; + + // Delete queued and pending checks once the database thread is done, calling + // back any clients with 'URL_SAFE'. + while (!queued_checks_.empty()) { + QueuedCheck check = queued_checks_.front(); + if (check.client) + check.client->OnUrlCheckResult(check.url, URL_SAFE); + queued_checks_.pop_front(); + } + + for (CurrentChecks::iterator it = checks_.begin(); + it != checks_.end(); ++it) { + if ((*it)->client) + (*it)->client->OnUrlCheckResult((*it)->url, URL_SAFE); + delete *it; + } + checks_.clear(); + + gethash_requests_.clear(); +} + SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() { DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); if (database_) @@ -413,134 +389,73 @@ SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() { return database_; } -// Public API called only on the IO thread. -// The SafeBrowsingProtocolManager has received the full hash results for -// prefix hits detected in the database. -void SafeBrowsingService::HandleGetHashResults( - SafeBrowsingCheck* check, - const std::vector& full_hashes, - bool can_cache) { - if (checks_.find(check) == checks_.end()) - return; - - DCHECK(enabled_); - - UMA_HISTOGRAM_LONG_TIMES("SB2.Network", Time::Now() - check->start); - - std::vector prefixes = check->prefix_hits; - OnHandleGetHashResults(check, full_hashes); // 'check' is deleted here. - - if (can_cache && database_) { - // Cache the GetHash results in memory: - database_->CacheHashResults(prefixes, full_hashes); - } -} +void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); -void SafeBrowsingService::OnHandleGetHashResults( - SafeBrowsingCheck* check, - const std::vector& full_hashes) { - SBPrefix prefix = check->prefix_hits[0]; - GetHashRequests::iterator it = gethash_requests_.find(prefix); - if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { - HandleOneCheck(check, full_hashes); + // If we've been shutdown during the database lookup, this check will already + // have been deleted (in OnIOShutdown). + if (!enabled_ || checks_.find(check) == checks_.end()) return; - } - // Call back all interested parties. - GetHashRequestors& requestors = it->second; - for (GetHashRequestors::iterator r = requestors.begin(); - r != requestors.end(); ++r) { - HandleOneCheck(*r, full_hashes); - } + 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. - gethash_requests_.erase(it); -} + // 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; + } -void SafeBrowsingService::HandleOneCheck( - SafeBrowsingCheck* check, - const std::vector& full_hashes) { - if (check->client) { - UrlCheckResult result = URL_SAFE; - int index = safe_browsing_util::CompareFullHashes(check->url, full_hashes); - if (index != -1) { - result = GetResultFromListname(full_hashes[index].list_name); - } else { - // Log the case where the SafeBrowsing servers return full hashes in the - // GetHash response that match the prefix we're looking up, but don't - // match the full hash of the URL. - if (!full_hashes.empty()) - UMA_HISTOGRAM_COUNTS("SB2.GetHashServerMiss", 1); + // No request in progress, so we're the first for this prefix. + GetHashRequestors requestors; + requestors.push_back(check); + gethash_requests_[prefix] = requestors; } - // Let the client continue handling the original request. - check->client->OnUrlCheckResult(check->url, result); - } - - checks_.erase(check); - delete check; -} - -void SafeBrowsingService::UpdateStarted() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DCHECK(enabled_); - DCHECK(!update_in_progress_); - update_in_progress_ = true; - safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &SafeBrowsingService::GetAllChunksFromDatabase)); -} - -void SafeBrowsingService::UpdateFinished(bool update_succeeded) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DCHECK(enabled_); - if (update_in_progress_) { - update_in_progress_ = false; - safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, - NewRunnableMethod(this, - &SafeBrowsingService::DatabaseUpdateFinished, - update_succeeded)); + // Reset the start time so that we can measure the network time without the + // database time. + check->start = Time::Now(); + protocol_manager_->GetFullHash(check, check->prefix_hits); + } else { + // We may have cached results for previous GetHash queries. + HandleOneCheck(check, check->full_hits); } } -void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) { +void SafeBrowsingService::GetAllChunksFromDatabase() { DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - if (GetDatabase()) - GetDatabase()->UpdateFinished(update_succeeded); -} - -void SafeBrowsingService::OnBlockingPageDone( - const std::vector& resources, - bool proceed) { - for (std::vector::const_iterator iter = resources.begin(); - iter != resources.end(); ++iter) { - const UnsafeResource& resource = *iter; - NotifyClientBlockingComplete(resource.client, proceed); - - if (proceed) { - // Whitelist this domain and warning type for the given tab. - WhiteListedEntry entry; - entry.render_process_host_id = resource.render_process_host_id; - entry.render_view_id = resource.render_view_id; - entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry( - resource.url); - entry.result = resource.threat_type; - white_listed_entries_.push_back(entry); + bool database_error = true; + std::vector lists; + if (GetDatabase()) { + if (GetDatabase()->UpdateStarted()) { + GetDatabase()->GetListsInfo(&lists); + database_error = false; + } else { + GetDatabase()->UpdateFinished(false); } } -} -void SafeBrowsingService::NotifyClientBlockingComplete(Client* client, - bool proceed) { - client->OnBlockingPageComplete(proceed); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists, + database_error)); } -// This method runs on the UI loop to access the prefs. -void SafeBrowsingService::OnNewMacKeys(const std::string& client_key, - const std::string& wrapped_key) { - PrefService* prefs = g_browser_process->local_state(); - if (prefs) { - prefs->SetString(prefs::kSafeBrowsingClientKey, ASCIIToWide(client_key)); - prefs->SetString(prefs::kSafeBrowsingWrappedKey, ASCIIToWide(wrapped_key)); - } +void SafeBrowsingService::OnGetAllChunksFromDatabase( + const std::vector& lists, bool database_error) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (enabled_) + protocol_manager_->OnGetChunksComplete(lists, database_error); } void SafeBrowsingService::ChunkInserted() { @@ -571,17 +486,75 @@ void SafeBrowsingService::DatabaseLoadComplete() { RunQueuedClients(); } -// static -void SafeBrowsingService::RegisterPrefs(PrefService* prefs) { - prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, L""); - prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, L""); +void SafeBrowsingService::HandleChunkForDatabase( + const std::string& list_name, + std::deque* chunks) { + DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + + GetDatabase()->InsertChunks(list_name, chunks); } -void SafeBrowsingService::ResetDatabase() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - resetting_ = true; +void SafeBrowsingService::DeleteChunks( + std::vector* chunk_deletes) { + DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + + GetDatabase()->DeleteChunks(chunk_deletes); +} + +SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname( + const std::string& list_name) { + if (safe_browsing_util::IsPhishingList(list_name)) { + return URL_PHISHING; + } + + if (safe_browsing_util::IsMalwareList(list_name)) { + return URL_MALWARE; + } + + SB_DLOG(INFO) << "Unknown safe browsing list " << list_name; + return URL_SAFE; +} + +void SafeBrowsingService::NotifyClientBlockingComplete(Client* client, + bool proceed) { + client->OnBlockingPageComplete(proceed); +} + +void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) { + DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + if (GetDatabase()) + GetDatabase()->UpdateFinished(update_succeeded); +} + +void SafeBrowsingService::Start() { + DCHECK(!safe_browsing_thread_.get()); + safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread")); + if (!safe_browsing_thread_->Start()) + return; + + // Retrieve client MAC keys. + PrefService* local_state = g_browser_process->local_state(); + std::string client_key, wrapped_key; + if (local_state) { + client_key = + WideToASCII(local_state->GetString(prefs::kSafeBrowsingClientKey)); + wrapped_key = + WideToASCII(local_state->GetString(prefs::kSafeBrowsingWrappedKey)); + } + + // We will issue network fetches using the default profile's request context. + URLRequestContextGetter* request_context_getter = + GetDefaultProfile()->GetRequestContext(); + request_context_getter->AddRef(); // Balanced in OnIOInitialize. + + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + this, &SafeBrowsingService::OnIOInitialize, client_key, wrapped_key, + request_context_getter)); + safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &SafeBrowsingService::OnResetDatabase)); + this, &SafeBrowsingService::OnDBInitialize)); } void SafeBrowsingService::OnResetDatabase() { @@ -601,100 +574,99 @@ void SafeBrowsingService::OnResetComplete() { } } -void SafeBrowsingService::HandleChunk(const std::string& list, - std::deque* chunks) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DCHECK(enabled_); - safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks)); -} - -void SafeBrowsingService::HandleChunkForDatabase( - const std::string& list_name, - std::deque* chunks) { +void SafeBrowsingService::CacheHashResults( + const std::vector& prefixes, + const std::vector& full_hashes) { DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - - GetDatabase()->InsertChunks(list_name, chunks); + GetDatabase()->CacheHashResults(prefixes, full_hashes); } -void SafeBrowsingService::HandleChunkDelete( - std::vector* chunk_deletes) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DCHECK(enabled_); - safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &SafeBrowsingService::DeleteChunks, chunk_deletes)); -} +void SafeBrowsingService::OnHandleGetHashResults( + SafeBrowsingCheck* check, + const std::vector& full_hashes) { + SBPrefix prefix = check->prefix_hits[0]; + GetHashRequests::iterator it = gethash_requests_.find(prefix); + if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) { + HandleOneCheck(check, full_hashes); + return; + } -void SafeBrowsingService::DeleteChunks( - std::vector* chunk_deletes) { - DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + // Call back all interested parties. + GetHashRequestors& requestors = it->second; + for (GetHashRequestors::iterator r = requestors.begin(); + r != requestors.end(); ++r) { + HandleOneCheck(*r, full_hashes); + } - GetDatabase()->DeleteChunks(chunk_deletes); + gethash_requests_.erase(it); } -// Database worker function. -void SafeBrowsingService::GetAllChunksFromDatabase() { - DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - bool database_error = true; - std::vector lists; - if (GetDatabase()) { - if (GetDatabase()->UpdateStarted()) { - GetDatabase()->GetListsInfo(&lists); - database_error = false; +void SafeBrowsingService::HandleOneCheck( + SafeBrowsingCheck* check, + const std::vector& full_hashes) { + if (check->client) { + UrlCheckResult result = URL_SAFE; + int index = safe_browsing_util::CompareFullHashes(check->url, full_hashes); + if (index != -1) { + result = GetResultFromListname(full_hashes[index].list_name); } else { - GetDatabase()->UpdateFinished(false); + // Log the case where the SafeBrowsing servers return full hashes in the + // GetHash response that match the prefix we're looking up, but don't + // match the full hash of the URL. + if (!full_hashes.empty()) + UMA_HISTOGRAM_COUNTS("SB2.GetHashServerMiss", 1); } + + // Let the client continue handling the original request. + check->client->OnUrlCheckResult(check->url, result); } - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod( - this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists, - database_error)); + checks_.erase(check); + delete check; } -// Called on the io thread with the results of all chunks. -void SafeBrowsingService::OnGetAllChunksFromDatabase( - const std::vector& lists, bool database_error) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - if (enabled_) - protocol_manager_->OnGetChunksComplete(lists, database_error); -} +void SafeBrowsingService::DoDisplayBlockingPage( + const UnsafeResource& resource) { + // The tab might have been closed. + TabContents* wc = + tab_util::GetTabContentsByID(resource.render_process_host_id, + resource.render_view_id); -SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname( - const std::string& list_name) { - if (safe_browsing_util::IsPhishingList(list_name)) { - return URL_PHISHING; + if (!wc) { + // The tab is gone and we did not have a chance at showing the interstitial. + // Just act as "Don't Proceed" was chosen. + std::vector resources; + resources.push_back(resource); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + this, &SafeBrowsingService::OnBlockingPageDone, resources, false)); + return; } - if (safe_browsing_util::IsMalwareList(list_name)) { - return URL_MALWARE; + // Report the malware sub-resource to the SafeBrowsing servers if we have a + // malware sub-resource on a safe page and only if the user has opted in to + // reporting statistics. + PrefService* prefs = g_browser_process->local_state(); + DCHECK(prefs); + if (prefs && prefs->GetBoolean(prefs::kMetricsReportingEnabled) && + resource.resource_type != ResourceType::MAIN_FRAME && + resource.threat_type == SafeBrowsingService::URL_MALWARE) { + GURL page_url = wc->GetURL(); + GURL referrer_url; + NavigationEntry* entry = wc->controller().GetActiveEntry(); + if (entry) + referrer_url = entry->referrer(); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, + &SafeBrowsingService::ReportMalware, + resource.url, + page_url, + referrer_url)); } - SB_DLOG(INFO) << "Unknown safe browsing list " << list_name; - return URL_SAFE; -} - -void SafeBrowsingService::LogPauseDelay(TimeDelta time) { - UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time); -} - -void SafeBrowsingService::CacheHashResults( - const std::vector& prefixes, - const std::vector& full_hashes) { - DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - GetDatabase()->CacheHashResults(prefixes, full_hashes); -} - -void SafeBrowsingService::RunQueuedClients() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size()); - while (!queued_checks_.empty()) { - QueuedCheck check = queued_checks_.front(); - HISTOGRAM_TIMES("SB.QueueDelay", Time::Now() - check.start); - CheckUrl(check.url, check.client); - queued_checks_.pop_front(); - } + SafeBrowsingBlockingPage::ShowBlockingPage(this, resource); } void SafeBrowsingService::ReportMalware(const GURL& malware_url, @@ -716,3 +688,14 @@ void SafeBrowsingService::ReportMalware(const GURL& malware_url, if (full_hits.empty()) protocol_manager_->ReportMalware(malware_url, page_url, referrer_url); } + +void SafeBrowsingService::RunQueuedClients() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size()); + while (!queued_checks_.empty()) { + QueuedCheck check = queued_checks_.front(); + HISTOGRAM_TIMES("SB.QueueDelay", Time::Now() - check.start); + CheckUrl(check.url, check.client); + queued_checks_.pop_front(); + } +} -- cgit v1.1