1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/safe_browsing/safe_browsing_service.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/callback.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/command_line.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/path_service.h"
11dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "base/stl_util-inl.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/threading/thread_restrictions.h"
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/metrics/metrics_service.h"
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h"
1721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile_manager.h"
1821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/safe_browsing/malware_details.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/safe_browsing/protocol_manager.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/safe_browsing/safe_browsing_database.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/tab_contents/tab_util.h"
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_constants.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_paths.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/chrome_switches.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/url_constants.h"
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/tab_contents.h"
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/registry_controlled_domain.h"
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "net/url_request/url_request_context_getter.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/installer/util/browser_distribution.h"
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsennamespace {
383f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The default URL prefix where browser fetches chunk updates, hashes,
4021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// and reports safe browsing hits.
413f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenconst char* const kSbDefaultInfoURLPrefix =
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    "http://safebrowsing.clients.google.com/safebrowsing";
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// The default URL prefix where browser fetches MAC client key and reports
4521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// malware details.
463f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenconst char* const kSbDefaultMacKeyURLPrefix =
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    "https://sb-ssl.google.com/safebrowsing";
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
49dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// When download url check takes this long, client's callback will be called
50dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// without waiting for the result.
51dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst int64 kDownloadUrlCheckTimeoutMs = 10000;
52dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
53dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// Similar to kDownloadUrlCheckTimeoutMs, but for download hash checks.
54dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenconst int64 kDownloadHashCheckTimeoutMs = 10000;
55dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// TODO(lzheng): Replace this with Profile* ProfileManager::GetDefaultProfile().
573f50c38dc070f4bb515c1b64450dae14f316474eKristian MonsenProfile* GetDefaultProfile() {
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath user_data_dir;
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ProfileManager* profile_manager = g_browser_process->profile_manager();
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return profile_manager->GetDefaultProfile(user_data_dir);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
643f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Records disposition information about the check.  |hit| should be
653f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// |true| if there were any prefix hits in |full_hashes|.
663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid RecordGetHashCheckStatus(
67dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    bool hit,
68dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    bool is_download,
69dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const std::vector<SBFullHashResult>& full_hashes) {
703f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  SafeBrowsingProtocolManager::ResultType result;
713f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  if (full_hashes.empty()) {
723f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_EMPTY;
733f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  } else if (hit) {
743f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_HIT;
753f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  } else {
763f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    result = SafeBrowsingProtocolManager::GET_HASH_FULL_HASH_MISS;
773f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  }
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SafeBrowsingProtocolManager::RecordGetHashResult(is_download, result);
793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}
803f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
813f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen}  // namespace
823f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
83201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// static
84201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochSafeBrowsingServiceFactory* SafeBrowsingService::factory_ = NULL;
85201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
86201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// The default SafeBrowsingServiceFactory.  Global, made a singleton so we
87201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch// don't leak it.
88201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdochclass SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
89201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch public:
90201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  virtual SafeBrowsingService* CreateSafeBrowsingService() {
91201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    return new SafeBrowsingService();
92201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
93201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
94201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch private:
9521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>;
96201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
97201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  SafeBrowsingServiceFactoryImpl() { }
98201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
99201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl);
100201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch};
101201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
10221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<SafeBrowsingServiceFactoryImpl>
10321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    g_safe_browsing_service_factory_impl(base::LINKER_INITIALIZED);
10421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
105731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickstruct SafeBrowsingService::WhiteListedEntry {
106731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int render_process_host_id;
107731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int render_view_id;
108731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::string domain;
109731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  UrlCheckResult result;
110731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick};
111731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
112513209b27ff55e2841eac0e4120199c23acce758Ben MurdochSafeBrowsingService::UnsafeResource::UnsafeResource()
113513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : resource_type(ResourceType::MAIN_FRAME),
114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      threat_type(SAFE),
115513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      client(NULL),
116513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      render_process_host_id(-1),
117513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      render_view_id(-1) {
118513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
119513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
120513209b27ff55e2841eac0e4120199c23acce758Ben MurdochSafeBrowsingService::UnsafeResource::~UnsafeResource() {}
121513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
122513209b27ff55e2841eac0e4120199c23acce758Ben MurdochSafeBrowsingService::SafeBrowsingCheck::SafeBrowsingCheck()
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : full_hash(NULL),
124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      client(NULL),
125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      need_get_hash(false),
126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      result(SAFE),
127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      is_download(false),
128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      timeout_task(NULL) {
129513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
130513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
131513209b27ff55e2841eac0e4120199c23acce758Ben MurdochSafeBrowsingService::SafeBrowsingCheck::~SafeBrowsingCheck() {}
132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::Client::OnSafeBrowsingResult(
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const SafeBrowsingCheck& check) {
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!check.urls.empty()) {
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DCHECK(!check.full_hash.get());
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!check.is_download) {
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      DCHECK_EQ(1U, check.urls.size());
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      OnBrowseUrlCheckResult(check.urls[0], check.result);
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      OnDownloadUrlCheckResult(check.urls, check.result);
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else if (check.full_hash.get()) {
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    OnDownloadHashCheckResult(
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        safe_browsing_util::SBFullHashToString(*check.full_hash),
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        check.result);
148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  } else {
149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    NOTREACHED();
150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
153201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch/* static */
154201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben MurdochSafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() {
155201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!factory_)
15621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    factory_ = g_safe_browsing_service_factory_impl.Pointer();
157201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  return factory_->CreateSafeBrowsingService();
158201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch}
159201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSafeBrowsingService::SafeBrowsingService()
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : database_(NULL),
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      protocol_manager_(NULL),
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      enabled_(false),
16421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      enable_download_protection_(false),
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      enable_csd_whitelist_(false),
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      update_in_progress_(false),
1673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      database_update_in_progress_(false),
168dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      closing_database_(false),
169dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      download_urlcheck_timeout_ms_(kDownloadUrlCheckTimeoutMs),
170dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      download_hashcheck_timeout_ms_(kDownloadHashCheckTimeoutMs) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::Initialize() {
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Get the profile's preference for SafeBrowsing.
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrefService* pref_service = GetDefaultProfile()->GetPrefs();
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled))
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Start();
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::ShutDown() {
181731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
182731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &SafeBrowsingService::OnIOShutdown));
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SafeBrowsingService::CanCheckUrl(const GURL& url) const {
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return url.SchemeIs(chrome::kFtpScheme) ||
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         url.SchemeIs(chrome::kHttpScheme) ||
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         url.SchemeIs(chrome::kHttpsScheme);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Only report SafeBrowsing related stats when UMA is enabled and
19372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// safe browsing is enabled.
19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SafeBrowsingService::CanReportStats() const {
19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  const MetricsService* metrics = g_browser_process->metrics_service();
19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  const PrefService* pref_service = GetDefaultProfile()->GetPrefs();
19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return metrics && metrics->reporting_active() &&
19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      pref_service && pref_service->GetBoolean(prefs::kSafeBrowsingEnabled);
19972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
20072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
20172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Binhash verification is only enabled for UMA users for now.
20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbool SafeBrowsingService::DownloadBinHashNeeded() const {
20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return enable_download_protection_ && CanReportStats();
20472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
20572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool SafeBrowsingService::CheckDownloadUrl(const std::vector<GURL>& url_chain,
20721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                           Client* client) {
20821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
20921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!enabled_ || !enable_download_protection_)
21021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return true;
21121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
21221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // We need to check the database for url prefix, and later may fetch the url
21321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // from the safebrowsing backends. These need to be asynchronous.
21421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SafeBrowsingCheck* check = new SafeBrowsingCheck();
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  check->urls = url_chain;
216dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  StartDownloadCheck(
217dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      check,
218dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      client,
219dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NewRunnableMethod(this,
220dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        &SafeBrowsingService::CheckDownloadUrlOnSBThread,
221dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        check),
222dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      download_urlcheck_timeout_ms_);
223dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return false;
224dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
22521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
226dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool SafeBrowsingService::CheckDownloadHash(const std::string& full_hash,
227dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                            Client* client) {
228dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
229dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!full_hash.empty());
230dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!enabled_ || !enable_download_protection_ || full_hash.empty())
231dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return true;
23221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
233dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // We need to check the database for url prefix, and later may fetch the url
234dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // from the safebrowsing backends. These need to be asynchronous.
235dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SafeBrowsingCheck* check = new SafeBrowsingCheck();
236dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->full_hash.reset(new SBFullHash);
237dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  safe_browsing_util::StringToSBFullHash(full_hash, check->full_hash.get());
238dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  StartDownloadCheck(
239dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      check,
240dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      client,
241dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NewRunnableMethod(this,
242dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        &SafeBrowsingService::CheckDownloadHashOnSBThread,
243dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                        check),
244dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      download_hashcheck_timeout_ms_);
24521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
24621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
24721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool SafeBrowsingService::MatchCsdWhitelistUrl(const GURL& url) {
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!enabled_ || !enable_csd_whitelist_ || !MakeDatabaseAvailable()) {
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // There is something funky going on here -- for example, perhaps the user
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // has not restarted since enabling metrics reporting, so we haven't
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // enabled the csd whitelist yet.  Just to be safe we return true in this
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // case.
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return database_->ContainsCsdWhitelistedUrl(url);
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
26021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool SafeBrowsingService::CheckBrowseUrl(const GURL& url,
26121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                         Client* client) {
262731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!enabled_)
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!CanCheckUrl(url))
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
269dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const base::TimeTicks start = base::TimeTicks::Now();
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!MakeDatabaseAvailable()) {
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    QueuedCheck check;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    check.client = client;
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    check.url = url;
274dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check.start = start;
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    queued_checks_.push_back(check);
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string list;
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<SBPrefix> prefix_hits;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<SBFullHashResult> full_hits;
28221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  bool prefix_match =
28321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      database_->ContainsBrowseUrl(url, &list, &prefix_hits,
28421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                   &full_hits,
28521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                   protocol_manager_->last_update());
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
287dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  UMA_HISTOGRAM_TIMES("SB2.FilterCheck", base::TimeTicks::Now() - start);
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!prefix_match)
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;  // URL is okay.
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Needs to be asynchronous, since we could be in the constructor of a
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ResourceDispatcherHost event handler which can't pause there.
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SafeBrowsingCheck* check = new SafeBrowsingCheck();
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  check->urls.push_back(url);
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  check->client = client;
297dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->result = SAFE;
298dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->is_download = false;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  check->need_get_hash = full_hits.empty();
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  check->prefix_hits.swap(prefix_hits);
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  check->full_hits.swap(full_hits);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  checks_.insert(check);
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
304731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
305731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::CancelCheck(Client* client) {
312731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (CurrentChecks::iterator i = checks_.begin(); i != checks_.end(); ++i) {
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We can't delete matching checks here because the db thread has a copy of
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the pointer.  Instead, we simply NULL out the client, and when the db
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // thread calls us back, we'll clean up the check.
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if ((*i)->client == client)
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (*i)->client = NULL;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Scan the queued clients store. Clients may be here if they requested a URL
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // check before the database has finished loading.
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::deque<QueuedCheck>::iterator it(queued_checks_.begin());
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != queued_checks_.end(); ) {
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // In this case it's safe to delete matches entirely since nothing has a
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // pointer to them.
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (it->client == client)
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      it = queued_checks_.erase(it);
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++it;
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SafeBrowsingService::DisplayBlockingPage(
33572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const GURL& url,
33672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const GURL& original_url,
33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const std::vector<GURL>& redirect_urls,
33872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    ResourceType::Type resource_type,
33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    UrlCheckResult result,
34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    Client* client,
34172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int render_process_host_id,
34272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    int render_view_id) {
343731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Check if the user has already ignored our warning for this render_view
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // and domain.
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const WhiteListedEntry& entry = white_listed_entries_[i];
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry.render_process_host_id == render_process_host_id &&
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        entry.render_view_id == render_view_id &&
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        entry.result == result &&
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        entry.domain ==
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        net::RegistryControlledDomainService::GetDomainAndRegistry(url)) {
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          this, &SafeBrowsingService::NotifyClientBlockingComplete,
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          client, true));
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UnsafeResource resource;
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource.url = url;
3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  resource.original_url = original_url;
36472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  resource.redirect_urls = redirect_urls;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource.resource_type = resource_type;
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource.threat_type= result;
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource.client = client;
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource.render_process_host_id = render_process_host_id;
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  resource.render_view_id = render_view_id;
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The blocking page must be created from the UI thread.
372731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
373731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::UI, FROM_HERE,
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          this, &SafeBrowsingService::DoDisplayBlockingPage, resource));
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::HandleGetHashResults(
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SafeBrowsingCheck* check,
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<SBFullHashResult>& full_hashes,
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool can_cache) {
382731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
383dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
384dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!enabled_)
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
387dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // If the service has been shut down, |check| should have been deleted.
388dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(checks_.find(check) != checks_.end());
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
390dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // |start| is set before calling |GetFullHash()|, which should be
391dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // the only path which gets to here.
392dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(!check->start.is_null());
393dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  UMA_HISTOGRAM_LONG_TIMES("SB2.Network",
394dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                           base::TimeTicks::Now() - check->start);
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<SBPrefix> prefixes = check->prefix_hits;
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OnHandleGetHashResults(check, full_hashes);  // 'check' is deleted here.
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (can_cache && MakeDatabaseAvailable()) {
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Cache the GetHash results in memory:
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    database_->CacheHashResults(prefixes, full_hashes);
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::HandleChunk(const std::string& list,
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                      SBChunkList* chunks) {
407731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(enabled_);
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this, &SafeBrowsingService::HandleChunkForDatabase, list, chunks));
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::HandleChunkDelete(
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SBChunkDelete>* chunk_deletes) {
415731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(enabled_);
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this, &SafeBrowsingService::DeleteChunks, chunk_deletes));
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::UpdateStarted() {
422731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(enabled_);
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!update_in_progress_);
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  update_in_progress_ = true;
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this, &SafeBrowsingService::GetAllChunksFromDatabase));
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::UpdateFinished(bool update_succeeded) {
431731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(enabled_);
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (update_in_progress_) {
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    update_in_progress_ = false;
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NewRunnableMethod(this,
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          &SafeBrowsingService::DatabaseUpdateFinished,
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          update_succeeded));
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SafeBrowsingService::IsUpdateInProgress() const {
443731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return update_in_progress_;
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnBlockingPageDone(
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<UnsafeResource>& resources,
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    bool proceed) {
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       iter != resources.end(); ++iter) {
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const UnsafeResource& resource = *iter;
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NotifyClientBlockingComplete(resource.client, proceed);
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (proceed) {
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Whitelist this domain and warning type for the given tab.
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      WhiteListedEntry entry;
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry.render_process_host_id = resource.render_process_host_id;
459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry.render_view_id = resource.render_view_id;
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry(
461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            resource.url);
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      entry.result = resource.threat_type;
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      white_listed_entries_.push_back(entry);
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnNewMacKeys(const std::string& client_key,
469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const std::string& wrapped_key) {
470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrefService* prefs = g_browser_process->local_state();
471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (prefs) {
472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefs->SetString(prefs::kSafeBrowsingClientKey, client_key);
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    prefs->SetString(prefs::kSafeBrowsingWrappedKey, wrapped_key);
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnEnable(bool enabled) {
478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (enabled)
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Start();
480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  else
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ShutDown();
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::RegisterPrefs(PrefService* prefs) {
486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->RegisterStringPref(prefs::kSafeBrowsingClientKey, "");
487c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  prefs->RegisterStringPref(prefs::kSafeBrowsingWrappedKey, "");
488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::CloseDatabase() {
491731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Cases to avoid:
494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //  * If |closing_database_| is true, continuing will queue up a second
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    request, |closing_database_| will be reset after handling the first
496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    request, and if any functions on the db thread recreate the database, we
497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    could start using it on the IO thread and then have the second request
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    handler delete it out from under us.
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //  * If |database_| is NULL, then either no creation request is in flight, in
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    which case we don't need to do anything, or one is in flight, in which
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    case the database will be recreated before our deletion request is
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    handled, and could be used on the IO thread in that time period, leading
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    to the same problem as above.
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //  * If |queued_checks_| is non-empty and |database_| is non-NULL, we're
505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    about to be called back (in DatabaseLoadComplete()).  This will call
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    CheckUrl(), which will want the database.  Closing the database here
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    would lead to an infinite loop in DatabaseLoadComplete(), and even if it
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //    didn't, it would be pointless since we'd just want to recreate.
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The first two cases above are handled by checking DatabaseAvailable().
511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!DatabaseAvailable() || !queued_checks_.empty())
512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  closing_database_ = true;
515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (safe_browsing_thread_.get()) {
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        NewRunnableMethod(this, &SafeBrowsingService::OnCloseDatabase));
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::ResetDatabase() {
522731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(enabled_);
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      this, &SafeBrowsingService::OnResetDatabase));
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
528dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::LogPauseDelay(base::TimeDelta time) {
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSafeBrowsingService::~SafeBrowsingService() {
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We should have already been shut down.  If we're still enabled, then the
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // database isn't going to be closed properly, which could lead to corruption.
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!enabled_);
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnIOInitialize(
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& client_key,
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& wrapped_key,
541ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    net::URLRequestContextGetter* request_context_getter) {
542731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  enabled_ = true;
54421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MakeDatabaseAvailable();
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // On Windows, get the safe browsing client name from the browser
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // distribution classes in installer util. These classes don't yet have
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // an analog on non-Windows builds so just keep the name specified here.
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string client_name(dist->GetSafeBrowsingName());
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(GOOGLE_CHROME_BUILD)
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string client_name("googlechrome");
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string client_name("chromium");
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CommandLine* cmdline = CommandLine::ForCurrentProcess();
5613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  bool disable_auto_update =
5623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
5633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string info_url_prefix =
565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cmdline->HasSwitch(switches::kSbInfoURLPrefix) ?
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cmdline->GetSwitchValueASCII(switches::kSbInfoURLPrefix) :
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kSbDefaultInfoURLPrefix;
568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string mackey_url_prefix =
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cmdline->HasSwitch(switches::kSbMacKeyURLPrefix) ?
570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      cmdline->GetSwitchValueASCII(switches::kSbMacKeyURLPrefix) :
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      kSbDefaultMacKeyURLPrefix;
572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(!protocol_manager_);
57421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  protocol_manager_ =
57521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      SafeBrowsingProtocolManager::Create(this,
57621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                          client_name,
57721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                          client_key,
57821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                          wrapped_key,
57921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                          request_context_getter,
58021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                          info_url_prefix,
58121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                          mackey_url_prefix,
58221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                          disable_auto_update);
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  protocol_manager_->Initialize();
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnIOShutdown() {
588731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!enabled_)
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  enabled_ = false;
593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This cancels all in-flight GetHash requests.
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete protocol_manager_;
596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  protocol_manager_ = NULL;
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
598dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Delete queued checks, calling back any clients with 'SAFE'.
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If we don't do this here we may fail to close the database below.
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!queued_checks_.empty()) {
601dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    QueuedCheck queued = queued_checks_.front();
602dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (queued.client) {
603dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      SafeBrowsingCheck sb_check;
604ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      sb_check.urls.push_back(queued.url);
605dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      sb_check.client = queued.client;
606dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      sb_check.result = SAFE;
607dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      queued.client->OnSafeBrowsingResult(sb_check);
608dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    queued_checks_.pop_front();
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Close the database.  We don't simply DeleteSoon() because if a close is
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // already pending, we'll double-free, and we don't set |database_| to NULL
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // because if there is still anything running on the db thread, it could
615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // create a new database object (via GetDatabase()) that would then leak.
616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CloseDatabase();
617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Flush the database thread. Any in-progress database check results will be
619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // ignored and cleaned up below.
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  //
621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Note that to avoid leaking the database, we rely on the fact that no new
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // tasks will be added to the db thread between the call above and this one.
623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // See comments on the declaration of |safe_browsing_thread_|.
62472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  {
62572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // A ScopedAllowIO object is required to join the thread when calling Stop.
62672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // See http://crbug.com/72696.
62772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join;
62872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    safe_browsing_thread_.reset();
62972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
631dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Delete pending checks, calling back any clients with 'SAFE'.  We have
632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // to do this after the db thread returns because methods on it can have
633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // copies of these pointers, so deleting them might lead to accessing garbage.
634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (CurrentChecks::iterator it = checks_.begin();
635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it != checks_.end(); ++it) {
636dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SafeBrowsingCheck* check = *it;
637dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (check->client) {
638dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      check->result = SAFE;
639dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      check->client->OnSafeBrowsingResult(*check);
640dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
641dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (check->timeout_task)
642dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      check->timeout_task->Cancel();
643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
644dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  STLDeleteElements(&checks_);
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gethash_requests_.clear();
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SafeBrowsingService::DatabaseAvailable() const {
65072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(database_lock_);
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return !closing_database_ && (database_ != NULL);
652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SafeBrowsingService::MakeDatabaseAvailable() {
655731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(enabled_);
657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (DatabaseAvailable())
658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE,
660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &SafeBrowsingService::GetDatabase));
661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
664c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSafeBrowsingDatabase* SafeBrowsingService::GetDatabase() {
6653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
666c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (database_)
667c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return database_;
668c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
669c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  FilePath path;
670c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
671c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(result);
67221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  path = path.Append(chrome::kSafeBrowsingBaseFilename);
673c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
674dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const base::TimeTicks before = base::TimeTicks::Now();
67521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
67621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  SafeBrowsingDatabase* database =
677ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      SafeBrowsingDatabase::Create(enable_download_protection_,
678ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                   enable_csd_whitelist_);
67921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
680c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  database->Init(path);
681c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
682c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Acquiring the lock here guarantees correct ordering between the writes to
683c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the new database object above, and the setting of |databse_| below.
68472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(database_lock_);
685c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    database_ = database;
686c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
687c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
688731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
689731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
690c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &SafeBrowsingService::DatabaseLoadComplete));
691c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
692dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  UMA_HISTOGRAM_TIMES("SB2.DatabaseOpen", base::TimeTicks::Now() - before);
693c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return database_;
694c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
695c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
696c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnCheckDone(SafeBrowsingCheck* check) {
697731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
698c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
699dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!enabled_)
700c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
701c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
702dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // If the service has been shut down, |check| should have been deleted.
703dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(checks_.find(check) != checks_.end());
704dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
705c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (check->client && check->need_get_hash) {
706c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // We have a partial match so we need to query Google for the full hash.
707c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Clean up will happen in HandleGetHashResults.
708c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
709c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // See if we have a GetHash request already in progress for this particular
710c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // prefix. If so, we just append ourselves to the list of interested parties
711c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // when the results arrive. We only do this for checks involving one prefix,
712c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // since that is the common case (multiple prefixes will issue the request
713c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // as normal).
714c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (check->prefix_hits.size() == 1) {
715c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SBPrefix prefix = check->prefix_hits[0];
716c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetHashRequests::iterator it = gethash_requests_.find(prefix);
717c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (it != gethash_requests_.end()) {
718c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // There's already a request in progress.
719c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        it->second.push_back(check);
720c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return;
721c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
722c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
723c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // No request in progress, so we're the first for this prefix.
724c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetHashRequestors requestors;
725c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      requestors.push_back(check);
726c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gethash_requests_[prefix] = requestors;
727c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
728c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
729c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Reset the start time so that we can measure the network time without the
730c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // database time.
731dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check->start = base::TimeTicks::Now();
732c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    protocol_manager_->GetFullHash(check, check->prefix_hits);
733c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
7343f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    // We may have cached results for previous GetHash queries.  Since
7353f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    // this data comes from cache, don't histogram hits.
736c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    HandleOneCheck(check, check->full_hits);
737c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
738c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
739c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
740c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::GetAllChunksFromDatabase() {
7413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
7423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
743c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool database_error = true;
744c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::vector<SBListChunkRanges> lists;
7453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(!database_update_in_progress_);
7463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  database_update_in_progress_ = true;
747c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetDatabase();  // This guarantees that |database_| is non-NULL.
7483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (database_->UpdateStarted(&lists)) {
749c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    database_error = false;
750c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
751c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    database_->UpdateFinished(false);
752c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
753c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
754731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
755731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
756c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(
757c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          this, &SafeBrowsingService::OnGetAllChunksFromDatabase, lists,
758c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          database_error));
759c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
760c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
761c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnGetAllChunksFromDatabase(
762c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<SBListChunkRanges>& lists, bool database_error) {
763731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
764c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (enabled_)
765c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    protocol_manager_->OnGetChunksComplete(lists, database_error);
766c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
767c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
768c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnChunkInserted() {
769731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
770c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (enabled_)
771c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    protocol_manager_->OnChunkInserted();
772c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
773c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
774c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::DatabaseLoadComplete() {
775731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
776c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!enabled_)
777c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
778c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
779c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  HISTOGRAM_COUNTS("SB.QueueDepth", queued_checks_.size());
780c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (queued_checks_.empty())
781c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
782c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
783c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the database isn't already available, calling CheckUrl() in the loop
784c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // below will add the check back to the queue, and we'll infinite-loop.
785c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(DatabaseAvailable());
786c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (!queued_checks_.empty()) {
787c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    QueuedCheck check = queued_checks_.front();
788dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    DCHECK(!check.start.is_null());
789dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    HISTOGRAM_TIMES("SB.QueueDelay", base::TimeTicks::Now() - check.start);
790c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If CheckUrl() determines the URL is safe immediately, it doesn't call the
791c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // client's handler function (because normally it's being directly called by
792c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // the client).  Since we're not the client, we have to convey this result.
793dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (check.client && CheckBrowseUrl(check.url, check.client)) {
794dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      SafeBrowsingCheck sb_check;
795ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      sb_check.urls.push_back(check.url);
796dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      sb_check.client = check.client;
797dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      sb_check.result = SAFE;
798dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      check.client->OnSafeBrowsingResult(sb_check);
799dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
800c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    queued_checks_.pop_front();
801c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
802c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
803c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
804c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::HandleChunkForDatabase(
80521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    const std::string& list_name, SBChunkList* chunks) {
8063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
807c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (chunks) {
808c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetDatabase()->InsertChunks(list_name, *chunks);
809c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete chunks;
810c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
811731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
812731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
813c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(this, &SafeBrowsingService::OnChunkInserted));
814c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
815c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
816c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::DeleteChunks(
817c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<SBChunkDelete>* chunk_deletes) {
8183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
819c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (chunk_deletes) {
820c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GetDatabase()->DeleteChunks(*chunk_deletes);
821c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    delete chunk_deletes;
822c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
823c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
824c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
825c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSafeBrowsingService::UrlCheckResult SafeBrowsingService::GetResultFromListname(
826c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::string& list_name) {
827c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (safe_browsing_util::IsPhishingList(list_name)) {
828c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return URL_PHISHING;
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
830c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
831c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (safe_browsing_util::IsMalwareList(list_name)) {
832c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return URL_MALWARE;
833c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
834c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
83521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (safe_browsing_util::IsBadbinurlList(list_name)) {
836dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return BINARY_MALWARE_URL;
837dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
838dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
839dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (safe_browsing_util::IsBadbinhashList(list_name)) {
840dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return BINARY_MALWARE_HASH;
84121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
84221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
843513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DVLOG(1) << "Unknown safe browsing list " << list_name;
844dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return SAFE;
845c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
846c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
847c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::NotifyClientBlockingComplete(Client* client,
848c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                                       bool proceed) {
849c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  client->OnBlockingPageComplete(proceed);
850c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
851c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
852c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) {
8533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
854c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetDatabase()->UpdateFinished(update_succeeded);
8553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK(database_update_in_progress_);
8563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  database_update_in_progress_ = false;
857c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
858c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
859c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::Start() {
860ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
861c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(!safe_browsing_thread_.get());
862c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  safe_browsing_thread_.reset(new base::Thread("Chrome_SafeBrowsingThread"));
863c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!safe_browsing_thread_->Start())
864c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
865c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
866c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Retrieve client MAC keys.
867c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrefService* local_state = g_browser_process->local_state();
868ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(local_state);
869c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  std::string client_key, wrapped_key;
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (local_state) {
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    client_key =
872c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      local_state->GetString(prefs::kSafeBrowsingClientKey);
873c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    wrapped_key =
874c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      local_state->GetString(prefs::kSafeBrowsingWrappedKey);
875c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
876c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
877c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We will issue network fetches using the default profile's request context.
878ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scoped_refptr<net::URLRequestContextGetter> request_context_getter(
879513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      GetDefaultProfile()->GetRequestContext());
880c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
881ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CommandLine* cmdline = CommandLine::ForCurrentProcess();
882ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  enable_download_protection_ =
883ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
884ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
885ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We only download the csd-whitelist if client-side phishing detection is
886ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // enabled and if the user has opted in with stats collection.  Note: we
887ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // cannot check whether the metrics_service() object is created because it
888ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // may be initialized after this method is called.
889ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#ifdef OS_CHROMEOS
890ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Client-side detection is disabled on ChromeOS for now, so don't bother
891ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // downloading the whitelist.
892ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  enable_csd_whitelist_ = false;
893ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else
894ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  enable_csd_whitelist_ =
895ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      (!cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection) &&
896ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       local_state && local_state->GetBoolean(prefs::kMetricsReportingEnabled));
897ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
898ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
899731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BrowserThread::PostTask(
900731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
901c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(
902c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          this, &SafeBrowsingService::OnIOInitialize, client_key, wrapped_key,
903c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          request_context_getter));
904c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
905c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
906c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnCloseDatabase() {
9073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
908c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(closing_database_);
909c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
910c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Because |closing_database_| is true, nothing on the IO thread will be
911c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // accessing the database, so it's safe to delete and then NULL the pointer.
912c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  delete database_;
913c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  database_ = NULL;
914c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
915c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Acquiring the lock here guarantees correct ordering between the resetting
916c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // of |database_| above and of |closing_database_| below, which ensures there
917c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // won't be a window during which the IO thread falsely believes the database
918c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is available.
91972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(database_lock_);
920c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  closing_database_ = false;
921c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
922c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
923c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnResetDatabase() {
9243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
925c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetDatabase()->ResetDatabase();
926c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
927c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
928c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::CacheHashResults(
929c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::vector<SBPrefix>& prefixes,
930c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::vector<SBFullHashResult>& full_hashes) {
9313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
932c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetDatabase()->CacheHashResults(prefixes, full_hashes);
933c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
934c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
935c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::OnHandleGetHashResults(
936c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SafeBrowsingCheck* check,
937c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<SBFullHashResult>& full_hashes) {
938731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
939dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  bool is_download = check->is_download;
940c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SBPrefix prefix = check->prefix_hits[0];
941c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetHashRequests::iterator it = gethash_requests_.find(prefix);
942c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (check->prefix_hits.size() > 1 || it == gethash_requests_.end()) {
9433f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    const bool hit = HandleOneCheck(check, full_hashes);
944dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    RecordGetHashCheckStatus(hit, is_download, full_hashes);
945c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
946c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
947c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9483f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // Call back all interested parties, noting if any has a hit.
949c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetHashRequestors& requestors = it->second;
9503f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  bool hit = false;
951c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (GetHashRequestors::iterator r = requestors.begin();
952c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       r != requestors.end(); ++r) {
9533f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    if (HandleOneCheck(*r, full_hashes))
9543f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen      hit = true;
955c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
956dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  RecordGetHashCheckStatus(hit, is_download, full_hashes);
957c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
958c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  gethash_requests_.erase(it);
959c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
960c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
9613f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenbool SafeBrowsingService::HandleOneCheck(
962c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SafeBrowsingCheck* check,
963c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const std::vector<SBFullHashResult>& full_hashes) {
964731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
965dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(check);
9663f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
9673f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // Always calculate the index, for recording hits.
968dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  int index = -1;
969ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!check->urls.empty()) {
970ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (size_t i = 0; i < check->urls.size(); ++i) {
971ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      index = safe_browsing_util::GetUrlHashIndex(check->urls[i], full_hashes);
972ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (index != -1)
973ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        break;
974ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
975ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
976dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    index = safe_browsing_util::GetHashIndex(*(check->full_hash), full_hashes);
977ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
9783f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen
9793f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  // |client| is NULL if the request was cancelled.
980c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (check->client) {
981dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check->result = SAFE;
9823f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen    if (index != -1)
983dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      check->result = GetResultFromListname(full_hashes[index].list_name);
984c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
985dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SafeBrowsingCheckDone(check);
9863f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  return (index != -1);
987c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
988c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
989c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SafeBrowsingService::DoDisplayBlockingPage(
990c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const UnsafeResource& resource) {
991c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The tab might have been closed.
992c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabContents* wc =
993c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      tab_util::GetTabContentsByID(resource.render_process_host_id,
994c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   resource.render_view_id);
995c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
996c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!wc) {
997c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // The tab is gone and we did not have a chance at showing the interstitial.
998c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Just act as "Don't Proceed" was chosen.
999c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    std::vector<UnsafeResource> resources;
1000c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    resources.push_back(resource);
1001731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
1002731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO, FROM_HERE,
1003c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableMethod(
1004c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          this, &SafeBrowsingService::OnBlockingPageDone, resources, false));
1005c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1006c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1007c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1008dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (resource.threat_type != SafeBrowsingService::SAFE && CanReportStats()) {
1009c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL page_url = wc->GetURL();
1010c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    GURL referrer_url;
1011c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    NavigationEntry* entry = wc->controller().GetActiveEntry();
1012c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (entry)
1013c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      referrer_url = entry->referrer();
10143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    bool is_subresource = resource.resource_type != ResourceType::MAIN_FRAME;
10153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
10163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // When the malicious url is on the main frame, and resource.original_url
10173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // is not the same as the resource.url, that means we have a redirect from
10183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // resource.original_url to resource.url.
10193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Also, at this point, page_url points to the _previous_ page that we
10203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // were on. We replace page_url with resource.original_url and referrer
10213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // with page_url.
10223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!is_subresource &&
10233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        !resource.original_url.is_empty() &&
10243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        resource.original_url != resource.url) {
10253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      referrer_url = page_url;
10263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      page_url = resource.original_url;
10273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
1028dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    ReportSafeBrowsingHit(resource.url, page_url, referrer_url, is_subresource,
1029ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                          resource.threat_type, std::string() /* post_data */);
1030c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
1031c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1032c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
1033c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
1034c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1035dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// A safebrowsing hit is sent after a blocking page for malware/phishing
1036dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// or after the warning dialog for download urls, only for UMA users.
1037731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid SafeBrowsingService::ReportSafeBrowsingHit(
1038731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GURL& malicious_url,
1039731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GURL& page_url,
1040731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const GURL& referrer_url,
1041731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    bool is_subresource,
1042ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SafeBrowsingService::UrlCheckResult threat_type,
1043ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& post_data) {
1044dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1045dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!CanReportStats())
1046dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
1047dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1048dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  BrowserThread::PostTask(
1049dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      BrowserThread::IO, FROM_HERE,
1050dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NewRunnableMethod(
1051dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          this,
1052dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          &SafeBrowsingService::ReportSafeBrowsingHitOnIOThread,
1053dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          malicious_url,
1054dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          page_url,
1055dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          referrer_url,
1056dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          is_subresource,
1057ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          threat_type,
1058ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          post_data));
1059dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1060dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1061dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::ReportSafeBrowsingHitOnIOThread(
1062dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const GURL& malicious_url,
1063dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const GURL& page_url,
1064dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const GURL& referrer_url,
1065dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    bool is_subresource,
1066ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SafeBrowsingService::UrlCheckResult threat_type,
1067ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& post_data) {
1068731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1069c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!enabled_)
1070c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1071c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1072513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url
1073513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch           << " " << referrer_url << " " << is_subresource << " "
1074513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch           << threat_type;
1075731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  protocol_manager_->ReportSafeBrowsingHit(malicious_url, page_url,
1076731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                           referrer_url, is_subresource,
1077ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                           threat_type, post_data);
1078c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
107921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
1080dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// If the user had opted-in to send MalwareDetails, this gets called
1081ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// when the report is ready.
1082ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SafeBrowsingService::SendSerializedMalwareDetails(
1083ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::string& serialized) {
108421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1085ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!serialized.empty()) {
108621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    DVLOG(1) << "Sending serialized malware details.";
1087ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    protocol_manager_->ReportMalwareDetails(serialized);
108821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
108921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
1090dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1091dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::CheckDownloadHashOnSBThread(
1092dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    SafeBrowsingCheck* check) {
1093dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
1094dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(enable_download_protection_);
1095dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1096dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!database_->ContainsDownloadHashPrefix(check->full_hash->prefix)) {
1097dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Good, we don't have hash for this url prefix.
1098dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check->result = SAFE;
1099dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    BrowserThread::PostTask(
1100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        BrowserThread::IO, FROM_HERE,
1101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        NewRunnableMethod(this,
1102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                          &SafeBrowsingService::CheckDownloadHashDone,
1103dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                          check));
1104dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
1105dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
1106dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1107dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->need_get_hash = true;
1108dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->prefix_hits.push_back(check->full_hash->prefix);
1109dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  BrowserThread::PostTask(
1110dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      BrowserThread::IO, FROM_HERE,
1111dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
1112dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1113dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1114dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::CheckDownloadUrlOnSBThread(SafeBrowsingCheck* check) {
1115dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(MessageLoop::current(), safe_browsing_thread_->message_loop());
1116dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(enable_download_protection_);
1117dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<SBPrefix> prefix_hits;
1119dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!database_->ContainsDownloadUrl(check->urls, &prefix_hits)) {
1121dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Good, we don't have hash for this url prefix.
1122dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check->result = SAFE;
1123dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    BrowserThread::PostTask(
1124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        BrowserThread::IO, FROM_HERE,
1125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        NewRunnableMethod(this,
1126dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                          &SafeBrowsingService::CheckDownloadUrlDone,
1127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                          check));
1128dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
1129dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
1130dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1131dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->need_get_hash = true;
1132dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->prefix_hits.clear();
1133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  check->prefix_hits = prefix_hits;
1134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  BrowserThread::PostTask(
1135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      BrowserThread::IO, FROM_HERE,
1136dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NewRunnableMethod(this, &SafeBrowsingService::OnCheckDone, check));
1137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::TimeoutCallback(SafeBrowsingCheck* check) {
1140dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(check);
1142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!enabled_)
1144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
1145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(checks_.find(check) != checks_.end());
1147dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK_EQ(check->result, SAFE);
1148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (check->client) {
1149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check->client->OnSafeBrowsingResult(*check);
1150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check->client = NULL;
1151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
1152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->timeout_task = NULL;
1153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::CheckDownloadUrlDone(SafeBrowsingCheck* check) {
1156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(enable_download_protection_);
1157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SafeBrowsingCheckDone(check);
1158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::CheckDownloadHashDone(SafeBrowsingCheck* check) {
1161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(enable_download_protection_);
1162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  SafeBrowsingCheckDone(check);
1163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::SafeBrowsingCheckDone(SafeBrowsingCheck* check) {
1166dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1167dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(check);
1168dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1169dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!enabled_)
1170dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
1171dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1172dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  VLOG(1) << "SafeBrowsingCheckDone: " << check->result;
1173dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(checks_.find(check) != checks_.end());
1174dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (check->client)
1175dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check->client->OnSafeBrowsingResult(*check);
1176dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (check->timeout_task)
1177dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    check->timeout_task->Cancel();
1178dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  checks_.erase(check);
1179dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  delete check;
1180dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1181dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1182dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid SafeBrowsingService::StartDownloadCheck(SafeBrowsingCheck* check,
1183dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                             Client* client,
1184dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                             CancelableTask* task,
1185dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                             int64 timeout_ms) {
1186dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1187dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->client = client;
1188dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->result = SAFE;
1189dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->is_download = true;
1190dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  check->timeout_task =
1191dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      NewRunnableMethod(this, &SafeBrowsingService::TimeoutCallback, check);
1192dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  checks_.insert(check);
1193dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1194dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  safe_browsing_thread_->message_loop()->PostTask(FROM_HERE, task);
1195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1196dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  MessageLoop::current()->PostDelayedTask(
1197dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      FROM_HERE, check->timeout_task, timeout_ms);
1198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
1199