Home | History | Annotate | Download | only in safe_browsing
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/safe_browsing/database_manager.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/callback.h"
     12 #include "base/command_line.h"
     13 #include "base/debug/leak_tracker.h"
     14 #include "base/path_service.h"
     15 #include "base/stl_util.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/threading/thread.h"
     18 #include "base/threading/thread_restrictions.h"
     19 #include "chrome/browser/browser_process.h"
     20 #include "chrome/browser/chrome_notification_types.h"
     21 #include "chrome/browser/metrics/metrics_service.h"
     22 #include "chrome/browser/prerender/prerender_field_trial.h"
     23 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
     24 #include "chrome/browser/safe_browsing/download_protection_service.h"
     25 #include "chrome/browser/safe_browsing/malware_details.h"
     26 #include "chrome/browser/safe_browsing/protocol_manager.h"
     27 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
     28 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
     29 #include "chrome/browser/safe_browsing/ui_manager.h"
     30 #include "chrome/common/chrome_constants.h"
     31 #include "chrome/common/chrome_paths.h"
     32 #include "chrome/common/chrome_switches.h"
     33 #include "chrome/common/startup_metric_utils.h"
     34 #include "chrome/common/url_constants.h"
     35 #include "content/public/browser/browser_thread.h"
     36 #include "content/public/browser/notification_service.h"
     37 
     38 using content::BrowserThread;
     39 
     40 namespace {
     41 
     42 // Timeout for match checks, e.g. download URLs, hashes.
     43 const int kCheckTimeoutMs = 10000;
     44 
     45 // Records disposition information about the check.  |hit| should be
     46 // |true| if there were any prefix hits in |full_hashes|.
     47 void RecordGetHashCheckStatus(
     48     bool hit,
     49     safe_browsing_util::ListType check_type,
     50     const std::vector<SBFullHashResult>& full_hashes) {
     51   SafeBrowsingProtocolManager::ResultType result;
     52   if (full_hashes.empty()) {
     53     result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
     54   } else if (hit) {
     55     result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
     56   } else {
     57     result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
     58   }
     59   bool is_download = check_type == safe_browsing_util::BINURL ||
     60                      check_type == safe_browsing_util::BINHASH;
     61   SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
     62 }
     63 
     64 }  // namespace
     65 
     66 SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
     67     const std::vector<GURL>& urls,
     68     const std::vector<SBFullHash>& full_hashes,
     69     Client* client,
     70     safe_browsing_util::ListType check_type)
     71     : urls(urls),
     72       url_results(urls.size(), SB_THREAT_TYPE_SAFE),
     73       full_hashes(full_hashes),
     74       full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE),
     75       client(client),
     76       need_get_hash(false),
     77       check_type(check_type) {
     78   DCHECK_EQ(urls.empty(), !full_hashes.empty())
     79       << "Exactly one of urls and full_hashes must be set";
     80 }
     81 
     82 SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
     83 
     84 void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
     85     const SafeBrowsingCheck& check) {
     86   DCHECK_EQ(check.urls.size(), check.url_results.size());
     87   DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size());
     88   if (!check.urls.empty()) {
     89     DCHECK(check.full_hashes.empty());
     90     switch (check.check_type) {
     91       case safe_browsing_util::MALWARE:
     92       case safe_browsing_util::PHISH:
     93         DCHECK_EQ(1u, check.urls.size());
     94         OnCheckBrowseUrlResult(check.urls[0], check.url_results[0]);
     95         break;
     96       case safe_browsing_util::BINURL:
     97         DCHECK_EQ(check.urls.size(), check.url_results.size());
     98         OnCheckDownloadUrlResult(
     99             check.urls,
    100             *std::max_element(check.url_results.begin(),
    101                               check.url_results.end()));
    102         break;
    103       default:
    104         NOTREACHED();
    105     }
    106   } else if (!check.full_hashes.empty()) {
    107     switch (check.check_type) {
    108       case safe_browsing_util::BINHASH:
    109         DCHECK_EQ(1u, check.full_hashes.size());
    110         OnCheckDownloadHashResult(
    111             safe_browsing_util::SBFullHashToString(check.full_hashes[0]),
    112             check.full_hash_results[0]);
    113         break;
    114       case safe_browsing_util::EXTENSIONBLACKLIST: {
    115         std::set<std::string> unsafe_extension_ids;
    116         for (size_t i = 0; i < check.full_hashes.size(); ++i) {
    117           std::string extension_id =
    118               safe_browsing_util::SBFullHashToString(check.full_hashes[i]);
    119           if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION)
    120             unsafe_extension_ids.insert(extension_id);
    121         }
    122         OnCheckExtensionsResult(unsafe_extension_ids);
    123         break;
    124       }
    125       default:
    126         NOTREACHED();
    127     }
    128   } else {
    129     NOTREACHED();
    130   }
    131 }
    132 
    133 SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
    134     const scoped_refptr<SafeBrowsingService>& service)
    135     : sb_service_(service),
    136       database_(NULL),
    137       enabled_(false),
    138       enable_download_protection_(false),
    139       enable_csd_whitelist_(false),
    140       enable_download_whitelist_(false),
    141       enable_extension_blacklist_(false),
    142       enable_side_effect_free_whitelist_(false),
    143       update_in_progress_(false),
    144       database_update_in_progress_(false),
    145       closing_database_(false),
    146       check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) {
    147   DCHECK(sb_service_.get() != NULL);
    148 
    149   CommandLine* cmdline = CommandLine::ForCurrentProcess();
    150   enable_download_protection_ =
    151       !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
    152 
    153   // We only download the csd-whitelist if client-side phishing detection is
    154   // enabled.
    155   enable_csd_whitelist_ =
    156       !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection);
    157 
    158   // TODO(noelutz): remove this boolean variable since it should always be true
    159   // if SafeBrowsing is enabled.  Unfortunately, we have no test data for this
    160   // list right now.  This means that we need to be able to disable this list
    161   // for the SafeBrowsing test to pass.
    162   enable_download_whitelist_ = enable_csd_whitelist_;
    163 
    164   // TODO(kalman): there really shouldn't be a flag for this.
    165   enable_extension_blacklist_ =
    166       !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
    167 
    168   enable_side_effect_free_whitelist_ =
    169       prerender::IsSideEffectFreeWhitelistEnabled() &&
    170       !cmdline->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist);
    171 
    172   enum SideEffectFreeWhitelistStatus {
    173     SIDE_EFFECT_FREE_WHITELIST_ENABLED,
    174     SIDE_EFFECT_FREE_WHITELIST_DISABLED,
    175     SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
    176   };
    177 
    178   SideEffectFreeWhitelistStatus side_effect_free_whitelist_status =
    179       enable_side_effect_free_whitelist_ ? SIDE_EFFECT_FREE_WHITELIST_ENABLED :
    180       SIDE_EFFECT_FREE_WHITELIST_DISABLED;
    181 
    182   UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
    183                             side_effect_free_whitelist_status,
    184                             SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX);
    185 }
    186 
    187 SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
    188   // We should have already been shut down. If we're still enabled, then the
    189   // database isn't going to be closed properly, which could lead to corruption.
    190   DCHECK(!enabled_);
    191 }
    192 
    193 bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
    194   return url.SchemeIs(chrome::kFtpScheme) ||
    195          url.SchemeIs(chrome::kHttpScheme) ||
    196          url.SchemeIs(chrome::kHttpsScheme);
    197 }
    198 
    199 bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
    200     const std::vector<GURL>& url_chain,
    201     Client* client) {
    202   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    203   if (!enabled_ || !enable_download_protection_)
    204     return true;
    205 
    206   // We need to check the database for url prefix, and later may fetch the url
    207   // from the safebrowsing backends. These need to be asynchronous.
    208   SafeBrowsingCheck* check = new SafeBrowsingCheck(url_chain,
    209                                                    std::vector<SBFullHash>(),
    210                                                    client,
    211                                                    safe_browsing_util::BINURL);
    212   StartSafeBrowsingCheck(
    213       check,
    214       base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this,
    215                  check));
    216   return false;
    217 }
    218 
    219 bool SafeBrowsingDatabaseManager::CheckDownloadHash(
    220     const std::string& full_hash,
    221     Client* client) {
    222   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    223   DCHECK(!full_hash.empty());
    224   if (!enabled_ || !enable_download_protection_ || full_hash.empty())
    225     return true;
    226 
    227   // We need to check the database for url prefix, and later may fetch the url
    228   // from the safebrowsing backends. These need to be asynchronous.
    229   std::vector<SBFullHash> full_hashes(
    230       1, safe_browsing_util::StringToSBFullHash(full_hash));
    231   SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(),
    232                                                    full_hashes,
    233                                                    client,
    234                                                    safe_browsing_util::BINHASH);
    235   StartSafeBrowsingCheck(
    236       check,
    237       base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread,this,
    238                  check));
    239   return false;
    240 }
    241 
    242 bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
    243     const std::set<std::string>& extension_ids,
    244     Client* client) {
    245   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    246 
    247   if (!enabled_ || !enable_extension_blacklist_)
    248     return true;
    249 
    250   std::vector<SBFullHash> extension_id_hashes;
    251   std::transform(extension_ids.begin(), extension_ids.end(),
    252                  std::back_inserter(extension_id_hashes),
    253                  safe_browsing_util::StringToSBFullHash);
    254 
    255   SafeBrowsingCheck* check = new SafeBrowsingCheck(
    256       std::vector<GURL>(),
    257       extension_id_hashes,
    258       client,
    259       safe_browsing_util::EXTENSIONBLACKLIST);
    260 
    261   StartSafeBrowsingCheck(
    262       check,
    263       base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread,
    264                  this,
    265                  check));
    266   return false;
    267 }
    268 
    269 bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
    270     const GURL& url) {
    271   if (!enabled_)
    272     return false;
    273 
    274   if (!CanCheckUrl(url))
    275     return false;
    276 
    277   return database_->ContainsSideEffectFreeWhitelistUrl(url);
    278 }
    279 
    280 bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
    281   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    282   if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
    283     // There is something funky going on here -- for example, perhaps the user
    284     // has not restarted since enabling metrics reporting, so we haven't
    285     // enabled the csd whitelist yet.  Just to be safe we return true in this
    286     // case.
    287     return true;
    288   }
    289   return database_->ContainsCsdWhitelistedUrl(url);
    290 }
    291 
    292 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
    293   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    294   if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
    295     return true;
    296   }
    297   return database_->ContainsDownloadWhitelistedUrl(url);
    298 }
    299 
    300 bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
    301     const std::string& str) {
    302   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    303   if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
    304     return true;
    305   }
    306   return database_->ContainsDownloadWhitelistedString(str);
    307 }
    308 
    309 bool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
    310   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    311   if (!enabled_ || !MakeDatabaseAvailable()) {
    312     return true;
    313   }
    314   return database_->IsMalwareIPMatchKillSwitchOn();
    315 }
    316 
    317 bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
    318                                                  Client* client) {
    319   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    320   if (!enabled_)
    321     return true;
    322 
    323   if (!CanCheckUrl(url))
    324     return true;
    325 
    326   const base::TimeTicks start = base::TimeTicks::Now();
    327   if (!MakeDatabaseAvailable()) {
    328     QueuedCheck check;
    329     check.check_type = safe_browsing_util::MALWARE;  // or PHISH
    330     check.client = client;
    331     check.url = url;
    332     check.start = start;
    333     queued_checks_.push_back(check);
    334     return false;
    335   }
    336 
    337   std::string list;
    338   std::vector<SBPrefix> prefix_hits;
    339   std::vector<SBFullHashResult> full_hits;
    340 
    341   bool prefix_match =
    342       database_->ContainsBrowseUrl(url, &list, &prefix_hits, &full_hits,
    343           sb_service_->protocol_manager()->last_update());
    344 
    345   UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
    346 
    347   if (!prefix_match)
    348     return true;  // URL is okay.
    349 
    350   // Needs to be asynchronous, since we could be in the constructor of a
    351   // ResourceDispatcherHost event handler which can't pause there.
    352   SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url),
    353                                                    std::vector<SBFullHash>(),
    354                                                    client,
    355                                                    safe_browsing_util::MALWARE);
    356   check->need_get_hash = full_hits.empty();
    357   check->prefix_hits.swap(prefix_hits);
    358   check->full_hits.swap(full_hits);
    359   checks_.insert(check);
    360 
    361   BrowserThread::PostTask(
    362       BrowserThread::IO, FROM_HERE,
    363       base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
    364 
    365   return false;
    366 }
    367 
    368 void SafeBrowsingDatabaseManager::CancelCheck(Client* client) {
    369   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    370   for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
    371     // We can't delete matching checks here because the db thread has a copy of
    372     // the pointer.  Instead, we simply NULL out the client, and when the db
    373     // thread calls us back, we'll clean up the check.
    374     if ((*i)->client == client)
    375       (*i)->client = NULL;
    376   }
    377 
    378   // Scan the queued clients store. Clients may be here if they requested a URL
    379   // check before the database has finished loading.
    380   for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
    381        it != queued_checks_.end(); ) {
    382     // In this case it's safe to delete matches entirely since nothing has a
    383     // pointer to them.
    384     if (it->client == client)
    385       it = queued_checks_.erase(it);
    386     else
    387       ++it;
    388   }
    389 }
    390 
    391 void SafeBrowsingDatabaseManager::HandleGetHashResults(
    392     SafeBrowsingCheck* check,
    393     const std::vector<SBFullHashResult>& full_hashes,
    394     bool can_cache) {
    395   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    396 
    397   if (!enabled_)
    398     return;
    399 
    400   // If the service has been shut down, |check| should have been deleted.
    401   DCHECK(checks_.find(check) != checks_.end());
    402 
    403   // |start| is set before calling |GetFullHash()|, which should be
    404   // the only path which gets to here.
    405   DCHECK(!check->start.is_null());
    406   UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
    407                            base::TimeTicks::Now() - check->start);
    408 
    409   std::vector<SBPrefix> prefixes = check->prefix_hits;
    410   OnHandleGetHashResults(check, full_hashes);  // 'check' is deleted here.
    411 
    412   if (can_cache && MakeDatabaseAvailable()) {
    413     // Cache the GetHash results in memory:
    414     database_->CacheHashResults(prefixes, full_hashes);
    415   }
    416 }
    417 
    418 void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) {
    419   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    420   DCHECK(enabled_);
    421   DCHECK(!callback.is_null());
    422   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
    423       &SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this, callback));
    424 }
    425 
    426 void SafeBrowsingDatabaseManager::AddChunks(const std::string& list,
    427                                             SBChunkList* chunks,
    428                                             AddChunksCallback callback) {
    429   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    430   DCHECK(enabled_);
    431   DCHECK(!callback.is_null());
    432   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
    433       &SafeBrowsingDatabaseManager::AddDatabaseChunks, this, list,
    434       chunks, callback));
    435 }
    436 
    437 void SafeBrowsingDatabaseManager::DeleteChunks(
    438     std::vector<SBChunkDelete>* chunk_deletes) {
    439   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    440   DCHECK(enabled_);
    441   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
    442       &SafeBrowsingDatabaseManager::DeleteDatabaseChunks, this, chunk_deletes));
    443 }
    444 
    445 void SafeBrowsingDatabaseManager::UpdateStarted() {
    446   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    447   DCHECK(enabled_);
    448   DCHECK(!update_in_progress_);
    449   update_in_progress_ = true;
    450 }
    451 
    452 void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) {
    453   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    454   DCHECK(enabled_);
    455   if (update_in_progress_) {
    456     update_in_progress_ = false;
    457     safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
    458       base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished,
    459                  this, update_succeeded));
    460   }
    461 }
    462 
    463 void SafeBrowsingDatabaseManager::ResetDatabase() {
    464   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    465   DCHECK(enabled_);
    466   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
    467       &SafeBrowsingDatabaseManager::OnResetDatabase, this));
    468 }
    469 
    470 void SafeBrowsingDatabaseManager::PurgeMemory() {
    471   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    472   CloseDatabase();
    473 }
    474 
    475 void SafeBrowsingDatabaseManager::LogPauseDelay(base::TimeDelta time) {
    476   UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
    477 }
    478 
    479 void SafeBrowsingDatabaseManager::StartOnIOThread() {
    480   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    481   if (enabled_)
    482     return;
    483 
    484   DCHECK(!safe_browsing_thread_.get());
    485   safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
    486   if (!safe_browsing_thread_->Start())
    487     return;
    488   enabled_ = true;
    489 
    490   MakeDatabaseAvailable();
    491 }
    492 
    493 void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
    494   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    495 
    496   DoStopOnIOThread();
    497   if (shutdown) {
    498     sb_service_ = NULL;
    499   }
    500 }
    501 
    502 void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
    503   if (!enabled_)
    504     return;
    505 
    506   enabled_ = false;
    507 
    508   // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
    509   // If we don't do this here we may fail to close the database below.
    510   while (!queued_checks_.empty()) {
    511     QueuedCheck queued = queued_checks_.front();
    512     if (queued.client) {
    513       SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url),
    514                                  std::vector<SBFullHash>(),
    515                                  queued.client,
    516                                  queued.check_type);
    517       queued.client->OnSafeBrowsingResult(sb_check);
    518     }
    519     queued_checks_.pop_front();
    520   }
    521 
    522   // Close the database.  We don't simply DeleteSoon() because if a close is
    523   // already pending, we'll double-free, and we don't set |database_| to NULL
    524   // because if there is still anything running on the db thread, it could
    525   // create a new database object (via GetDatabase()) that would then leak.
    526   CloseDatabase();
    527 
    528   // Flush the database thread. Any in-progress database check results will be
    529   // ignored and cleaned up below.
    530   //
    531   // Note that to avoid leaking the database, we rely on the fact that no new
    532   // tasks will be added to the db thread between the call above and this one.
    533   // See comments on the declaration of |safe_browsing_thread_|.
    534   {
    535     // A ScopedAllowIO object is required to join the thread when calling Stop.
    536     // See http://crbug.com/72696. Note that we call Stop() first to clear out
    537     // any remaining tasks before clearing safe_browsing_thread_.
    538     base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
    539     safe_browsing_thread_->Stop();
    540     safe_browsing_thread_.reset();
    541   }
    542 
    543   // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
    544   // We have to do this after the db thread returns because methods on it can
    545   // have copies of these pointers, so deleting them might lead to accessing
    546   // garbage.
    547   for (CurrentChecks::iterator it = checks_.begin();
    548        it != checks_.end(); ++it) {
    549     SafeBrowsingCheck* check = *it;
    550     if (check->client)
    551       check->client->OnSafeBrowsingResult(*check);
    552   }
    553   STLDeleteElements(&checks_);
    554 
    555   gethash_requests_.clear();
    556 }
    557 
    558 bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
    559   base::AutoLock lock(database_lock_);
    560   return !closing_database_ && (database_ != NULL);
    561 }
    562 
    563 bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
    564   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    565   DCHECK(enabled_);
    566   if (DatabaseAvailable())
    567     return true;
    568   safe_browsing_thread_->message_loop()->PostTask(
    569       FROM_HERE,
    570       base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase),
    571                  this));
    572   return false;
    573 }
    574 
    575 void SafeBrowsingDatabaseManager::CloseDatabase() {
    576   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    577 
    578   // Cases to avoid:
    579   //  * If |closing_database_| is true, continuing will queue up a second
    580   //    request, |closing_database_| will be reset after handling the first
    581   //    request, and if any functions on the db thread recreate the database, we
    582   //    could start using it on the IO thread and then have the second request
    583   //    handler delete it out from under us.
    584   //  * If |database_| is NULL, then either no creation request is in flight, in
    585   //    which case we don't need to do anything, or one is in flight, in which
    586   //    case the database will be recreated before our deletion request is
    587   //    handled, and could be used on the IO thread in that time period, leading
    588   //    to the same problem as above.
    589   //  * If |queued_checks_| is non-empty and |database_| is non-NULL, we're
    590   //    about to be called back (in DatabaseLoadComplete()).  This will call
    591   //    CheckUrl(), which will want the database.  Closing the database here
    592   //    would lead to an infinite loop in DatabaseLoadComplete(), and even if it
    593   //    didn't, it would be pointless since we'd just want to recreate.
    594   //
    595   // The first two cases above are handled by checking DatabaseAvailable().
    596   if (!DatabaseAvailable() || !queued_checks_.empty())
    597     return;
    598 
    599   closing_database_ = true;
    600   if (safe_browsing_thread_.get()) {
    601     safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
    602         base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this));
    603   }
    604 }
    605 
    606 SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
    607   DCHECK_EQ(base::MessageLoop::current(),
    608             safe_browsing_thread_->message_loop());
    609   if (database_)
    610     return database_;
    611   startup_metric_utils::ScopedSlowStartupUMA
    612       scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
    613   const base::TimeTicks before = base::TimeTicks::Now();
    614 
    615   SafeBrowsingDatabase* database =
    616       SafeBrowsingDatabase::Create(enable_download_protection_,
    617                                    enable_csd_whitelist_,
    618                                    enable_download_whitelist_,
    619                                    enable_extension_blacklist_,
    620                                    enable_side_effect_free_whitelist_);
    621 
    622   database->Init(SafeBrowsingService::GetBaseFilename());
    623   {
    624     // Acquiring the lock here guarantees correct ordering between the writes to
    625     // the new database object above, and the setting of |databse_| below.
    626     base::AutoLock lock(database_lock_);
    627     database_ = database;
    628   }
    629 
    630   BrowserThread::PostTask(
    631       BrowserThread::IO, FROM_HERE,
    632       base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this));
    633 
    634   UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
    635   return database_;
    636 }
    637 
    638 void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) {
    639   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    640 
    641   if (!enabled_)
    642     return;
    643 
    644   // If the service has been shut down, |check| should have been deleted.
    645   DCHECK(checks_.find(check) != checks_.end());
    646 
    647   if (check->client && check->need_get_hash) {
    648     // We have a partial match so we need to query Google for the full hash.
    649     // Clean up will happen in HandleGetHashResults.
    650 
    651     // See if we have a GetHash request already in progress for this particular
    652     // prefix. If so, we just append ourselves to the list of interested parties
    653     // when the results arrive. We only do this for checks involving one prefix,
    654     // since that is the common case (multiple prefixes will issue the request
    655     // as normal).
    656     if (check->prefix_hits.size() == 1) {
    657       SBPrefix prefix = check->prefix_hits[0];
    658       GetHashRequests::iterator it = gethash_requests_.find(prefix);
    659       if (it != gethash_requests_.end()) {
    660         // There's already a request in progress.
    661         it->second.push_back(check);
    662         return;
    663       }
    664 
    665       // No request in progress, so we're the first for this prefix.
    666       GetHashRequestors requestors;
    667       requestors.push_back(check);
    668       gethash_requests_[prefix] = requestors;
    669     }
    670 
    671     // Reset the start time so that we can measure the network time without the
    672     // database time.
    673     check->start = base::TimeTicks::Now();
    674     // Note: If |this| is deleted or stopped, the protocol_manager will
    675     // be destroyed as well - hence it's OK to do unretained in this case.
    676     bool is_download = check->check_type == safe_browsing_util::BINURL ||
    677                        check->check_type == safe_browsing_util::BINHASH;
    678     sb_service_->protocol_manager()->GetFullHash(
    679         check->prefix_hits,
    680         base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults,
    681                    base::Unretained(this),
    682                    check),
    683         is_download);
    684   } else {
    685     // We may have cached results for previous GetHash queries.  Since
    686     // this data comes from cache, don't histogram hits.
    687     HandleOneCheck(check, check->full_hits);
    688   }
    689 }
    690 
    691 void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
    692     GetChunksCallback callback) {
    693   DCHECK_EQ(base::MessageLoop::current(),
    694             safe_browsing_thread_->message_loop());
    695 
    696   bool database_error = true;
    697   std::vector<SBListChunkRanges> lists;
    698   DCHECK(!database_update_in_progress_);
    699   database_update_in_progress_ = true;
    700   GetDatabase();  // This guarantees that |database_| is non-NULL.
    701   if (database_->UpdateStarted(&lists)) {
    702     database_error = false;
    703   } else {
    704     database_->UpdateFinished(false);
    705   }
    706 
    707   BrowserThread::PostTask(
    708       BrowserThread::IO, FROM_HERE,
    709       base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase,
    710                  this, lists, database_error, callback));
    711 }
    712 
    713 void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
    714     const std::vector<SBListChunkRanges>& lists, bool database_error,
    715     GetChunksCallback callback) {
    716   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    717   if (enabled_)
    718     callback.Run(lists, database_error);
    719 }
    720 
    721 void SafeBrowsingDatabaseManager::OnAddChunksComplete(
    722     AddChunksCallback callback) {
    723   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    724   if (enabled_)
    725     callback.Run();
    726 }
    727 
    728 void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
    729   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    730   if (!enabled_)
    731     return;
    732 
    733   HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
    734   if (queued_checks_.empty())
    735     return;
    736 
    737   // If the database isn't already available, calling CheckUrl() in the loop
    738   // below will add the check back to the queue, and we'll infinite-loop.
    739   DCHECK(DatabaseAvailable());
    740   while (!queued_checks_.empty()) {
    741     QueuedCheck check = queued_checks_.front();
    742     DCHECK(!check.start.is_null());
    743     HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start);
    744     // If CheckUrl() determines the URL is safe immediately, it doesn't call the
    745     // client's handler function (because normally it's being directly called by
    746     // the client).  Since we're not the client, we have to convey this result.
    747     if (check.client && CheckBrowseUrl(check.url, check.client)) {
    748       SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url),
    749                                  std::vector<SBFullHash>(),
    750                                  check.client,
    751                                  check.check_type);
    752       check.client->OnSafeBrowsingResult(sb_check);
    753     }
    754     queued_checks_.pop_front();
    755   }
    756 }
    757 
    758 void SafeBrowsingDatabaseManager::AddDatabaseChunks(
    759     const std::string& list_name, SBChunkList* chunks,
    760     AddChunksCallback callback) {
    761   DCHECK_EQ(base::MessageLoop::current(),
    762             safe_browsing_thread_->message_loop());
    763   if (chunks) {
    764     GetDatabase()->InsertChunks(list_name, *chunks);
    765     delete chunks;
    766   }
    767   BrowserThread::PostTask(
    768       BrowserThread::IO, FROM_HERE,
    769       base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this,
    770                  callback));
    771 }
    772 
    773 void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
    774     std::vector<SBChunkDelete>* chunk_deletes) {
    775   DCHECK_EQ(base::MessageLoop::current(),
    776             safe_browsing_thread_->message_loop());
    777   if (chunk_deletes) {
    778     GetDatabase()->DeleteChunks(*chunk_deletes);
    779     delete chunk_deletes;
    780   }
    781 }
    782 
    783 SBThreatType SafeBrowsingDatabaseManager::GetThreatTypeFromListname(
    784     const std::string& list_name) {
    785   if (safe_browsing_util::IsPhishingList(list_name)) {
    786     return SB_THREAT_TYPE_URL_PHISHING;
    787   }
    788 
    789   if (safe_browsing_util::IsMalwareList(list_name)) {
    790     return SB_THREAT_TYPE_URL_MALWARE;
    791   }
    792 
    793   if (safe_browsing_util::IsBadbinurlList(list_name)) {
    794     return SB_THREAT_TYPE_BINARY_MALWARE_URL;
    795   }
    796 
    797   if (safe_browsing_util::IsBadbinhashList(list_name)) {
    798     return SB_THREAT_TYPE_BINARY_MALWARE_HASH;
    799   }
    800 
    801   if (safe_browsing_util::IsExtensionList(list_name)) {
    802     return SB_THREAT_TYPE_EXTENSION;
    803   }
    804 
    805   DVLOG(1) << "Unknown safe browsing list " << list_name;
    806   return SB_THREAT_TYPE_SAFE;
    807 }
    808 
    809 void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
    810     bool update_succeeded) {
    811   DCHECK_EQ(base::MessageLoop::current(),
    812             safe_browsing_thread_->message_loop());
    813   GetDatabase()->UpdateFinished(update_succeeded);
    814   DCHECK(database_update_in_progress_);
    815   database_update_in_progress_ = false;
    816   BrowserThread::PostTask(
    817       BrowserThread::UI, FROM_HERE,
    818       base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished,
    819                  this, update_succeeded));
    820 }
    821 
    822 void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
    823     bool update_succeeded) {
    824   content::NotificationService::current()->Notify(
    825       chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
    826       content::Source<SafeBrowsingDatabaseManager>(this),
    827       content::Details<bool>(&update_succeeded));
    828 }
    829 
    830 void SafeBrowsingDatabaseManager::OnCloseDatabase() {
    831   DCHECK_EQ(base::MessageLoop::current(),
    832             safe_browsing_thread_->message_loop());
    833   DCHECK(closing_database_);
    834 
    835   // Because |closing_database_| is true, nothing on the IO thread will be
    836   // accessing the database, so it's safe to delete and then NULL the pointer.
    837   delete database_;
    838   database_ = NULL;
    839 
    840   // Acquiring the lock here guarantees correct ordering between the resetting
    841   // of |database_| above and of |closing_database_| below, which ensures there
    842   // won't be a window during which the IO thread falsely believes the database
    843   // is available.
    844   base::AutoLock lock(database_lock_);
    845   closing_database_ = false;
    846 }
    847 
    848 void SafeBrowsingDatabaseManager::OnResetDatabase() {
    849   DCHECK_EQ(base::MessageLoop::current(),
    850             safe_browsing_thread_->message_loop());
    851   GetDatabase()->ResetDatabase();
    852 }
    853 
    854 void SafeBrowsingDatabaseManager::CacheHashResults(
    855   const std::vector<SBPrefix>& prefixes,
    856   const std::vector<SBFullHashResult>& full_hashes) {
    857   DCHECK_EQ(base::MessageLoop::current(),
    858             safe_browsing_thread_->message_loop());
    859   GetDatabase()->CacheHashResults(prefixes, full_hashes);
    860 }
    861 
    862 void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
    863     SafeBrowsingCheck* check,
    864     const std::vector<SBFullHashResult>& full_hashes) {
    865   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    866   safe_browsing_util::ListType check_type = check->check_type;
    867   SBPrefix prefix = check->prefix_hits[0];
    868   GetHashRequests::iterator it = gethash_requests_.find(prefix);
    869   if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
    870     const bool hit = HandleOneCheck(check, full_hashes);
    871     RecordGetHashCheckStatus(hit, check_type, full_hashes);
    872     return;
    873   }
    874 
    875   // Call back all interested parties, noting if any has a hit.
    876   GetHashRequestors& requestors = it->second;
    877   bool hit = false;
    878   for (GetHashRequestors::iterator r = requestors.begin();
    879        r != requestors.end(); ++r) {
    880     if (HandleOneCheck(*r, full_hashes))
    881       hit = true;
    882   }
    883   RecordGetHashCheckStatus(hit, check_type, full_hashes);
    884 
    885   gethash_requests_.erase(it);
    886 }
    887 
    888 bool SafeBrowsingDatabaseManager::HandleOneCheck(
    889     SafeBrowsingCheck* check,
    890     const std::vector<SBFullHashResult>& full_hashes) {
    891   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    892   DCHECK(check);
    893 
    894   bool is_threat = false;
    895 
    896   for (size_t i = 0; i < check->urls.size(); ++i) {
    897     int index =
    898         safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes);
    899     if (index == -1)
    900       continue;
    901     SBThreatType threat =
    902         GetThreatTypeFromListname(full_hashes[index].list_name);
    903     if (threat != SB_THREAT_TYPE_SAFE) {
    904       check->url_results[i] = threat;
    905       is_threat = true;
    906     } else {
    907       NOTREACHED();
    908     }
    909   }
    910 
    911   for (size_t i = 0; i < check->full_hashes.size(); ++i) {
    912     int index =
    913         safe_browsing_util::GetHashIndex(check->full_hashes[i], full_hashes);
    914     if (index == -1)
    915       continue;
    916     SBThreatType threat =
    917         GetThreatTypeFromListname(full_hashes[index].list_name);
    918     if (threat != SB_THREAT_TYPE_SAFE) {
    919       check->full_hash_results[i] = threat;
    920       is_threat = true;
    921     } else {
    922       NOTREACHED();
    923     }
    924   }
    925 
    926   SafeBrowsingCheckDone(check);
    927   return is_threat;
    928 }
    929 
    930 void SafeBrowsingDatabaseManager::CheckDownloadHashOnSBThread(
    931     SafeBrowsingCheck* check) {
    932   DCHECK_EQ(base::MessageLoop::current(),
    933             safe_browsing_thread_->message_loop());
    934   DCHECK(enable_download_protection_);
    935 
    936   DCHECK_EQ(1u, check->full_hashes.size());
    937   SBFullHash full_hash = check->full_hashes[0];
    938 
    939   if (!database_->ContainsDownloadHashPrefix(full_hash.prefix)) {
    940     // Good, we don't have hash for this url prefix.
    941     BrowserThread::PostTask(
    942         BrowserThread::IO, FROM_HERE,
    943         base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadHashDone, this,
    944                    check));
    945     return;
    946   }
    947 
    948   check->need_get_hash = true;
    949   check->prefix_hits.push_back(full_hash.prefix);
    950   BrowserThread::PostTask(
    951       BrowserThread::IO, FROM_HERE,
    952       base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
    953 }
    954 
    955 void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
    956     SafeBrowsingCheck* check) {
    957   DCHECK_EQ(base::MessageLoop::current(),
    958             safe_browsing_thread_->message_loop());
    959   DCHECK(enable_download_protection_);
    960 
    961   std::vector<SBPrefix> prefix_hits;
    962 
    963   if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
    964     // Good, we don't have hash for this url prefix.
    965     BrowserThread::PostTask(
    966         BrowserThread::IO, FROM_HERE,
    967         base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this,
    968                    check));
    969     return;
    970   }
    971 
    972   check->need_get_hash = true;
    973   check->prefix_hits.clear();
    974   check->prefix_hits = prefix_hits;
    975   BrowserThread::PostTask(
    976       BrowserThread::IO, FROM_HERE,
    977       base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
    978 }
    979 
    980 void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
    981     SafeBrowsingCheck* check) {
    982   DCHECK_EQ(base::MessageLoop::current(),
    983             safe_browsing_thread_->message_loop());
    984 
    985   std::vector<SBPrefix> prefixes;
    986   for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin();
    987        it != check->full_hashes.end(); ++it) {
    988     prefixes.push_back((*it).prefix);
    989   }
    990   database_->ContainsExtensionPrefixes(prefixes, &check->prefix_hits);
    991 
    992   if (check->prefix_hits.empty()) {
    993     // No matches for any extensions.
    994     BrowserThread::PostTask(
    995         BrowserThread::IO,
    996         FROM_HERE,
    997         base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone, this,
    998                    check));
    999   } else {
   1000     // Some prefixes matched, we need to ask Google whether they're legit.
   1001     check->need_get_hash = true;
   1002     BrowserThread::PostTask(
   1003         BrowserThread::IO,
   1004         FROM_HERE,
   1005         base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
   1006   }
   1007 }
   1008 
   1009 void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
   1010   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   1011   DCHECK(check);
   1012 
   1013   if (!enabled_)
   1014     return;
   1015 
   1016   DCHECK(checks_.find(check) != checks_.end());
   1017   if (check->client) {
   1018     check->client->OnSafeBrowsingResult(*check);
   1019     check->client = NULL;
   1020   }
   1021 }
   1022 
   1023 void SafeBrowsingDatabaseManager::CheckDownloadUrlDone(
   1024     SafeBrowsingCheck* check) {
   1025   DCHECK(enable_download_protection_);
   1026   SafeBrowsingCheckDone(check);
   1027 }
   1028 
   1029 void SafeBrowsingDatabaseManager::CheckDownloadHashDone(
   1030     SafeBrowsingCheck* check) {
   1031   DCHECK(enable_download_protection_);
   1032   SafeBrowsingCheckDone(check);
   1033 }
   1034 
   1035 void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
   1036     SafeBrowsingCheck* check) {
   1037   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   1038   DCHECK(check);
   1039 
   1040   if (!enabled_)
   1041     return;
   1042 
   1043   VLOG(1) << "SafeBrowsingCheckDone";
   1044   DCHECK(checks_.find(check) != checks_.end());
   1045   if (check->client)
   1046     check->client->OnSafeBrowsingResult(*check);
   1047   checks_.erase(check);
   1048   delete check;
   1049 }
   1050 
   1051 void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
   1052     SafeBrowsingCheck* check,
   1053     const base::Closure& task) {
   1054   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   1055   check->timeout_factory_.reset(
   1056       new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this));
   1057   checks_.insert(check);
   1058 
   1059   safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task);
   1060 
   1061   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
   1062       base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback,
   1063                  check->timeout_factory_->GetWeakPtr(), check),
   1064       check_timeout_);
   1065 }
   1066