// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/bind.h" #include "base/command_line.h" #include "base/memory/ref_counted.h" #include "chrome/browser/browser_shutdown.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile_io_data.h" #include "chrome/browser/ui/startup/startup_browser_creator.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/dom_storage_context.h" #include "content/public/browser/local_storage_usage_info.h" #include "content/public/browser/storage_partition.h" #include "net/cookies/cookie_monster.h" #include "net/cookies/cookie_store.h" #include "net/cookies/cookie_util.h" #include "net/url_request/url_request_context.h" #include "storage/browser/quota/special_storage_policy.h" namespace { void CookieDeleted(bool success) { DCHECK(success); } class SessionDataDeleter : public base::RefCountedThreadSafe { public: SessionDataDeleter(storage::SpecialStoragePolicy* storage_policy, bool delete_only_by_session_only_policy); void Run(content::StoragePartition* storage_partition, ProfileIOData* profile_io_data); private: friend class base::RefCountedThreadSafe; ~SessionDataDeleter(); // Deletes the local storage described by |usages| for origins which are // session-only. void ClearSessionOnlyLocalStorage( content::StoragePartition* storage_partition, const std::vector& usages); // Deletes all cookies that are session only if // |delete_only_by_session_only_policy_| is false. Once completed or skipped, // this arranges for DeleteSessionOnlyOriginCookies to be called with a list // of all remaining cookies. void DeleteSessionCookiesOnIOThread(ProfileIOData* profile_io_data); // Called when all session-only cookies have been deleted. void DeleteSessionCookiesDone(int num_deleted); // Deletes the cookies in |cookies| that are for origins which are // session-only. void DeleteSessionOnlyOriginCookies(const net::CookieList& cookies); scoped_refptr cookie_monster_; scoped_refptr storage_policy_; const bool delete_only_by_session_only_policy_; DISALLOW_COPY_AND_ASSIGN(SessionDataDeleter); }; SessionDataDeleter::SessionDataDeleter( storage::SpecialStoragePolicy* storage_policy, bool delete_only_by_session_only_policy) : storage_policy_(storage_policy), delete_only_by_session_only_policy_(delete_only_by_session_only_policy) { } void SessionDataDeleter::Run(content::StoragePartition* storage_partition, ProfileIOData* profile_io_data) { if (storage_policy_.get() && storage_policy_->HasSessionOnlyOrigins()) { storage_partition->GetDOMStorageContext()->GetLocalStorageUsage( base::Bind(&SessionDataDeleter::ClearSessionOnlyLocalStorage, this, storage_partition)); } content::BrowserThread::PostTask( content::BrowserThread::IO, FROM_HERE, base::Bind(&SessionDataDeleter::DeleteSessionCookiesOnIOThread, this, profile_io_data)); } SessionDataDeleter::~SessionDataDeleter() {} void SessionDataDeleter::ClearSessionOnlyLocalStorage( content::StoragePartition* storage_partition, const std::vector& usages) { DCHECK(storage_policy_.get()); DCHECK(storage_policy_->HasSessionOnlyOrigins()); for (size_t i = 0; i < usages.size(); ++i) { const content::LocalStorageUsageInfo& usage = usages[i]; if (!storage_policy_->IsStorageSessionOnly(usage.origin)) continue; storage_partition->GetDOMStorageContext()->DeleteLocalStorage(usage.origin); } } void SessionDataDeleter::DeleteSessionCookiesOnIOThread( ProfileIOData* profile_io_data) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); net::URLRequestContext* request_context = profile_io_data->GetMainRequestContext(); cookie_monster_ = request_context->cookie_store()->GetCookieMonster(); if (delete_only_by_session_only_policy_) { cookie_monster_->GetAllCookiesAsync( base::Bind(&SessionDataDeleter::DeleteSessionOnlyOriginCookies, this)); } else { cookie_monster_->DeleteSessionCookiesAsync( base::Bind(&SessionDataDeleter::DeleteSessionCookiesDone, this)); } } void SessionDataDeleter::DeleteSessionCookiesDone(int num_deleted) { cookie_monster_->GetAllCookiesAsync( base::Bind(&SessionDataDeleter::DeleteSessionOnlyOriginCookies, this)); } void SessionDataDeleter::DeleteSessionOnlyOriginCookies( const net::CookieList& cookies) { if (!storage_policy_.get() || !storage_policy_->HasSessionOnlyOrigins()) return; for (net::CookieList::const_iterator it = cookies.begin(); it != cookies.end(); ++it) { GURL url = net::cookie_util::CookieOriginToURL(it->Domain(), it->IsSecure()); if (!storage_policy_->IsStorageSessionOnly(url)) continue; cookie_monster_->DeleteCanonicalCookieAsync(*it, base::Bind(CookieDeleted)); } } } // namespace void DeleteSessionOnlyData(Profile* profile) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (browser_shutdown::IsTryingToQuit()) return; // TODO: Remove Athena special casing once the AthenaSessionRestore is in // place. #if defined(OS_ANDROID) SessionStartupPref::Type startup_pref_type = SessionStartupPref::GetDefaultStartupType(); #else SessionStartupPref::Type startup_pref_type = StartupBrowserCreator::GetSessionStartupPref( *base::CommandLine::ForCurrentProcess(), profile).type; #endif scoped_refptr deleter( new SessionDataDeleter(profile->GetSpecialStoragePolicy(), startup_pref_type == SessionStartupPref::LAST)); deleter->Run( Profile::GetDefaultStoragePartition(profile), ProfileIOData::FromResourceContext(profile->GetResourceContext())); }