diff options
author | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-13 00:28:54 +0000 |
---|---|---|
committer | pkasting@chromium.org <pkasting@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-11-13 00:28:54 +0000 |
commit | 90a3b24080e8432726dde4b4f72821e49416180e (patch) | |
tree | 0fd94921b79a9452b78eef78ceb0e01bb152ca51 /chrome/browser/safe_browsing/safe_browsing_service.cc | |
parent | 9eda5b7490cb3463435287b003058d6d486a83b3 (diff) | |
download | chromium_src-90a3b24080e8432726dde4b4f72821e49416180e.zip chromium_src-90a3b24080e8432726dde4b4f72821e49416180e.tar.gz chromium_src-90a3b24080e8432726dde4b4f72821e49416180e.tar.bz2 |
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
Diffstat (limited to 'chrome/browser/safe_browsing/safe_browsing_service.cc')
-rw-r--r-- | chrome/browser/safe_browsing/safe_browsing_service.cc | 775 |
1 files changed, 379 insertions, 396 deletions
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<QueuedCheck>::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,143 +162,6 @@ 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<UnsafeResource> resources; - resources.push_back(resource); - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod( - this, &SafeBrowsingService::OnBlockingPageDone, resources, false)); - 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)); - } - - SafeBrowsingBlockingPage::ShowBlockingPage(this, resource); -} - -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<QueuedCheck>::iterator it = queued_checks_.begin(); - for (; it != queued_checks_.end(); ++it) { - if (it->client == client) - it->client = NULL; - } - } -} - -void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - - // 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; - - 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 = Time::Now(); - protocol_manager_->GetFullHash(check, check->prefix_hits); - } else { - // We may have cached results for previous GetHash queries. - HandleOneCheck(check, check->full_hits); - } -} - -SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() { - DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - if (database_) - return database_; - - FilePath path; - bool result = PathService::Get(chrome::DIR_USER_DATA, &path); - DCHECK(result); - path = path.Append(chrome::kSafeBrowsingFilename); - - Time before = Time::Now(); - SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create(); - Callback0::Type* chunk_callback = - NewCallback(this, &SafeBrowsingService::ChunkInserted); - database->Init(path, chunk_callback); - database_ = database; - - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod(this, &SafeBrowsingService::DatabaseLoadComplete)); - - TimeDelta open_time = Time::Now() - before; - SB_DLOG(INFO) << "SafeBrowsing database open took " << - open_time.InMilliseconds() << " ms."; - - 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<SBFullHashResult>& full_hashes, @@ -436,48 +182,20 @@ void SafeBrowsingService::HandleGetHashResults( } } -void SafeBrowsingService::OnHandleGetHashResults( - SafeBrowsingCheck* check, - const std::vector<SBFullHashResult>& 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; - } - - // Call back all interested parties. - GetHashRequestors& requestors = it->second; - for (GetHashRequestors::iterator r = requestors.begin(); - r != requestors.end(); ++r) { - HandleOneCheck(*r, full_hashes); - } - - gethash_requests_.erase(it); +void SafeBrowsingService::HandleChunk(const std::string& list, + std::deque<SBChunk>* chunks) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + DCHECK(enabled_); + safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks)); } -void SafeBrowsingService::HandleOneCheck( - SafeBrowsingCheck* check, - const std::vector<SBFullHashResult>& 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); - } - - // Let the client continue handling the original request. - check->client->OnUrlCheckResult(check->url, result); - } - - checks_.erase(check); - delete check; +void SafeBrowsingService::HandleChunkDelete( + std::vector<SBChunkDelete>* 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::UpdateStarted() { @@ -501,12 +219,6 @@ void SafeBrowsingService::UpdateFinished(bool update_succeeded) { } } -void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) { - DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - if (GetDatabase()) - GetDatabase()->UpdateFinished(update_succeeded); -} - void SafeBrowsingService::OnBlockingPageDone( const std::vector<UnsafeResource>& resources, bool proceed) { @@ -528,12 +240,6 @@ void SafeBrowsingService::OnBlockingPageDone( } } -void SafeBrowsingService::NotifyClientBlockingComplete(Client* client, - bool proceed) { - client->OnBlockingPageComplete(proceed); -} - -// 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(); @@ -543,32 +249,11 @@ void SafeBrowsingService::OnNewMacKeys(const std::string& client_key, } } -void SafeBrowsingService::ChunkInserted() { - DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod(this, &SafeBrowsingService::OnChunkInserted)); -} - -void SafeBrowsingService::OnChunkInserted() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - if (enabled_) - protocol_manager_->OnChunkInserted(); -} - -void SafeBrowsingService::DatabaseLoadComplete() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - if (!enabled_) - return; - - database_loaded_ = true; - - if (protocol_manager_) - protocol_manager_->Initialize(); - - // If we have any queued requests, we can now check them. - if (!resetting_) - RunQueuedClients(); +void SafeBrowsingService::OnEnable(bool enabled) { + if (enabled) + Start(); + else + ShutDown(); } // static @@ -584,55 +269,168 @@ void SafeBrowsingService::ResetDatabase() { this, &SafeBrowsingService::OnResetDatabase)); } -void SafeBrowsingService::OnResetDatabase() { - DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - GetDatabase()->ResetDatabase(); - ChromeThread::PostTask( - ChromeThread::IO, FROM_HERE, - NewRunnableMethod(this, &SafeBrowsingService::OnResetComplete)); +void SafeBrowsingService::LogPauseDelay(TimeDelta time) { + UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time); } -void SafeBrowsingService::OnResetComplete() { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - if (enabled_) { - resetting_ = false; - database_loaded_ = true; - RunQueuedClients(); - } +SafeBrowsingService::~SafeBrowsingService() { } -void SafeBrowsingService::HandleChunk(const std::string& list, - std::deque<SBChunk>* chunks) { +void SafeBrowsingService::OnIOInitialize( + const std::string& client_key, + const std::string& wrapped_key, + URLRequestContextGetter* request_context_getter) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DCHECK(enabled_); - safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks)); + 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::HandleChunkForDatabase( - const std::string& list_name, - std::deque<SBChunk>* chunks) { +void SafeBrowsingService::OnDBInitialize() { DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); - - GetDatabase()->InsertChunks(list_name, chunks); + GetDatabase(); } -void SafeBrowsingService::HandleChunkDelete( - std::vector<SBChunkDelete>* chunk_deletes) { +void SafeBrowsingService::OnIOShutdown() { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); - DCHECK(enabled_); - safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod( - this, &SafeBrowsingService::DeleteChunks, chunk_deletes)); + 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(); } -void SafeBrowsingService::DeleteChunks( - std::vector<SBChunkDelete>* chunk_deletes) { +SafeBrowsingDatabase* SafeBrowsingService::GetDatabase() { DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + if (database_) + return database_; - GetDatabase()->DeleteChunks(chunk_deletes); + FilePath path; + bool result = PathService::Get(chrome::DIR_USER_DATA, &path); + DCHECK(result); + path = path.Append(chrome::kSafeBrowsingFilename); + + Time before = Time::Now(); + SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create(); + Callback0::Type* chunk_callback = + NewCallback(this, &SafeBrowsingService::ChunkInserted); + database->Init(path, chunk_callback); + database_ = database; + + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &SafeBrowsingService::DatabaseLoadComplete)); + + TimeDelta open_time = Time::Now() - before; + SB_DLOG(INFO) << "SafeBrowsing database open took " << + open_time.InMilliseconds() << " ms."; + + return database_; +} + +void SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + + // 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; + + 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 = Time::Now(); + protocol_manager_->GetFullHash(check, check->prefix_hits); + } else { + // We may have cached results for previous GetHash queries. + HandleOneCheck(check, check->full_hits); + } } -// Database worker function. void SafeBrowsingService::GetAllChunksFromDatabase() { DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); bool database_error = true; @@ -653,7 +451,6 @@ void SafeBrowsingService::GetAllChunksFromDatabase() { database_error)); } -// Called on the io thread with the results of all chunks. void SafeBrowsingService::OnGetAllChunksFromDatabase( const std::vector<SBListChunkRanges>& lists, bool database_error) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); @@ -661,6 +458,49 @@ void SafeBrowsingService::OnGetAllChunksFromDatabase( protocol_manager_->OnGetChunksComplete(lists, database_error); } +void SafeBrowsingService::ChunkInserted() { + DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &SafeBrowsingService::OnChunkInserted)); +} + +void SafeBrowsingService::OnChunkInserted() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (enabled_) + protocol_manager_->OnChunkInserted(); +} + +void SafeBrowsingService::DatabaseLoadComplete() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (!enabled_) + return; + + database_loaded_ = true; + + if (protocol_manager_) + protocol_manager_->Initialize(); + + // If we have any queued requests, we can now check them. + if (!resetting_) + RunQueuedClients(); +} + +void SafeBrowsingService::HandleChunkForDatabase( + const std::string& list_name, + std::deque<SBChunk>* chunks) { + DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + + GetDatabase()->InsertChunks(list_name, chunks); +} + +void SafeBrowsingService::DeleteChunks( + std::vector<SBChunkDelete>* 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)) { @@ -675,8 +515,63 @@ SafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname( return URL_SAFE; } -void SafeBrowsingService::LogPauseDelay(TimeDelta time) { - UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time); +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::OnDBInitialize)); +} + +void SafeBrowsingService::OnResetDatabase() { + DCHECK(MessageLoop::current() == safe_browsing_thread_->message_loop()); + GetDatabase()->ResetDatabase(); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod(this, &SafeBrowsingService::OnResetComplete)); +} + +void SafeBrowsingService::OnResetComplete() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + if (enabled_) { + resetting_ = false; + database_loaded_ = true; + RunQueuedClients(); + } } void SafeBrowsingService::CacheHashResults( @@ -686,15 +581,92 @@ void SafeBrowsingService::CacheHashResults( 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(); +void SafeBrowsingService::OnHandleGetHashResults( + SafeBrowsingCheck* check, + const std::vector<SBFullHashResult>& 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; + } + + // Call back all interested parties. + GetHashRequestors& requestors = it->second; + for (GetHashRequestors::iterator r = requestors.begin(); + r != requestors.end(); ++r) { + HandleOneCheck(*r, full_hashes); + } + + gethash_requests_.erase(it); +} + +void SafeBrowsingService::HandleOneCheck( + SafeBrowsingCheck* check, + const std::vector<SBFullHashResult>& 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); + } + + // Let the client continue handling the original request. + check->client->OnUrlCheckResult(check->url, result); + } + + checks_.erase(check); + delete check; +} + +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<UnsafeResource> resources; + resources.push_back(resource); + ChromeThread::PostTask( + ChromeThread::IO, FROM_HERE, + NewRunnableMethod( + this, &SafeBrowsingService::OnBlockingPageDone, resources, false)); + 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)); + } + + 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(); + } +} |