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