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