1// Copyright 2013 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 "base/bind.h"
6#include "base/command_line.h"
7#include "base/memory/ref_counted.h"
8#include "chrome/browser/browser_shutdown.h"
9#include "chrome/browser/prefs/session_startup_pref.h"
10#include "chrome/browser/profiles/profile_io_data.h"
11#include "chrome/browser/ui/startup/startup_browser_creator.h"
12#include "content/public/browser/browser_context.h"
13#include "content/public/browser/browser_thread.h"
14#include "content/public/browser/dom_storage_context.h"
15#include "content/public/browser/local_storage_usage_info.h"
16#include "content/public/browser/storage_partition.h"
17#include "net/cookies/cookie_monster.h"
18#include "net/cookies/cookie_store.h"
19#include "net/cookies/cookie_util.h"
20#include "net/url_request/url_request_context.h"
21#include "storage/browser/quota/special_storage_policy.h"
22
23namespace {
24
25void CookieDeleted(bool success) {
26  DCHECK(success);
27}
28
29class SessionDataDeleter
30    : public base::RefCountedThreadSafe<SessionDataDeleter> {
31 public:
32  SessionDataDeleter(storage::SpecialStoragePolicy* storage_policy,
33                     bool delete_only_by_session_only_policy);
34
35  void Run(content::StoragePartition* storage_partition,
36           ProfileIOData* profile_io_data);
37
38 private:
39  friend class base::RefCountedThreadSafe<SessionDataDeleter>;
40  ~SessionDataDeleter();
41
42  // Deletes the local storage described by |usages| for origins which are
43  // session-only.
44  void ClearSessionOnlyLocalStorage(
45      content::StoragePartition* storage_partition,
46      const std::vector<content::LocalStorageUsageInfo>& usages);
47
48  // Deletes all cookies that are session only if
49  // |delete_only_by_session_only_policy_| is false. Once completed or skipped,
50  // this arranges for DeleteSessionOnlyOriginCookies to be called with a list
51  // of all remaining cookies.
52  void DeleteSessionCookiesOnIOThread(ProfileIOData* profile_io_data);
53
54  // Called when all session-only cookies have been deleted.
55  void DeleteSessionCookiesDone(int num_deleted);
56
57  // Deletes the cookies in |cookies| that are for origins which are
58  // session-only.
59  void DeleteSessionOnlyOriginCookies(const net::CookieList& cookies);
60
61  scoped_refptr<net::CookieMonster> cookie_monster_;
62  scoped_refptr<storage::SpecialStoragePolicy> storage_policy_;
63  const bool delete_only_by_session_only_policy_;
64
65  DISALLOW_COPY_AND_ASSIGN(SessionDataDeleter);
66};
67
68SessionDataDeleter::SessionDataDeleter(
69    storage::SpecialStoragePolicy* storage_policy,
70    bool delete_only_by_session_only_policy)
71    : storage_policy_(storage_policy),
72      delete_only_by_session_only_policy_(delete_only_by_session_only_policy) {
73}
74
75void SessionDataDeleter::Run(content::StoragePartition* storage_partition,
76                             ProfileIOData* profile_io_data) {
77  if (storage_policy_.get() && storage_policy_->HasSessionOnlyOrigins()) {
78    storage_partition->GetDOMStorageContext()->GetLocalStorageUsage(
79        base::Bind(&SessionDataDeleter::ClearSessionOnlyLocalStorage,
80                   this,
81                   storage_partition));
82  }
83  content::BrowserThread::PostTask(
84      content::BrowserThread::IO,
85      FROM_HERE,
86      base::Bind(&SessionDataDeleter::DeleteSessionCookiesOnIOThread,
87                 this,
88                 profile_io_data));
89}
90
91SessionDataDeleter::~SessionDataDeleter() {}
92
93void SessionDataDeleter::ClearSessionOnlyLocalStorage(
94    content::StoragePartition* storage_partition,
95    const std::vector<content::LocalStorageUsageInfo>& usages) {
96  DCHECK(storage_policy_.get());
97  DCHECK(storage_policy_->HasSessionOnlyOrigins());
98  for (size_t i = 0; i < usages.size(); ++i) {
99    const content::LocalStorageUsageInfo& usage = usages[i];
100    if (!storage_policy_->IsStorageSessionOnly(usage.origin))
101      continue;
102    storage_partition->GetDOMStorageContext()->DeleteLocalStorage(usage.origin);
103  }
104}
105
106void SessionDataDeleter::DeleteSessionCookiesOnIOThread(
107    ProfileIOData* profile_io_data) {
108  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
109  net::URLRequestContext* request_context =
110      profile_io_data->GetMainRequestContext();
111  cookie_monster_ = request_context->cookie_store()->GetCookieMonster();
112  if (delete_only_by_session_only_policy_) {
113    cookie_monster_->GetAllCookiesAsync(
114        base::Bind(&SessionDataDeleter::DeleteSessionOnlyOriginCookies, this));
115  } else {
116    cookie_monster_->DeleteSessionCookiesAsync(
117        base::Bind(&SessionDataDeleter::DeleteSessionCookiesDone, this));
118  }
119}
120
121void SessionDataDeleter::DeleteSessionCookiesDone(int num_deleted) {
122  cookie_monster_->GetAllCookiesAsync(
123      base::Bind(&SessionDataDeleter::DeleteSessionOnlyOriginCookies, this));
124}
125
126void SessionDataDeleter::DeleteSessionOnlyOriginCookies(
127    const net::CookieList& cookies) {
128  if (!storage_policy_.get() || !storage_policy_->HasSessionOnlyOrigins())
129    return;
130
131  for (net::CookieList::const_iterator it = cookies.begin();
132       it != cookies.end();
133       ++it) {
134    GURL url =
135        net::cookie_util::CookieOriginToURL(it->Domain(), it->IsSecure());
136    if (!storage_policy_->IsStorageSessionOnly(url))
137      continue;
138    cookie_monster_->DeleteCanonicalCookieAsync(*it, base::Bind(CookieDeleted));
139  }
140}
141
142}  // namespace
143
144void DeleteSessionOnlyData(Profile* profile) {
145  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
146  if (browser_shutdown::IsTryingToQuit())
147    return;
148
149#if defined(OS_ANDROID)
150  SessionStartupPref::Type startup_pref_type =
151      SessionStartupPref::GetDefaultStartupType();
152#else
153  SessionStartupPref::Type startup_pref_type =
154      StartupBrowserCreator::GetSessionStartupPref(
155          *CommandLine::ForCurrentProcess(), profile).type;
156#endif
157
158  scoped_refptr<SessionDataDeleter> deleter(
159      new SessionDataDeleter(profile->GetSpecialStoragePolicy(),
160                             startup_pref_type == SessionStartupPref::LAST));
161  deleter->Run(
162      Profile::GetDefaultStoragePartition(profile),
163      ProfileIOData::FromResourceContext(profile->GetResourceContext()));
164}
165