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