12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/database_manager.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <algorithm>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind_helpers.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/callback.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/command_line.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/leak_tracker.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/path_service.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/stl_util.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_restrictions.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/browser_process.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/prerender/prerender_field_trial.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/client_side_detection_service.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/download_protection_service.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/malware_details.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/protocol_manager.h"
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_database.h"
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/ui_manager.h"
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_constants.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_paths.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/chrome_switches.h"
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "components/metrics/metrics_service.h"
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "components/startup_metric_utils/startup_metric_utils.h"
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_service.h"
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "url/url_constants.h"
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Timeout for match checks, e.g. download URLs, hashes.
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kCheckTimeoutMs = 10000;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Records disposition information about the check.  |hit| should be
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// |true| if there were any prefix hits in |full_hashes|.
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void RecordGetHashCheckStatus(
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool hit,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    safe_browsing_util::ListType check_type,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<SBFullHashResult>& full_hashes) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeBrowsingProtocolManager::ResultType result;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (full_hashes.empty()) {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (hit) {
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool is_download = check_type == safe_browsing_util::BINURL;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)bool IsExpectedThreat(
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const SBThreatType threat_type,
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::vector<SBThreatType>& expected_threats) {
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  return expected_threats.end() != std::find(expected_threats.begin(),
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                             expected_threats.end(),
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                             threat_type);
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Return the list id from the first result in |full_hashes| which matches
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// |hash|, or INVALID if none match.
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)safe_browsing_util::ListType GetHashThreatListType(
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const SBFullHash& hash,
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<SBFullHashResult>& full_hashes,
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t* index) {
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t i = 0; i < full_hashes.size(); ++i) {
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (SBFullHashEqual(hash, full_hashes[i].hash)) {
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (index)
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        *index = i;
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return static_cast<safe_browsing_util::ListType>(full_hashes[i].list_id);
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return safe_browsing_util::INVALID;
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Given a URL, compare all the possible host + path full hashes to the set of
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// provided full hashes.  Returns the list id of the a matching result from
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// |full_hashes|, or INVALID if none match.
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)safe_browsing_util::ListType GetUrlThreatListType(
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const GURL& url,
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<SBFullHashResult>& full_hashes,
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t* index) {
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (full_hashes.empty())
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return safe_browsing_util::INVALID;
960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<std::string> patterns;
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  safe_browsing_util::GeneratePatternsToCheck(url, &patterns);
990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t i = 0; i < patterns.size(); ++i) {
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    safe_browsing_util::ListType threat = GetHashThreatListType(
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        SBFullHashForString(patterns[i]), full_hashes, index);
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (threat != safe_browsing_util::INVALID)
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return threat;
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return safe_browsing_util::INVALID;
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SBThreatType GetThreatTypeFromListType(safe_browsing_util::ListType list_type) {
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (list_type) {
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case safe_browsing_util::PHISH:
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return SB_THREAT_TYPE_URL_PHISHING;
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case safe_browsing_util::MALWARE:
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return SB_THREAT_TYPE_URL_MALWARE;
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case safe_browsing_util::BINURL:
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return SB_THREAT_TYPE_BINARY_MALWARE_URL;
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case safe_browsing_util::EXTENSIONBLACKLIST:
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return SB_THREAT_TYPE_EXTENSION;
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    default:
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      DVLOG(1) << "Unknown safe browsing list id " << list_type;
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return SB_THREAT_TYPE_SAFE;
1220529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
1230529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// static
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SBThreatType SafeBrowsingDatabaseManager::GetHashThreatType(
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const SBFullHash& hash,
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::vector<SBFullHashResult>& full_hashes) {
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return GetThreatTypeFromListType(
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GetHashThreatListType(hash, full_hashes, NULL));
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// static
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SBThreatType SafeBrowsingDatabaseManager::GetUrlThreatType(
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const GURL& url,
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::vector<SBFullHashResult>& full_hashes,
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t* index) {
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return GetThreatTypeFromListType(
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GetUrlThreatListType(url, full_hashes, index));
142f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
143f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SafeBrowsingDatabaseManager::SafeBrowsingCheck::SafeBrowsingCheck(
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<GURL>& urls,
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<SBFullHash>& full_hashes,
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Client* client,
14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    safe_browsing_util::ListType check_type,
14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::vector<SBThreatType>& expected_threats)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : urls(urls),
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      url_results(urls.size(), SB_THREAT_TYPE_SAFE),
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      url_metadata(urls.size()),
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      full_hashes(full_hashes),
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      full_hash_results(full_hashes.size(), SB_THREAT_TYPE_SAFE),
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client(client),
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      need_get_hash(false),
15758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      check_type(check_type),
15858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      expected_threats(expected_threats) {
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(urls.empty(), !full_hashes.empty())
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      << "Exactly one of urls and full_hashes must be set";
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SafeBrowsingDatabaseManager::SafeBrowsingCheck::~SafeBrowsingCheck() {}
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::Client::OnSafeBrowsingResult(
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const SafeBrowsingCheck& check) {
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(check.urls.size(), check.url_results.size());
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_EQ(check.full_hashes.size(), check.full_hash_results.size());
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!check.urls.empty()) {
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(check.full_hashes.empty());
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (check.check_type) {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case safe_browsing_util::MALWARE:
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case safe_browsing_util::PHISH:
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DCHECK_EQ(1u, check.urls.size());
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        OnCheckBrowseUrlResult(
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            check.urls[0], check.url_results[0], check.url_metadata[0]);
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case safe_browsing_util::BINURL:
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DCHECK_EQ(check.urls.size(), check.url_results.size());
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        OnCheckDownloadUrlResult(
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            check.urls,
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            *std::max_element(check.url_results.begin(),
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              check.url_results.end()));
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NOTREACHED();
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (!check.full_hashes.empty()) {
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    switch (check.check_type) {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      case safe_browsing_util::EXTENSIONBLACKLIST: {
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::set<std::string> unsafe_extension_ids;
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        for (size_t i = 0; i < check.full_hashes.size(); ++i) {
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          std::string extension_id =
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              safe_browsing_util::SBFullHashToString(check.full_hashes[i]);
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          if (check.full_hash_results[i] == SB_THREAT_TYPE_EXTENSION)
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            unsafe_extension_ids.insert(extension_id);
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        OnCheckExtensionsResult(unsafe_extension_ids);
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        break;
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      default:
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        NOTREACHED();
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    NOTREACHED();
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SafeBrowsingDatabaseManager::SafeBrowsingDatabaseManager(
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const scoped_refptr<SafeBrowsingService>& service)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : sb_service_(service),
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      database_(NULL),
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enabled_(false),
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_download_protection_(false),
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_csd_whitelist_(false),
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_download_whitelist_(false),
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      enable_extension_blacklist_(false),
21890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      enable_side_effect_free_whitelist_(false),
2190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      enable_ip_blacklist_(false),
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      update_in_progress_(false),
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      database_update_in_progress_(false),
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      closing_database_(false),
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      check_timeout_(base::TimeDelta::FromMilliseconds(kCheckTimeoutMs)) {
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(sb_service_.get() != NULL);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Android only supports a subset of FULL_SAFE_BROWSING.
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(shess): This shouldn't be OS-driven <http://crbug.com/394379>
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if !defined(OS_ANDROID)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CommandLine* cmdline = CommandLine::ForCurrentProcess();
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enable_download_protection_ =
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We only download the csd-whitelist if client-side phishing detection is
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // enabled.
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enable_csd_whitelist_ =
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection);
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(noelutz): remove this boolean variable since it should always be true
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // if SafeBrowsing is enabled.  Unfortunately, we have no test data for this
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // list right now.  This means that we need to be able to disable this list
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // for the SafeBrowsing test to pass.
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enable_download_whitelist_ = enable_csd_whitelist_;
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(kalman): there really shouldn't be a flag for this.
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enable_extension_blacklist_ =
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
24790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  enable_side_effect_free_whitelist_ =
24990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      prerender::IsSideEffectFreeWhitelistEnabled() &&
25090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      !cmdline->HasSwitch(switches::kSbDisableSideEffectFreeWhitelist);
25190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // The client-side IP blacklist feature is tightly integrated with client-side
2530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // phishing protection for now.
2540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  enable_ip_blacklist_ = enable_csd_whitelist_;
2550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
25690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  enum SideEffectFreeWhitelistStatus {
25790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SIDE_EFFECT_FREE_WHITELIST_ENABLED,
25890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SIDE_EFFECT_FREE_WHITELIST_DISABLED,
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX
26090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  };
26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SideEffectFreeWhitelistStatus side_effect_free_whitelist_status =
26390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      enable_side_effect_free_whitelist_ ? SIDE_EFFECT_FREE_WHITELIST_ENABLED :
26490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      SIDE_EFFECT_FREE_WHITELIST_DISABLED;
26590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("SB2.SideEffectFreeWhitelistStatus",
26790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            side_effect_free_whitelist_status,
26890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            SIDE_EFFECT_FREE_WHITELIST_STATUS_MAX);
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#endif
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SafeBrowsingDatabaseManager::~SafeBrowsingDatabaseManager() {
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We should have already been shut down. If we're still enabled, then the
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // database isn't going to be closed properly, which could lead to corruption.
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!enabled_);
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::CanCheckUrl(const GURL& url) const {
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return url.SchemeIs(url::kFtpScheme) ||
280010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         url.SchemeIs(url::kHttpScheme) ||
281010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         url.SchemeIs(url::kHttpsScheme);
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::CheckDownloadUrl(
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<GURL>& url_chain,
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Client* client) {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_ || !enable_download_protection_)
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We need to check the database for url prefix, and later may fetch the url
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // from the safebrowsing backends. These need to be asynchronous.
29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  SafeBrowsingCheck* check =
29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      new SafeBrowsingCheck(url_chain,
29558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            std::vector<SBFullHash>(),
29658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            client,
29758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            safe_browsing_util::BINURL,
29858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            std::vector<SBThreatType>(1,
29958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                SB_THREAT_TYPE_BINARY_MALWARE_URL));
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StartSafeBrowsingCheck(
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      check,
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread, this,
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 check));
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::CheckExtensionIDs(
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::set<std::string>& extension_ids,
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Client* client) {
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_ || !enable_extension_blacklist_)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<SBFullHash> extension_id_hashes;
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::transform(extension_ids.begin(), extension_ids.end(),
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 std::back_inserter(extension_id_hashes),
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 safe_browsing_util::StringToSBFullHash);
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeBrowsingCheck* check = new SafeBrowsingCheck(
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      std::vector<GURL>(),
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_id_hashes,
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client,
32458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      safe_browsing_util::EXTENSIONBLACKLIST,
32558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      std::vector<SBThreatType>(1, SB_THREAT_TYPE_EXTENSION));
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StartSafeBrowsingCheck(
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      check,
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread,
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this,
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 check));
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool SafeBrowsingDatabaseManager::CheckSideEffectFreeWhitelistUrl(
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const GURL& url) {
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!enabled_)
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (!CanCheckUrl(url))
34190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return false;
34290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return database_->ContainsSideEffectFreeWhitelistUrl(url);
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3460f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool SafeBrowsingDatabaseManager::MatchMalwareIP(
3470f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    const std::string& ip_address) {
3480f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3490f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (!enabled_ || !enable_ip_blacklist_ || !MakeDatabaseAvailable()) {
3500f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return false;  // Fail open.
3510f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  }
3520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return database_->ContainsMalwareIP(ip_address);
3530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
3540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::MatchCsdWhitelistUrl(const GURL& url) {
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // There is something funky going on here -- for example, perhaps the user
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // has not restarted since enabling metrics reporting, so we haven't
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // enabled the csd whitelist yet.  Just to be safe we return true in this
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // case.
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return database_->ContainsCsdWhitelistedUrl(url);
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistUrl(const GURL& url) {
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return database_->ContainsDownloadWhitelistedUrl(url);
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::MatchDownloadWhitelistString(
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& str) {
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_ || !enable_download_whitelist_ || !MakeDatabaseAvailable()) {
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return database_->ContainsDownloadWhitelistedString(str);
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
38458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochbool SafeBrowsingDatabaseManager::IsMalwareKillSwitchOn() {
38558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
38658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (!enabled_ || !MakeDatabaseAvailable()) {
38758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    return true;
38858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  }
38958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  return database_->IsMalwareIPMatchKillSwitchOn();
39058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
39158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool SafeBrowsingDatabaseManager::IsCsdWhitelistKillSwitchOn() {
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!enabled_ || !MakeDatabaseAvailable()) {
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return true;
396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return database_->IsCsdWhitelistKillSwitchOn();
398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::CheckBrowseUrl(const GURL& url,
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                 Client* client) {
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_)
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!CanCheckUrl(url))
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
40958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  std::vector<SBThreatType> expected_threats;
41058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE);
41158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING);
41258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::TimeTicks start = base::TimeTicks::Now();
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!MakeDatabaseAvailable()) {
41558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    QueuedCheck queued_check(safe_browsing_util::MALWARE,  // or PHISH
41658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             client,
41758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             url,
41858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             expected_threats,
41958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                             start);
42058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    queued_checks_.push_back(queued_check);
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<SBPrefix> prefix_hits;
425cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<SBFullHashResult> cache_hits;
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool prefix_match =
428cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      database_->ContainsBrowseUrl(url, &prefix_hits, &cache_hits);
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!prefix_match)
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;  // URL is okay.
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Needs to be asynchronous, since we could be in the constructor of a
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ResourceDispatcherHost event handler which can't pause there.
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeBrowsingCheck* check = new SafeBrowsingCheck(std::vector<GURL>(1, url),
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                   std::vector<SBFullHash>(),
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                                   client,
44058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                                   safe_browsing_util::MALWARE,
44158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                                   expected_threats);
442cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  check->need_get_hash = cache_hits.empty();
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  check->prefix_hits.swap(prefix_hits);
444cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  check->cache_hits.swap(cache_hits);
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checks_.insert(check);
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::IO, FROM_HERE,
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::CancelCheck(Client* client) {
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We can't delete matching checks here because the db thread has a copy of
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the pointer.  Instead, we simply NULL out the client, and when the db
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // thread calls us back, we'll clean up the check.
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if ((*i)->client == client)
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (*i)->client = NULL;
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Scan the queued clients store. Clients may be here if they requested a URL
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // check before the database has finished loading.
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != queued_checks_.end(); ) {
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // In this case it's safe to delete matches entirely since nothing has a
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // pointer to them.
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (it->client == client)
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      it = queued_checks_.erase(it);
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ++it;
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::HandleGetHashResults(
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check,
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<SBFullHashResult>& full_hashes,
480cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::TimeDelta& cache_lifetime) {
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_)
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the service has been shut down, |check| should have been deleted.
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(checks_.find(check) != checks_.end());
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |start| is set before calling |GetFullHash()|, which should be
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // the only path which gets to here.
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!check->start.is_null());
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           base::TimeTicks::Now() - check->start);
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<SBPrefix> prefixes = check->prefix_hits;
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnHandleGetHashResults(check, full_hashes);  // 'check' is deleted here.
4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
498cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Cache the GetHash results.
499cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (cache_lifetime != base::TimeDelta() && MakeDatabaseAvailable())
500cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    database_->CacheHashResults(prefixes, full_hashes, cache_lifetime);
5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::GetChunks(GetChunksCallback callback) {
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enabled_);
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &SafeBrowsingDatabaseManager::GetAllChunksFromDatabase, this, callback));
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
511f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SafeBrowsingDatabaseManager::AddChunks(
512f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& list,
513f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<ScopedVector<SBChunkData> > chunks,
514f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    AddChunksCallback callback) {
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enabled_);
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback.is_null());
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &SafeBrowsingDatabaseManager::AddDatabaseChunks, this, list,
520f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      base::Passed(&chunks), callback));
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::DeleteChunks(
524f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) {
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enabled_);
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
528f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      &SafeBrowsingDatabaseManager::DeleteDatabaseChunks, this,
529f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      base::Passed(&chunk_deletes)));
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::UpdateStarted() {
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enabled_);
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!update_in_progress_);
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  update_in_progress_ = true;
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::UpdateFinished(bool update_succeeded) {
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enabled_);
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (update_in_progress_) {
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    update_in_progress_ = false;
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::DatabaseUpdateFinished,
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this, update_succeeded));
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::ResetDatabase() {
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enabled_);
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, base::Bind(
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      &SafeBrowsingDatabaseManager::OnResetDatabase, this));
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::LogPauseDelay(base::TimeDelta time) {
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::StartOnIOThread() {
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (enabled_)
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!safe_browsing_thread_.get());
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!safe_browsing_thread_->Start())
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enabled_ = true;
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MakeDatabaseAvailable();
5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::StopOnIOThread(bool shutdown) {
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
5772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DoStopOnIOThread();
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (shutdown) {
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sb_service_ = NULL;
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
58468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished(
58568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    bool update_succeeded) {
58668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  content::NotificationService::current()->Notify(
58768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      chrome::NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
58868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      content::Source<SafeBrowsingDatabaseManager>(this),
58968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      content::Details<bool>(&update_succeeded));
59068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
59168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
59258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)SafeBrowsingDatabaseManager::QueuedCheck::QueuedCheck(
59358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const safe_browsing_util::ListType check_type,
59458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Client* client,
59558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const GURL& url,
59658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::vector<SBThreatType>& expected_threats,
59758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const base::TimeTicks& start)
59858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    : check_type(check_type),
59958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      client(client),
60058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      url(url),
60158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      expected_threats(expected_threats),
60258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      start(start) {
60358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
60458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
60558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)SafeBrowsingDatabaseManager::QueuedCheck::~QueuedCheck() {
60658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
60758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::DoStopOnIOThread() {
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_)
6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
6112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  enabled_ = false;
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Delete queued checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
6152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (!queued_checks_.empty()) {
6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    QueuedCheck queued = queued_checks_.front();
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (queued.client) {
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SafeBrowsingCheck sb_check(std::vector<GURL>(1, queued.url),
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 std::vector<SBFullHash>(),
6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 queued.client,
62158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 queued.check_type,
62258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 queued.expected_threats);
6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      queued.client->OnSafeBrowsingResult(sb_check);
6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    queued_checks_.pop_front();
6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
628a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Close the database.  Cases to avoid:
629a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //  * If |closing_database_| is true, continuing will queue up a second
630a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //    request, |closing_database_| will be reset after handling the first
631a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //    request, and if any functions on the db thread recreate the database, we
632a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //    could start using it on the IO thread and then have the second request
633a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //    handler delete it out from under us.
634a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //  * If |database_| is NULL, then either no creation request is in flight, in
635a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //    which case we don't need to do anything, or one is in flight, in which
636a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //    case the database will be recreated before our deletion request is
637a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //    handled, and could be used on the IO thread in that time period, leading
638a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  //    to the same problem as above.
639a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Checking DatabaseAvailable() avoids both of these.
640a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (DatabaseAvailable()) {
641a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    closing_database_ = true;
642a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
643a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        base::Bind(&SafeBrowsingDatabaseManager::OnCloseDatabase, this));
644a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Flush the database thread. Any in-progress database check results will be
6472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // ignored and cleaned up below.
6482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Note that to avoid leaking the database, we rely on the fact that no new
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // tasks will be added to the db thread between the call above and this one.
6512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // See comments on the declaration of |safe_browsing_thread_|.
6522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // A ScopedAllowIO object is required to join the thread when calling Stop.
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // See http://crbug.com/72696. Note that we call Stop() first to clear out
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // any remaining tasks before clearing safe_browsing_thread_.
6562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    safe_browsing_thread_->Stop();
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    safe_browsing_thread_.reset();
6592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Delete pending checks, calling back any clients with 'SB_THREAT_TYPE_SAFE'.
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We have to do this after the db thread returns because methods on it can
6632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // have copies of these pointers, so deleting them might lead to accessing
6642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // garbage.
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (CurrentChecks::iterator it = checks_.begin();
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != checks_.end(); ++it) {
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check = *it;
6682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (check->client)
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      check->client->OnSafeBrowsingResult(*check);
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  STLDeleteElements(&checks_);
6722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gethash_requests_.clear();
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::DatabaseAvailable() const {
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(database_lock_);
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !closing_database_ && (database_ != NULL);
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::MakeDatabaseAvailable() {
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enabled_);
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (DatabaseAvailable())
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_thread_->message_loop()->PostTask(
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      FROM_HERE,
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(base::IgnoreResult(&SafeBrowsingDatabaseManager::GetDatabase),
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this));
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SafeBrowsingDatabase* SafeBrowsingDatabaseManager::GetDatabase() {
69490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
69590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (database_)
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return database_;
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  startup_metric_utils::ScopedSlowStartupUMA
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scoped_timer("Startup.SlowStartupSafeBrowsingGetDatabase");
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::TimeTicks before = base::TimeTicks::Now();
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeBrowsingDatabase* database =
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SafeBrowsingDatabase::Create(enable_download_protection_,
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   enable_csd_whitelist_,
7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   enable_download_whitelist_,
70690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                   enable_extension_blacklist_,
7070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                   enable_side_effect_free_whitelist_,
7080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                                   enable_ip_blacklist_);
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  database->Init(SafeBrowsingService::GetBaseFilename());
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  {
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Acquiring the lock here guarantees correct ordering between the writes to
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the new database object above, and the setting of |databse_| below.
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::AutoLock lock(database_lock_);
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    database_ = database;
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::IO, FROM_HERE,
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::DatabaseLoadComplete, this));
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return database_;
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::OnCheckDone(SafeBrowsingCheck* check) {
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_)
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the service has been shut down, |check| should have been deleted.
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(checks_.find(check) != checks_.end());
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (check->client && check->need_get_hash) {
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We have a partial match so we need to query Google for the full hash.
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Clean up will happen in HandleGetHashResults.
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // See if we have a GetHash request already in progress for this particular
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // prefix. If so, we just append ourselves to the list of interested parties
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // when the results arrive. We only do this for checks involving one prefix,
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // since that is the common case (multiple prefixes will issue the request
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // as normal).
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (check->prefix_hits.size() == 1) {
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SBPrefix prefix = check->prefix_hits[0];
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetHashRequests::iterator it = gethash_requests_.find(prefix);
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (it != gethash_requests_.end()) {
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // There's already a request in progress.
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        it->second.push_back(check);
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return;
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // No request in progress, so we're the first for this prefix.
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GetHashRequestors requestors;
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      requestors.push_back(check);
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      gethash_requests_[prefix] = requestors;
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Reset the start time so that we can measure the network time without the
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // database time.
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    check->start = base::TimeTicks::Now();
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Note: If |this| is deleted or stopped, the protocol_manager will
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // be destroyed as well - hence it's OK to do unretained in this case.
764a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool is_download = check->check_type == safe_browsing_util::BINURL;
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    sb_service_->protocol_manager()->GetFullHash(
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        check->prefix_hits,
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&SafeBrowsingDatabaseManager::HandleGetHashResults,
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   base::Unretained(this),
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   check),
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        is_download);
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We may have cached results for previous GetHash queries.  Since
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // this data comes from cache, don't histogram hits.
774116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    bool is_threat = HandleOneCheck(check, check->cache_hits);
775116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // cache_hits should only contain hits for a fullhash we searched for, so if
776116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // we got to this point it should always result in a threat match.
777116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DCHECK(is_threat);
7782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
7802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::GetAllChunksFromDatabase(
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GetChunksCallback callback) {
78390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
78490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool database_error = true;
7872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<SBListChunkRanges> lists;
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!database_update_in_progress_);
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  database_update_in_progress_ = true;
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetDatabase();  // This guarantees that |database_| is non-NULL.
7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (database_->UpdateStarted(&lists)) {
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    database_error = false;
7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    database_->UpdateFinished(false);
7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::IO, FROM_HERE,
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase,
8002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this, lists, database_error, callback));
8012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::OnGetAllChunksFromDatabase(
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<SBListChunkRanges>& lists, bool database_error,
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GetChunksCallback callback) {
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (enabled_)
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run(lists, database_error);
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::OnAddChunksComplete(
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddChunksCallback callback) {
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (enabled_)
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback.Run();
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::DatabaseLoadComplete() {
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_)
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  LOCAL_HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (queued_checks_.empty())
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the database isn't already available, calling CheckUrl() in the loop
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // below will add the check back to the queue, and we'll infinite-loop.
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(DatabaseAvailable());
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (!queued_checks_.empty()) {
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    QueuedCheck check = queued_checks_.front();
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DCHECK(!check.start.is_null());
8331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOCAL_HISTOGRAM_TIMES("SB.QueueDelay",
8341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                          base::TimeTicks::Now() - check.start);
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If CheckUrl() determines the URL is safe immediately, it doesn't call the
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // client's handler function (because normally it's being directly called by
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // the client).  Since we're not the client, we have to convey this result.
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (check.client && CheckBrowseUrl(check.url, check.client)) {
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SafeBrowsingCheck sb_check(std::vector<GURL>(1, check.url),
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 std::vector<SBFullHash>(),
8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 check.client,
84258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 check.check_type,
84358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                                 check.expected_threats);
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      check.client->OnSafeBrowsingResult(sb_check);
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    queued_checks_.pop_front();
8472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::AddDatabaseChunks(
851f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& list_name,
852f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<ScopedVector<SBChunkData> > chunks,
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    AddChunksCallback callback) {
85490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
85590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
856f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (chunks)
857f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    GetDatabase()->InsertChunks(list_name, chunks->get());
8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
8592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::IO, FROM_HERE,
8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::OnAddChunksComplete, this,
8612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 callback));
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::DeleteDatabaseChunks(
865f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) {
86690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
86790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
868f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (chunk_deletes)
8692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    GetDatabase()->DeleteChunks(*chunk_deletes);
8702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::DatabaseUpdateFinished(
8732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool update_succeeded) {
87490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
87590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
8762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetDatabase()->UpdateFinished(update_succeeded);
8772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(database_update_in_progress_);
8782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  database_update_in_progress_ = false;
8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
8802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::UI, FROM_HERE,
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::NotifyDatabaseUpdateFinished,
8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 this, update_succeeded));
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::OnCloseDatabase() {
88690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
88790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(closing_database_);
8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Because |closing_database_| is true, nothing on the IO thread will be
8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // accessing the database, so it's safe to delete and then NULL the pointer.
8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete database_;
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  database_ = NULL;
8942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Acquiring the lock here guarantees correct ordering between the resetting
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // of |database_| above and of |closing_database_| below, which ensures there
8972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // won't be a window during which the IO thread falsely believes the database
8982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // is available.
8992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::AutoLock lock(database_lock_);
9002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  closing_database_ = false;
9012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::OnResetDatabase() {
90490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
90590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetDatabase()->ResetDatabase();
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::OnHandleGetHashResults(
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check,
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<SBFullHashResult>& full_hashes) {
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_util::ListType check_type = check->check_type;
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SBPrefix prefix = check->prefix_hits[0];
9152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetHashRequests::iterator it = gethash_requests_.find(prefix);
9162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
9172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const bool hit = HandleOneCheck(check, full_hashes);
9182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RecordGetHashCheckStatus(hit, check_type, full_hashes);
9192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Call back all interested parties, noting if any has a hit.
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  GetHashRequestors& requestors = it->second;
9242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool hit = false;
9252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (GetHashRequestors::iterator r = requestors.begin();
9262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       r != requestors.end(); ++r) {
9272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (HandleOneCheck(*r, full_hashes))
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      hit = true;
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RecordGetHashCheckStatus(hit, check_type, full_hashes);
9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gethash_requests_.erase(it);
9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool SafeBrowsingDatabaseManager::HandleOneCheck(
9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check,
9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::vector<SBFullHashResult>& full_hashes) {
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(check);
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_threat = false;
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
943f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // TODO(shess): GetHashThreadListType() contains a loop,
944f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // GetUrlThreatListType() a loop around that loop.  Having another loop out
945f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // here concerns me.  It is likely that SAFE is an expected outcome, which
946f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // means all of those loops run to completion.  Refactoring this to generate a
947f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // set of sorted items to compare in sequence would probably improve things.
948f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  //
949f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Additionally, the set of patterns generated from the urls is very similar
950f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // to the patterns generated in ContainsBrowseUrl() and other database checks,
951f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // which are called from this code.  Refactoring that across the checks could
952f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // interact well with batching the checks here.
953f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < check->urls.size(); ++i) {
9551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t threat_index;
9561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SBThreatType threat =
9571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        GetUrlThreatType(check->urls[i], full_hashes, &threat_index);
95858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (threat != SB_THREAT_TYPE_SAFE &&
95958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        IsExpectedThreat(threat, check->expected_threats)) {
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      check->url_results[i] = threat;
9611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      check->url_metadata[i] = full_hashes[threat_index].metadata;
9622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      is_threat = true;
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < check->full_hashes.size(); ++i) {
967f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SBThreatType threat = GetHashThreatType(check->full_hashes[i], full_hashes);
96858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if (threat != SB_THREAT_TYPE_SAFE &&
96958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        IsExpectedThreat(threat, check->expected_threats)) {
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      check->full_hash_results[i] = threat;
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      is_threat = true;
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeBrowsingCheckDone(check);
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return is_threat;
9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::CheckDownloadUrlOnSBThread(
9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check) {
98190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
98290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
9832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enable_download_protection_);
9842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<SBPrefix> prefix_hits;
9862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
9882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Good, we don't have hash for this url prefix.
9892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
9902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::IO, FROM_HERE,
9912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&SafeBrowsingDatabaseManager::CheckDownloadUrlDone, this,
9922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   check));
9932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
9942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  check->need_get_hash = true;
9972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  check->prefix_hits.clear();
9982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  check->prefix_hits = prefix_hits;
9992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(
10002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      BrowserThread::IO, FROM_HERE,
10012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
10022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::CheckExtensionIDsOnSBThread(
10052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check) {
100690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK_EQ(base::MessageLoop::current(),
100790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            safe_browsing_thread_->message_loop());
10082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<SBPrefix> prefixes;
10102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::vector<SBFullHash>::iterator it = check->full_hashes.begin();
10112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       it != check->full_hashes.end(); ++it) {
10122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    prefixes.push_back((*it).prefix);
10132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  database_->ContainsExtensionPrefixes(prefixes, &check->prefix_hits);
10152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (check->prefix_hits.empty()) {
10172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // No matches for any extensions.
10182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
10192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::IO,
10202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&SafeBrowsingDatabaseManager::SafeBrowsingCheckDone, this,
10222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   check));
10232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
10242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Some prefixes matched, we need to ask Google whether they're legit.
10252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    check->need_get_hash = true;
10262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostTask(
10272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::IO,
10282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        FROM_HERE,
10292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&SafeBrowsingDatabaseManager::OnCheckDone, this, check));
10302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::TimeoutCallback(SafeBrowsingCheck* check) {
10342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
10352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(check);
10362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_)
10382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
10392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(checks_.find(check) != checks_.end());
10412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (check->client) {
10422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    check->client->OnSafeBrowsingResult(*check);
10432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    check->client = NULL;
10442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
10452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::CheckDownloadUrlDone(
10482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check) {
10492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(enable_download_protection_);
10502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SafeBrowsingCheckDone(check);
10512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::SafeBrowsingCheckDone(
10542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check) {
10552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
10562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(check);
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!enabled_)
10592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
10602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VLOG(1) << "SafeBrowsingCheckDone";
10622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(checks_.find(check) != checks_.end());
10632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (check->client)
10642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    check->client->OnSafeBrowsingResult(*check);
10652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checks_.erase(check);
10662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  delete check;
10672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
10682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SafeBrowsingDatabaseManager::StartSafeBrowsingCheck(
10702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SafeBrowsingCheck* check,
10712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Closure& task) {
10722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
10732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  check->timeout_factory_.reset(
10742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      new base::WeakPtrFactory<SafeBrowsingDatabaseManager>(this));
10752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  checks_.insert(check);
10762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task);
10782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
107990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
10802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&SafeBrowsingDatabaseManager::TimeoutCallback,
10812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 check->timeout_factory_->GetWeakPtr(), check),
10822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      check_timeout_);
10832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1084