browsing_data_remover.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2010 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/browsing_data_remover.h" 6 7#include <map> 8#include <set> 9 10#include "base/callback.h" 11#include "chrome/browser/autofill/personal_data_manager.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/browser/browser_thread.h" 14#include "chrome/browser/download/download_manager.h" 15#include "chrome/browser/extensions/extension_service.h" 16#include "chrome/browser/history/history.h" 17#include "chrome/browser/in_process_webkit/webkit_context.h" 18#include "chrome/browser/io_thread.h" 19#include "chrome/browser/metrics/user_metrics.h" 20#include "chrome/browser/net/chrome_net_log.h" 21#include "chrome/browser/net/chrome_url_request_context.h" 22#include "chrome/browser/password_manager/password_store.h" 23#include "chrome/browser/plugin_data_remover.h" 24#include "chrome/browser/profiles/profile.h" 25#include "chrome/browser/renderer_host/web_cache_manager.h" 26#include "chrome/browser/search_engines/template_url_model.h" 27#include "chrome/browser/sessions/session_service.h" 28#include "chrome/browser/sessions/tab_restore_service.h" 29#include "chrome/browser/webdata/web_data_service.h" 30#include "chrome/common/net/url_request_context_getter.h" 31#include "chrome/common/notification_source.h" 32#include "chrome/common/url_constants.h" 33#include "net/base/cookie_monster.h" 34#include "net/base/net_errors.h" 35#include "net/base/transport_security_state.h" 36#include "net/disk_cache/disk_cache.h" 37#include "net/http/http_cache.h" 38#include "net/url_request/url_request_context.h" 39#include "webkit/database/database_tracker.h" 40#include "webkit/database/database_util.h" 41 42// Done so that we can use PostTask on BrowsingDataRemovers and not have 43// BrowsingDataRemover implement RefCounted. 44DISABLE_RUNNABLE_METHOD_REFCOUNT(BrowsingDataRemover); 45 46bool BrowsingDataRemover::removing_ = false; 47 48BrowsingDataRemover::BrowsingDataRemover(Profile* profile, 49 base::Time delete_begin, 50 base::Time delete_end) 51 : profile_(profile), 52 delete_begin_(delete_begin), 53 delete_end_(delete_end), 54 ALLOW_THIS_IN_INITIALIZER_LIST(database_cleared_callback_( 55 this, &BrowsingDataRemover::OnClearedDatabases)), 56 ALLOW_THIS_IN_INITIALIZER_LIST(cache_callback_( 57 this, &BrowsingDataRemover::DoClearCache)), 58 ALLOW_THIS_IN_INITIALIZER_LIST(appcache_got_info_callback_( 59 this, &BrowsingDataRemover::OnGotAppCacheInfo)), 60 ALLOW_THIS_IN_INITIALIZER_LIST(appcache_deleted_callback_( 61 this, &BrowsingDataRemover::OnAppCacheDeleted)), 62 appcaches_to_be_deleted_count_(0), 63 next_cache_state_(STATE_NONE), 64 cache_(NULL), 65 main_context_getter_(profile->GetRequestContext()), 66 media_context_getter_(profile->GetRequestContextForMedia()), 67 waiting_for_clear_databases_(false), 68 waiting_for_clear_history_(false), 69 waiting_for_clear_host_cache_(false), 70 waiting_for_clear_cache_(false), 71 waiting_for_clear_appcache_(false) { 72 DCHECK(profile); 73} 74 75BrowsingDataRemover::BrowsingDataRemover(Profile* profile, 76 TimePeriod time_period, 77 base::Time delete_end) 78 : profile_(profile), 79 delete_begin_(CalculateBeginDeleteTime(time_period)), 80 delete_end_(delete_end), 81 ALLOW_THIS_IN_INITIALIZER_LIST(database_cleared_callback_( 82 this, &BrowsingDataRemover::OnClearedDatabases)), 83 ALLOW_THIS_IN_INITIALIZER_LIST(cache_callback_( 84 this, &BrowsingDataRemover::DoClearCache)), 85 ALLOW_THIS_IN_INITIALIZER_LIST(appcache_got_info_callback_( 86 this, &BrowsingDataRemover::OnGotAppCacheInfo)), 87 ALLOW_THIS_IN_INITIALIZER_LIST(appcache_deleted_callback_( 88 this, &BrowsingDataRemover::OnAppCacheDeleted)), 89 appcaches_to_be_deleted_count_(0), 90 next_cache_state_(STATE_NONE), 91 cache_(NULL), 92 main_context_getter_(profile->GetRequestContext()), 93 media_context_getter_(profile->GetRequestContextForMedia()), 94 waiting_for_clear_databases_(false), 95 waiting_for_clear_history_(false), 96 waiting_for_clear_host_cache_(false), 97 waiting_for_clear_cache_(false), 98 waiting_for_clear_appcache_(false), 99 waiting_for_clear_lso_data_(false) { 100 DCHECK(profile); 101} 102 103BrowsingDataRemover::~BrowsingDataRemover() { 104 DCHECK(all_done()); 105} 106 107void BrowsingDataRemover::Remove(int remove_mask) { 108 DCHECK(!removing_); 109 removing_ = true; 110 111 std::vector<GURL> origin_whitelist; 112 ExtensionService* extensions_service = profile_->GetExtensionService(); 113 if (extensions_service && extensions_service->HasInstalledExtensions()) { 114 std::map<GURL, int> whitelist_map = 115 extensions_service->protected_storage_map(); 116 for (std::map<GURL, int>::const_iterator iter = whitelist_map.begin(); 117 iter != whitelist_map.end(); ++iter) { 118 origin_whitelist.push_back(iter->first); 119 } 120 } 121 122 std::vector<string16> webkit_db_whitelist; 123 for (size_t i = 0; i < origin_whitelist.size(); ++i) { 124 webkit_db_whitelist.push_back( 125 webkit_database::DatabaseUtil::GetOriginIdentifier( 126 origin_whitelist[i])); 127 } 128 129 130 if (remove_mask & REMOVE_HISTORY) { 131 HistoryService* history_service = 132 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); 133 if (history_service) { 134 std::set<GURL> restrict_urls; 135 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_History"), 136 profile_); 137 waiting_for_clear_history_ = true; 138 history_service->ExpireHistoryBetween(restrict_urls, 139 delete_begin_, delete_end_, 140 &request_consumer_, 141 NewCallback(this, &BrowsingDataRemover::OnHistoryDeletionDone)); 142 } 143 144 // Need to clear the host cache, as it also reveals some history. 145 waiting_for_clear_host_cache_ = true; 146 BrowserThread::PostTask( 147 BrowserThread::IO, FROM_HERE, 148 NewRunnableMethod( 149 this, 150 &BrowsingDataRemover::ClearHostCacheOnIOThread, 151 g_browser_process->io_thread())); 152 153 // As part of history deletion we also delete the auto-generated keywords. 154 TemplateURLModel* keywords_model = profile_->GetTemplateURLModel(); 155 if (keywords_model && !keywords_model->loaded()) { 156 registrar_.Add(this, NotificationType::TEMPLATE_URL_MODEL_LOADED, 157 Source<TemplateURLModel>(keywords_model)); 158 keywords_model->Load(); 159 } else if (keywords_model) { 160 keywords_model->RemoveAutoGeneratedBetween(delete_begin_, delete_end_); 161 } 162 163 // We also delete the list of recently closed tabs. Since these expire, 164 // they can't be more than a day old, so we can simply clear them all. 165 TabRestoreService* tab_service = profile_->GetTabRestoreService(); 166 if (tab_service) { 167 tab_service->ClearEntries(); 168 tab_service->DeleteLastSession(); 169 } 170 171 // We also delete the last session when we delete the history. 172 SessionService* session_service = profile_->GetSessionService(); 173 if (session_service) 174 session_service->DeleteLastSession(); 175 } 176 177 if (remove_mask & REMOVE_DOWNLOADS) { 178 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_Downloads"), 179 profile_); 180 DownloadManager* download_manager = profile_->GetDownloadManager(); 181 download_manager->RemoveDownloadsBetween(delete_begin_, delete_end_); 182 download_manager->ClearLastDownloadPath(); 183 } 184 185 if (remove_mask & REMOVE_COOKIES) { 186 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_Cookies"), 187 profile_); 188 // Since we are running on the UI thread don't call GetURLRequestContext(). 189 net::CookieMonster* cookie_monster = 190 profile_->GetRequestContext()->GetCookieStore()->GetCookieMonster(); 191 if (cookie_monster) 192 cookie_monster->DeleteAllCreatedBetween(delete_begin_, delete_end_, true); 193 194 // REMOVE_COOKIES is actually "cookies and other site data" so we make sure 195 // to remove other data such local databases, STS state, etc. 196 profile_->GetWebKitContext()->DeleteDataModifiedSince( 197 delete_begin_, chrome::kExtensionScheme, webkit_db_whitelist); 198 199 database_tracker_ = profile_->GetDatabaseTracker(); 200 if (database_tracker_.get()) { 201 waiting_for_clear_databases_ = true; 202 BrowserThread::PostTask( 203 BrowserThread::FILE, FROM_HERE, 204 NewRunnableMethod( 205 this, 206 &BrowsingDataRemover::ClearDatabasesOnFILEThread, 207 delete_begin_, 208 webkit_db_whitelist)); 209 } 210 211 BrowserThread::PostTask( 212 BrowserThread::IO, FROM_HERE, 213 NewRunnableMethod( 214 profile_->GetTransportSecurityState(), 215 &net::TransportSecurityState::DeleteSince, 216 delete_begin_)); 217 218 waiting_for_clear_appcache_ = true; 219 BrowserThread::PostTask( 220 BrowserThread::IO, FROM_HERE, 221 NewRunnableMethod( 222 this, 223 &BrowsingDataRemover::ClearAppCacheOnIOThread, 224 delete_begin_, // we assume end time == now 225 origin_whitelist)); 226 } 227 228 if (remove_mask & REMOVE_PASSWORDS) { 229 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_Passwords"), 230 profile_); 231 PasswordStore* password_store = 232 profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS); 233 234 if (password_store) 235 password_store->RemoveLoginsCreatedBetween(delete_begin_, delete_end_); 236 } 237 238 if (remove_mask & REMOVE_FORM_DATA) { 239 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_Autofill"), 240 profile_); 241 WebDataService* web_data_service = 242 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); 243 244 if (web_data_service) { 245 web_data_service->RemoveFormElementsAddedBetween(delete_begin_, 246 delete_end_); 247 web_data_service->RemoveAutoFillProfilesAndCreditCardsModifiedBetween( 248 delete_begin_, delete_end_); 249 PersonalDataManager* data_manager = profile_->GetPersonalDataManager(); 250 if (data_manager) { 251 data_manager->Refresh(); 252 } 253 } 254 } 255 256 if (remove_mask & REMOVE_CACHE) { 257 // Tell the renderers to clear their cache. 258 WebCacheManager::GetInstance()->ClearCache(); 259 260 // Invoke ClearBrowsingDataView::ClearCache on the IO thread. 261 waiting_for_clear_cache_ = true; 262 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_Cache"), 263 profile_); 264 265 BrowserThread::PostTask( 266 BrowserThread::IO, FROM_HERE, 267 NewRunnableMethod(this, &BrowsingDataRemover::ClearCacheOnIOThread)); 268 } 269 270 if (remove_mask & REMOVE_LSO_DATA) { 271 UserMetrics::RecordAction(UserMetricsAction("ClearBrowsingData_LSOData")); 272 273 waiting_for_clear_lso_data_ = true; 274 if (!plugin_data_remover_.get()) 275 plugin_data_remover_ = new PluginDataRemover(); 276 base::WaitableEvent* event = 277 plugin_data_remover_->StartRemoving(delete_begin_); 278 watcher_.StartWatching(event, this); 279 } 280 281 NotifyAndDeleteIfDone(); 282} 283 284void BrowsingDataRemover::AddObserver(Observer* observer) { 285 observer_list_.AddObserver(observer); 286} 287 288void BrowsingDataRemover::RemoveObserver(Observer* observer) { 289 observer_list_.RemoveObserver(observer); 290} 291 292void BrowsingDataRemover::OnHistoryDeletionDone() { 293 waiting_for_clear_history_ = false; 294 NotifyAndDeleteIfDone(); 295} 296 297base::Time BrowsingDataRemover::CalculateBeginDeleteTime( 298 TimePeriod time_period) { 299 base::TimeDelta diff; 300 base::Time delete_begin_time = base::Time::Now(); 301 switch (time_period) { 302 case LAST_HOUR: 303 diff = base::TimeDelta::FromHours(1); 304 break; 305 case LAST_DAY: 306 diff = base::TimeDelta::FromHours(24); 307 break; 308 case LAST_WEEK: 309 diff = base::TimeDelta::FromHours(7*24); 310 break; 311 case FOUR_WEEKS: 312 diff = base::TimeDelta::FromHours(4*7*24); 313 break; 314 case EVERYTHING: 315 delete_begin_time = base::Time(); 316 break; 317 default: 318 NOTREACHED() << L"Missing item"; 319 break; 320 } 321 return delete_begin_time - diff; 322} 323 324void BrowsingDataRemover::Observe(NotificationType type, 325 const NotificationSource& source, 326 const NotificationDetails& details) { 327 // TODO(brettw) bug 1139736: This should also observe session 328 // clearing (what about other things such as passwords, etc.?) and wait for 329 // them to complete before continuing. 330 DCHECK(type == NotificationType::TEMPLATE_URL_MODEL_LOADED); 331 TemplateURLModel* model = Source<TemplateURLModel>(source).ptr(); 332 if (model->profile() == profile_->GetOriginalProfile()) { 333 registrar_.RemoveAll(); 334 model->RemoveAutoGeneratedBetween(delete_begin_, delete_end_); 335 NotifyAndDeleteIfDone(); 336 } 337} 338 339void BrowsingDataRemover::NotifyAndDeleteIfDone() { 340 // TODO(brettw) bug 1139736: see TODO in Observe() above. 341 if (!all_done()) 342 return; 343 344 // The NetLog contains download history, but may also contain form data, 345 // cookies and passwords. Simplest just to always clear it. Must be cleared 346 // after the cache, as cleaning up the disk cache exposes some of the history 347 // in the NetLog. 348 g_browser_process->net_log()->ClearAllPassivelyCapturedEvents(); 349 350 removing_ = false; 351 FOR_EACH_OBSERVER(Observer, observer_list_, OnBrowsingDataRemoverDone()); 352 353 // History requests aren't happy if you delete yourself from the callback. 354 // As such, we do a delete later. 355 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 356} 357 358void BrowsingDataRemover::ClearedNetworkHistory() { 359 waiting_for_clear_host_cache_ = false; 360 361 NotifyAndDeleteIfDone(); 362} 363 364void BrowsingDataRemover::ClearHostCacheOnIOThread(IOThread* io_thread) { 365 // This function should be called on the IO thread. 366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 367 368 io_thread->ClearHostCache(); 369 370 // Notify the UI thread that we are done. 371 BrowserThread::PostTask( 372 BrowserThread::UI, FROM_HERE, 373 NewRunnableMethod(this, &BrowsingDataRemover::ClearedNetworkHistory)); 374} 375 376void BrowsingDataRemover::ClearedCache() { 377 waiting_for_clear_cache_ = false; 378 379 NotifyAndDeleteIfDone(); 380} 381 382void BrowsingDataRemover::ClearCacheOnIOThread() { 383 // This function should be called on the IO thread. 384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 385 DCHECK_EQ(STATE_NONE, next_cache_state_); 386 DCHECK(main_context_getter_); 387 DCHECK(media_context_getter_); 388 389 next_cache_state_ = STATE_CREATE_MAIN; 390 DoClearCache(net::OK); 391} 392 393// The expected state sequence is STATE_NONE --> STATE_CREATE_MAIN --> 394// STATE_DELETE_MAIN --> STATE_CREATE_MEDIA --> STATE_DELETE_MEDIA --> 395// STATE_DONE, and any errors are ignored. 396void BrowsingDataRemover::DoClearCache(int rv) { 397 DCHECK_NE(STATE_NONE, next_cache_state_); 398 399 while (rv != net::ERR_IO_PENDING && next_cache_state_ != STATE_NONE) { 400 switch (next_cache_state_) { 401 case STATE_CREATE_MAIN: 402 case STATE_CREATE_MEDIA: { 403 // Get a pointer to the cache. 404 URLRequestContextGetter* getter = 405 (next_cache_state_ == STATE_CREATE_MAIN) ? 406 main_context_getter_ : media_context_getter_; 407 net::HttpTransactionFactory* factory = 408 getter->GetURLRequestContext()->http_transaction_factory(); 409 410 rv = factory->GetCache()->GetBackend(&cache_, &cache_callback_); 411 next_cache_state_ = (next_cache_state_ == STATE_CREATE_MAIN) ? 412 STATE_DELETE_MAIN : STATE_DELETE_MEDIA; 413 break; 414 } 415 case STATE_DELETE_MAIN: 416 case STATE_DELETE_MEDIA: { 417 // |cache_| can be null if it cannot be initialized. 418 if (cache_) { 419 if (delete_begin_.is_null()) { 420 rv = cache_->DoomAllEntries(&cache_callback_); 421 } else { 422 rv = cache_->DoomEntriesBetween(delete_begin_, delete_end_, 423 &cache_callback_); 424 } 425 cache_ = NULL; 426 } 427 next_cache_state_ = (next_cache_state_ == STATE_DELETE_MAIN) ? 428 STATE_CREATE_MEDIA : STATE_DONE; 429 break; 430 } 431 case STATE_DONE: { 432 cache_ = NULL; 433 434 // Notify the UI thread that we are done. 435 BrowserThread::PostTask( 436 BrowserThread::UI, FROM_HERE, 437 NewRunnableMethod(this, &BrowsingDataRemover::ClearedCache)); 438 439 next_cache_state_ = STATE_NONE; 440 break; 441 } 442 default: { 443 NOTREACHED() << "bad state"; 444 next_cache_state_ = STATE_NONE; // Stop looping. 445 break; 446 } 447 } 448 } 449} 450 451void BrowsingDataRemover::OnClearedDatabases(int rv) { 452 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 453 bool result = BrowserThread::PostTask( 454 BrowserThread::UI, FROM_HERE, 455 NewRunnableMethod(this, &BrowsingDataRemover::OnClearedDatabases, rv)); 456 DCHECK(result); 457 return; 458 } 459 // Notify the UI thread that we are done. 460 database_tracker_ = NULL; 461 waiting_for_clear_databases_ = false; 462 463 NotifyAndDeleteIfDone(); 464} 465 466void BrowsingDataRemover::ClearDatabasesOnFILEThread(base::Time delete_begin, 467 const std::vector<string16>& webkit_db_whitelist) { 468 // This function should be called on the FILE thread. 469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 470 471 int rv = database_tracker_->DeleteDataModifiedSince( 472 delete_begin, webkit_db_whitelist, &database_cleared_callback_); 473 if (rv != net::ERR_IO_PENDING) 474 OnClearedDatabases(rv); 475} 476 477void BrowsingDataRemover::OnClearedAppCache() { 478 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 479 bool result = BrowserThread::PostTask( 480 BrowserThread::UI, FROM_HERE, 481 NewRunnableMethod(this, &BrowsingDataRemover::OnClearedAppCache)); 482 DCHECK(result); 483 return; 484 } 485 appcache_whitelist_.clear(); 486 waiting_for_clear_appcache_ = false; 487 NotifyAndDeleteIfDone(); 488} 489 490void BrowsingDataRemover::ClearAppCacheOnIOThread(base::Time delete_begin, 491 const std::vector<GURL>& origin_whitelist) { 492 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 493 DCHECK(waiting_for_clear_appcache_); 494 495 appcache_whitelist_ = origin_whitelist; 496 appcache_info_ = new appcache::AppCacheInfoCollection; 497 GetAppCacheService()->GetAllAppCacheInfo( 498 appcache_info_, &appcache_got_info_callback_); 499 // continues in OnGotAppCacheInfo 500} 501 502void BrowsingDataRemover::OnGotAppCacheInfo(int rv) { 503 using appcache::AppCacheInfoVector; 504 typedef std::map<GURL, AppCacheInfoVector> InfoByOrigin; 505 506 for (InfoByOrigin::const_iterator origin = 507 appcache_info_->infos_by_origin.begin(); 508 origin != appcache_info_->infos_by_origin.end(); ++origin) { 509 bool found_in_whitelist = false; 510 for (size_t i = 0; i < appcache_whitelist_.size(); ++i) { 511 if (appcache_whitelist_[i] == origin->first) 512 found_in_whitelist = true; 513 } 514 if (found_in_whitelist) 515 continue; 516 517 for (AppCacheInfoVector::const_iterator info = origin->second.begin(); 518 info != origin->second.end(); ++info) { 519 if (info->creation_time > delete_begin_) { 520 ++appcaches_to_be_deleted_count_; 521 GetAppCacheService()->DeleteAppCacheGroup( 522 info->manifest_url, &appcache_deleted_callback_); 523 } 524 } 525 } 526 527 if (!appcaches_to_be_deleted_count_) 528 OnClearedAppCache(); 529 // else continues in OnAppCacheDeleted 530} 531 532void BrowsingDataRemover::OnAppCacheDeleted(int rv) { 533 --appcaches_to_be_deleted_count_; 534 if (!appcaches_to_be_deleted_count_) 535 OnClearedAppCache(); 536} 537 538ChromeAppCacheService* BrowsingDataRemover::GetAppCacheService() { 539 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 540 ChromeURLRequestContext* request_context = 541 reinterpret_cast<ChromeURLRequestContext*>( 542 main_context_getter_->GetURLRequestContext()); 543 return request_context ? request_context->appcache_service() 544 : NULL; 545} 546 547void BrowsingDataRemover::OnWaitableEventSignaled( 548 base::WaitableEvent* waitable_event) { 549 waiting_for_clear_lso_data_ = false; 550 NotifyAndDeleteIfDone(); 551} 552