safe_browsing_service.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/safe_browsing/safe_browsing_service.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/callback.h"
10#include "base/command_line.h"
11#include "base/debug/leak_tracker.h"
12#include "base/lazy_instance.h"
13#include "base/path_service.h"
14#include "base/prefs/pref_change_registrar.h"
15#include "base/prefs/pref_service.h"
16#include "base/stl_util.h"
17#include "base/string_util.h"
18#include "base/threading/thread.h"
19#include "base/threading/thread_restrictions.h"
20#include "chrome/browser/browser_process.h"
21#include "chrome/browser/metrics/metrics_service.h"
22#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
23#include "chrome/browser/profiles/profile.h"
24#include "chrome/browser/profiles/profile_manager.h"
25#include "chrome/browser/safe_browsing/client_side_detection_service.h"
26#include "chrome/browser/safe_browsing/database_manager.h"
27#include "chrome/browser/safe_browsing/download_protection_service.h"
28#include "chrome/browser/safe_browsing/malware_details.h"
29#include "chrome/browser/safe_browsing/ping_manager.h"
30#include "chrome/browser/safe_browsing/protocol_manager.h"
31#include "chrome/browser/safe_browsing/safe_browsing_database.h"
32#include "chrome/browser/safe_browsing/ui_manager.h"
33#include "chrome/common/chrome_constants.h"
34#include "chrome/common/chrome_notification_types.h"
35#include "chrome/common/chrome_paths.h"
36#include "chrome/common/chrome_switches.h"
37#include "chrome/common/pref_names.h"
38#include "chrome/common/startup_metric_utils.h"
39#include "chrome/common/url_constants.h"
40#include "content/public/browser/browser_thread.h"
41#include "content/public/browser/notification_service.h"
42#include "net/cookies/cookie_monster.h"
43#include "net/url_request/url_request_context.h"
44#include "net/url_request/url_request_context_getter.h"
45
46#if defined(OS_WIN)
47#include "chrome/installer/util/browser_distribution.h"
48#endif
49
50using content::BrowserThread;
51
52namespace {
53
54// Filename suffix for the cookie database.
55const base::FilePath::CharType kCookiesFile[] = FILE_PATH_LITERAL(" Cookies");
56
57// The default URL prefix where browser fetches chunk updates, hashes,
58// and reports safe browsing hits and malware details.
59const char* const kSbDefaultURLPrefix =
60    "https://safebrowsing.google.com/safebrowsing";
61
62// The backup URL prefix used when there are issues establishing a connection
63// with the server at the primary URL.
64const char* const kSbBackupConnectErrorURLPrefix =
65    "https://alt1-safebrowsing.google.com/safebrowsing";
66
67// The backup URL prefix used when there are HTTP-specific issues with the
68// server at the primary URL.
69const char* const kSbBackupHttpErrorURLPrefix =
70    "https://alt2-safebrowsing.google.com/safebrowsing";
71
72// The backup URL prefix used when there are local network specific issues.
73const char* const kSbBackupNetworkErrorURLPrefix =
74    "https://alt3-safebrowsing.google.com/safebrowsing";
75
76base::FilePath CookieFilePath() {
77  return base::FilePath(
78      SafeBrowsingService::GetBaseFilename().value() + kCookiesFile);
79}
80
81}  // namespace
82
83class SafeBrowsingURLRequestContextGetter
84    : public net::URLRequestContextGetter {
85 public:
86  explicit SafeBrowsingURLRequestContextGetter(
87      SafeBrowsingService* sb_service_);
88
89  // Implementation for net::UrlRequestContextGetter.
90  virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
91  virtual scoped_refptr<base::SingleThreadTaskRunner>
92      GetNetworkTaskRunner() const OVERRIDE;
93
94 protected:
95  virtual ~SafeBrowsingURLRequestContextGetter();
96
97 private:
98  SafeBrowsingService* const sb_service_;  // Owned by BrowserProcess.
99  scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
100
101  base::debug::LeakTracker<SafeBrowsingURLRequestContextGetter> leak_tracker_;
102};
103
104SafeBrowsingURLRequestContextGetter::SafeBrowsingURLRequestContextGetter(
105    SafeBrowsingService* sb_service)
106    : sb_service_(sb_service),
107      network_task_runner_(
108          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)) {
109}
110
111SafeBrowsingURLRequestContextGetter::~SafeBrowsingURLRequestContextGetter() {}
112
113net::URLRequestContext*
114SafeBrowsingURLRequestContextGetter::GetURLRequestContext() {
115  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
116  DCHECK(sb_service_->url_request_context_.get());
117
118  return sb_service_->url_request_context_.get();
119}
120
121scoped_refptr<base::SingleThreadTaskRunner>
122SafeBrowsingURLRequestContextGetter::GetNetworkTaskRunner() const {
123  return network_task_runner_;
124}
125
126// static
127SafeBrowsingServiceFactory* SafeBrowsingService::factory_ = NULL;
128
129// The default SafeBrowsingServiceFactory.  Global, made a singleton so we
130// don't leak it.
131class SafeBrowsingServiceFactoryImpl : public SafeBrowsingServiceFactory {
132 public:
133  virtual SafeBrowsingService* CreateSafeBrowsingService() OVERRIDE {
134    return new SafeBrowsingService();
135  }
136
137 private:
138  friend struct base::DefaultLazyInstanceTraits<SafeBrowsingServiceFactoryImpl>;
139
140  SafeBrowsingServiceFactoryImpl() { }
141
142  DISALLOW_COPY_AND_ASSIGN(SafeBrowsingServiceFactoryImpl);
143};
144
145static base::LazyInstance<SafeBrowsingServiceFactoryImpl>
146    g_safe_browsing_service_factory_impl = LAZY_INSTANCE_INITIALIZER;
147
148// static
149base::FilePath SafeBrowsingService::GetCookieFilePathForTesting() {
150  return CookieFilePath();
151}
152
153// static
154base::FilePath SafeBrowsingService::GetBaseFilename() {
155  base::FilePath path;
156  bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
157  DCHECK(result);
158  return path.Append(chrome::kSafeBrowsingBaseFilename);
159}
160
161
162// static
163SafeBrowsingService* SafeBrowsingService::CreateSafeBrowsingService() {
164  if (!factory_)
165    factory_ = g_safe_browsing_service_factory_impl.Pointer();
166  return factory_->CreateSafeBrowsingService();
167}
168
169SafeBrowsingService::SafeBrowsingService()
170    : protocol_manager_(NULL),
171      ping_manager_(NULL),
172      enabled_(false) {
173}
174
175SafeBrowsingService::~SafeBrowsingService() {
176  // We should have already been shut down. If we're still enabled, then the
177  // database isn't going to be closed properly, which could lead to corruption.
178  DCHECK(!enabled_);
179}
180
181void SafeBrowsingService::Initialize() {
182  startup_metric_utils::ScopedSlowStartupUMA
183      scoped_timer("Startup.SlowStartupSafeBrowsingServiceInitialize");
184
185  url_request_context_getter_ =
186      new SafeBrowsingURLRequestContextGetter(this);
187
188  ui_manager_ = CreateUIManager();
189
190  database_manager_ = CreateDatabaseManager();
191
192  BrowserThread::PostTask(
193      BrowserThread::IO, FROM_HERE,
194      base::Bind(
195          &SafeBrowsingService::InitURLRequestContextOnIOThread, this,
196          make_scoped_refptr(g_browser_process->system_request_context())));
197
198#if defined(FULL_SAFE_BROWSING)
199  if (!CommandLine::ForCurrentProcess()->HasSwitch(
200          switches::kDisableClientSidePhishingDetection)) {
201    csd_service_.reset(
202        safe_browsing::ClientSideDetectionService::Create(
203            url_request_context_getter_));
204  }
205  download_service_.reset(new safe_browsing::DownloadProtectionService(
206      this,
207      url_request_context_getter_));
208#endif
209
210  // Track the safe browsing preference of existing profiles.
211  // The SafeBrowsingService will be started if any existing profile has the
212  // preference enabled. It will also listen for updates to the preferences.
213  ProfileManager* profile_manager = g_browser_process->profile_manager();
214  if (profile_manager) {
215    std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
216    for (size_t i = 0; i < profiles.size(); ++i) {
217      if (profiles[i]->IsOffTheRecord())
218        continue;
219      AddPrefService(profiles[i]->GetPrefs());
220    }
221  }
222
223  // Track profile creation and destruction.
224  prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
225                       content::NotificationService::AllSources());
226  prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
227                       content::NotificationService::AllSources());
228}
229
230void SafeBrowsingService::ShutDown() {
231  // Deletes the PrefChangeRegistrars, whose dtors also unregister |this| as an
232  // observer of the preferences.
233  STLDeleteValues(&prefs_map_);
234
235  // Remove Profile creation/destruction observers.
236  prefs_registrar_.RemoveAll();
237
238  Stop(true);
239  // The IO thread is going away, so make sure the ClientSideDetectionService
240  // dtor executes now since it may call the dtor of URLFetcher which relies
241  // on it.
242  csd_service_.reset();
243  download_service_.reset();
244
245  url_request_context_getter_ = NULL;
246  BrowserThread::PostNonNestableTask(
247      BrowserThread::IO, FROM_HERE,
248      base::Bind(&SafeBrowsingService::DestroyURLRequestContextOnIOThread,
249                 this));
250}
251
252// Binhash verification is only enabled for UMA users for now.
253bool SafeBrowsingService::DownloadBinHashNeeded() const {
254  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
255
256#if defined(FULL_SAFE_BROWSING)
257  return (database_manager_->download_protection_enabled() &&
258          ui_manager_->CanReportStats()) ||
259      (download_protection_service() &&
260       download_protection_service()->enabled());
261#else
262  return false;
263#endif
264}
265
266net::URLRequestContextGetter* SafeBrowsingService::url_request_context() {
267  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
268  return url_request_context_getter_.get();
269}
270
271const scoped_refptr<SafeBrowsingUIManager>&
272SafeBrowsingService::ui_manager() const {
273  return ui_manager_;
274}
275
276const scoped_refptr<SafeBrowsingDatabaseManager>&
277SafeBrowsingService::database_manager() const {
278  return database_manager_;
279}
280
281SafeBrowsingProtocolManager* SafeBrowsingService::protocol_manager() const {
282  return protocol_manager_;
283}
284
285SafeBrowsingPingManager* SafeBrowsingService::ping_manager() const {
286  return ping_manager_;
287}
288
289SafeBrowsingUIManager* SafeBrowsingService::CreateUIManager() {
290  return new SafeBrowsingUIManager(this);
291}
292
293SafeBrowsingDatabaseManager* SafeBrowsingService::CreateDatabaseManager() {
294
295#if defined(FULL_SAFE_BROWSING)
296  return new SafeBrowsingDatabaseManager(this);
297#else
298  return NULL;
299#endif
300}
301
302void SafeBrowsingService::InitURLRequestContextOnIOThread(
303    net::URLRequestContextGetter* system_url_request_context_getter) {
304  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
305  DCHECK(!url_request_context_.get());
306
307  scoped_refptr<net::CookieStore> cookie_store = new net::CookieMonster(
308      new SQLitePersistentCookieStore(
309          CookieFilePath(),
310          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO),
311          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
312          false,
313          NULL),
314      NULL);
315
316  url_request_context_.reset(new net::URLRequestContext);
317  // |system_url_request_context_getter| may be NULL during tests.
318  if (system_url_request_context_getter) {
319    url_request_context_->CopyFrom(
320        system_url_request_context_getter->GetURLRequestContext());
321  }
322  url_request_context_->set_cookie_store(cookie_store);
323}
324
325void SafeBrowsingService::DestroyURLRequestContextOnIOThread() {
326  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
327
328  url_request_context_->AssertNoURLRequests();
329
330  // Need to do the CheckForLeaks on IOThread instead of in ShutDown where
331  // url_request_context_getter_ is cleared,  since the URLRequestContextGetter
332  // will PostTask to IOTread to delete itself.
333  using base::debug::LeakTracker;
334  LeakTracker<SafeBrowsingURLRequestContextGetter>::CheckForLeaks();
335
336  url_request_context_.reset();
337}
338
339void SafeBrowsingService::StartOnIOThread() {
340  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
341  if (enabled_)
342    return;
343  enabled_ = true;
344
345  SafeBrowsingProtocolConfig config;
346  // On Windows, get the safe browsing client name from the browser
347  // distribution classes in installer util. These classes don't yet have
348  // an analog on non-Windows builds so just keep the name specified here.
349#if defined(OS_WIN)
350  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
351  config.client_name = dist->GetSafeBrowsingName();
352#else
353#if defined(GOOGLE_CHROME_BUILD)
354  config.client_name = "googlechrome";
355#else
356  config.client_name = "chromium";
357#endif
358#endif
359  CommandLine* cmdline = CommandLine::ForCurrentProcess();
360  config.disable_auto_update =
361      cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
362      cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
363  config.url_prefix =
364      cmdline->HasSwitch(switches::kSbURLPrefix) ?
365      cmdline->GetSwitchValueASCII(switches::kSbURLPrefix) :
366      kSbDefaultURLPrefix;
367  config.backup_connect_error_url_prefix = kSbBackupConnectErrorURLPrefix;
368  config.backup_http_error_url_prefix = kSbBackupHttpErrorURLPrefix;
369  config.backup_network_error_url_prefix = kSbBackupNetworkErrorURLPrefix;
370
371#if defined(FULL_SAFE_BROWSING)
372  DCHECK(database_manager_);
373  database_manager_->StartOnIOThread();
374
375  DCHECK(!protocol_manager_);
376  protocol_manager_ =
377      SafeBrowsingProtocolManager::Create(database_manager_,
378                                          url_request_context_getter_,
379                                          config);
380  protocol_manager_->Initialize();
381#endif
382
383  DCHECK(!ping_manager_);
384  ping_manager_ =
385      SafeBrowsingPingManager::Create(url_request_context_getter_,
386                                      config);
387}
388
389void SafeBrowsingService::StopOnIOThread(bool shutdown) {
390  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
391
392#if defined(FULL_SAFE_BROWSING)
393  database_manager_->StopOnIOThread(shutdown);
394#endif
395  ui_manager_->StopOnIOThread(shutdown);
396
397  if (enabled_) {
398    enabled_ = false;
399
400#if defined(FULL_SAFE_BROWSING)
401    // This cancels all in-flight GetHash requests. Note that database_manager_
402    // relies on the protocol_manager_ so if the latter is destroyed, the
403    // former must be stopped.
404    delete protocol_manager_;
405    protocol_manager_ = NULL;
406#endif
407    delete ping_manager_;
408    ping_manager_ = NULL;
409  }
410}
411
412void SafeBrowsingService::Start() {
413  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
414
415  BrowserThread::PostTask(
416      BrowserThread::IO, FROM_HERE,
417      base::Bind(&SafeBrowsingService::StartOnIOThread, this));
418}
419
420void SafeBrowsingService::Stop(bool shutdown) {
421  BrowserThread::PostTask(
422      BrowserThread::IO, FROM_HERE,
423      base::Bind(&SafeBrowsingService::StopOnIOThread, this, shutdown));
424}
425
426void SafeBrowsingService::Observe(int type,
427                                  const content::NotificationSource& source,
428                                  const content::NotificationDetails& details) {
429  switch (type) {
430    case chrome::NOTIFICATION_PROFILE_CREATED: {
431      DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
432      Profile* profile = content::Source<Profile>(source).ptr();
433      if (!profile->IsOffTheRecord())
434        AddPrefService(profile->GetPrefs());
435      break;
436    }
437    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
438      DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
439      Profile* profile = content::Source<Profile>(source).ptr();
440      if (!profile->IsOffTheRecord())
441        RemovePrefService(profile->GetPrefs());
442      break;
443    }
444    default:
445      NOTREACHED();
446  }
447}
448
449void SafeBrowsingService::AddPrefService(PrefService* pref_service) {
450  DCHECK(prefs_map_.find(pref_service) == prefs_map_.end());
451  PrefChangeRegistrar* registrar = new PrefChangeRegistrar();
452  registrar->Init(pref_service);
453  registrar->Add(prefs::kSafeBrowsingEnabled,
454                 base::Bind(&SafeBrowsingService::RefreshState,
455                            base::Unretained(this)));
456  prefs_map_[pref_service] = registrar;
457  RefreshState();
458}
459
460void SafeBrowsingService::RemovePrefService(PrefService* pref_service) {
461  if (prefs_map_.find(pref_service) != prefs_map_.end()) {
462    delete prefs_map_[pref_service];
463    prefs_map_.erase(pref_service);
464    RefreshState();
465  } else {
466    NOTREACHED();
467  }
468}
469
470void SafeBrowsingService::RefreshState() {
471  // Check if any profile requires the service to be active.
472  bool enable = false;
473  std::map<PrefService*, PrefChangeRegistrar*>::iterator iter;
474  for (iter = prefs_map_.begin(); iter != prefs_map_.end(); ++iter) {
475    if (iter->first->GetBoolean(prefs::kSafeBrowsingEnabled)) {
476      enable = true;
477      break;
478    }
479  }
480
481  if (enable)
482    Start();
483  else
484    Stop(false);
485
486#if defined(FULL_SAFE_BROWSING)
487  if (csd_service_.get())
488    csd_service_->SetEnabledAndRefreshState(enable);
489  if (download_service_.get()) {
490    download_service_->SetEnabled(
491        enable && !CommandLine::ForCurrentProcess()->HasSwitch(
492            switches::kDisableImprovedDownloadProtection));
493  }
494#endif
495}
496