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