diff options
Diffstat (limited to 'chrome/browser')
8 files changed, 390 insertions, 8 deletions
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc index 7fd24c0..b1ffcd1 100644 --- a/chrome/browser/background/background_mode_manager.cc +++ b/chrome/browser/background/background_mode_manager.cc @@ -262,7 +262,7 @@ void BackgroundModeManager::LaunchBackgroundApplication( OpenApplication(AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB)); } -bool BackgroundModeManager::IsBackgroundModeActiveForTest() { +bool BackgroundModeManager::IsBackgroundModeActive() { return in_background_mode_; } diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h index 118d386..0494f5a 100644 --- a/chrome/browser/background/background_mode_manager.h +++ b/chrome/browser/background/background_mode_manager.h @@ -60,6 +60,9 @@ class BackgroundModeManager static void LaunchBackgroundApplication(Profile* profile, const extensions::Extension* extension); + // Returns true if background mode is active. + virtual bool IsBackgroundModeActive(); + // For testing purposes. int NumberOfBackgroundModeData(); @@ -246,9 +249,6 @@ class BackgroundModeManager // (virtual to allow overriding in tests). virtual bool IsBackgroundModePrefEnabled() const; - // Returns true if background mode is active. Used only by tests. - bool IsBackgroundModeActiveForTest(); - // Turns off background mode if it's currently enabled. void DisableBackgroundMode(); diff --git a/chrome/browser/extensions/app_background_page_apitest.cc b/chrome/browser/extensions/app_background_page_apitest.cc index f07952c..35165ec 100644 --- a/chrome/browser/extensions/app_background_page_apitest.cc +++ b/chrome/browser/extensions/app_background_page_apitest.cc @@ -69,7 +69,7 @@ class AppBackgroundPageApiTest : public ExtensionApiTest { DLOG(WARNING) << "Skipping check - background mode disabled"; return true; } - if (manager->IsBackgroundModeActiveForTest() == expected_background_mode) + if (manager->IsBackgroundModeActive() == expected_background_mode) return true; // We are not currently in the expected state - wait for the state to @@ -78,7 +78,7 @@ class AppBackgroundPageApiTest : public ExtensionApiTest { chrome::NOTIFICATION_BACKGROUND_MODE_CHANGED, content::NotificationService::AllSources()); watcher.Wait(); - return manager->IsBackgroundModeActiveForTest() == expected_background_mode; + return manager->IsBackgroundModeActive() == expected_background_mode; #endif } diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc index 11ea512..ad68c95 100644 --- a/chrome/browser/sessions/better_session_restore_browsertest.cc +++ b/chrome/browser/sessions/better_session_restore_browsertest.cc @@ -9,16 +9,21 @@ #include "base/path_service.h" #include "base/prefs/pref_service.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/background/background_mode_manager.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/content_settings/cookie_settings.h" +#include "chrome/browser/defaults.h" #include "chrome/browser/infobars/confirm_infobar_delegate.h" #include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_impl.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/sessions/session_backend.h" #include "chrome/browser/sessions/session_service_factory.h" +#include "chrome/browser/sessions/session_service_test_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_iterator.h" @@ -41,6 +46,10 @@ #include "net/url_request/url_request_filter.h" #include "net/url_request/url_request_test_job.h" +#if defined(OS_MACOSX) +#include "base/mac/scoped_nsautorelease_pool.h" +#endif + namespace { Browser* FindOneOtherBrowserForProfile(Profile* profile, @@ -97,6 +106,27 @@ net::URLRequestJob* URLRequestFakerForPostRequests( true); } +class FakeBackgroundModeManager : public BackgroundModeManager { + public: + FakeBackgroundModeManager() + : BackgroundModeManager( + CommandLine::ForCurrentProcess(), + &g_browser_process->profile_manager()->GetProfileInfoCache()), + background_mode_active_(false) {} + + void SetBackgroundModeActive(bool active) { + background_mode_active_ = active; + } + + virtual bool IsBackgroundModeActive() OVERRIDE { + return background_mode_active_; + } + + private: + bool background_mode_active_; + +}; + } // namespace class BetterSessionRestoreTest : public InProcessBrowserTest { @@ -138,6 +168,15 @@ class BetterSessionRestoreTest : public InProcessBrowserTest { } protected: + virtual void SetUpOnMainThread() OVERRIDE { + SessionServiceTestHelper helper( + SessionServiceFactory::GetForProfile(browser()->profile())); + helper.SetForceBrowserNotAliveWithNoWindows(true); + helper.ReleaseService(); + g_browser_process->set_background_mode_manager_for_test( + scoped_ptr<BackgroundModeManager>(new FakeBackgroundModeManager)); + } + void StoreDataWithPage(const std::string& filename) { StoreDataWithPage(browser(), filename); } @@ -184,7 +223,11 @@ class BetterSessionRestoreTest : public InProcessBrowserTest { } void CheckReloadedPageNotRestored() { - CheckTitle(browser(), title_storing_); + CheckReloadedPageNotRestored(browser()); + } + + void CheckReloadedPageNotRestored(Browser* browser) { + CheckTitle(browser, title_storing_); } void CheckTitle(Browser* browser, const string16& expected_title) { @@ -230,7 +273,12 @@ class BetterSessionRestoreTest : public InProcessBrowserTest { } void CheckFormRestored(bool text_present, bool password_present) { - CheckReloadedPageRestored(); + CheckFormRestored(browser(), text_present, password_present); + } + + void CheckFormRestored( + Browser* browser, bool text_present, bool password_present) { + CheckReloadedPageRestored(browser); if (text_present) { EXPECT_TRUE(g_last_upload_bytes.Get().find("posted-text") != std::string::npos); @@ -255,6 +303,36 @@ class BetterSessionRestoreTest : public InProcessBrowserTest { } } + void CloseBrowserSynchronously(Browser* browser) { + content::WindowedNotificationObserver observer( + chrome::NOTIFICATION_BROWSER_CLOSED, + content::NotificationService::AllSources()); + browser->window()->Close(); +#if defined(OS_MACOSX) + // BrowserWindowController depends on the auto release pool being recycled + // in the message loop to delete itself, which frees the Browser object + // which fires this event. + AutoreleasePool()->Recycle(); +#endif + observer.Wait(); + } + + virtual Browser* QuitBrowserAndRestore(Browser* browser) { + Profile* profile = browser->profile(); + + // Close the browser. + chrome::StartKeepAlive(); + CloseBrowserSynchronously(browser); + + // Create a new window, which should trigger session restore. + ui_test_utils::BrowserAddedObserver window_observer; + chrome::NewEmptyWindow(profile, chrome::HOST_DESKTOP_TYPE_NATIVE); + Browser* new_browser = window_observer.WaitForSingleNewBrowser(); + chrome::EndKeepAlive(); + + return new_browser; + } + std::string fake_server_address() { return fake_server_address_; } @@ -263,6 +341,18 @@ class BetterSessionRestoreTest : public InProcessBrowserTest { return test_path_; } + void EnableBackgroundMode() { + static_cast<FakeBackgroundModeManager*>( + g_browser_process->background_mode_manager())-> + SetBackgroundModeActive(true); + } + + void DisableBackgroundMode() { + static_cast<FakeBackgroundModeManager*>( + g_browser_process->background_mode_manager())-> + SetBackgroundModeActive(false); + } + private: const std::string fake_server_address_; const std::string test_path_; @@ -284,6 +374,17 @@ class ContinueWhereILeftOffTest : public BetterSessionRestoreTest { browser()->profile(), SessionStartupPref(SessionStartupPref::LAST)); } + protected: + virtual Browser* QuitBrowserAndRestore(Browser* browser) OVERRIDE { + content::WindowedNotificationObserver session_restore_observer( + chrome::NOTIFICATION_SESSION_RESTORE_DONE, + content::NotificationService::AllSources()); + Browser* new_browser = + BetterSessionRestoreTest::QuitBrowserAndRestore(browser); + session_restore_observer.Wait(); + return new_browser; + } + DISALLOW_COPY_AND_ASSIGN(ContinueWhereILeftOffTest); }; @@ -360,6 +461,53 @@ IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, PostWithPassword) { CheckFormRestored(false, false); } +IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, SessionCookiesBrowserClose) { + // Set the startup preference to "continue where I left off" and visit a page + // which stores a session cookie. + StoreDataWithPage("session_cookies.html"); + Browser* new_browser = QuitBrowserAndRestore(browser()); + // The browsing session will be continued; just wait for the page to reload + // and check the stored data. + CheckReloadedPageRestored(new_browser); +} + +IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, + CookiesClearedOnBrowserClose) { + StoreDataWithPage("cookies.html"); + // Normally cookies are restored. + Browser* new_browser = QuitBrowserAndRestore(browser()); + CheckReloadedPageRestored(new_browser); + // ... but not if the content setting is set to clear on exit. + CookieSettings::Factory::GetForProfile(new_browser->profile())-> + SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY); + // ... unless background mode is active. + EnableBackgroundMode(); + new_browser = QuitBrowserAndRestore(new_browser); + CheckReloadedPageRestored(new_browser); + + DisableBackgroundMode(); + new_browser = QuitBrowserAndRestore(new_browser); + if (browser_defaults::kBrowserAliveWithNoWindows) + CheckReloadedPageRestored(new_browser); + else + CheckReloadedPageNotRestored(new_browser); +} + +IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, PostBrowserClose) { + PostFormWithPage("post.html", false); + Browser* new_browser = QuitBrowserAndRestore(browser()); + CheckFormRestored(new_browser, true, false); +} + +IN_PROC_BROWSER_TEST_F(ContinueWhereILeftOffTest, + PostWithPasswordBrowserClose) { + PostFormWithPage("post_with_password.html", true); + Browser* new_browser = QuitBrowserAndRestore(browser()); + CheckReloadedPageRestored(new_browser); + // The form data contained passwords, so it's removed completely. + CheckFormRestored(new_browser, false, false); +} + class RestartTest : public BetterSessionRestoreTest { public: RestartTest() { } @@ -530,3 +678,38 @@ IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, CookiesClearedOnExit) { web_contents->GetURL().spec()); StoreDataWithPage("local_storage.html"); } + +IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, SessionCookiesBrowserClose) { + StoreDataWithPage("session_cookies.html"); + EnableBackgroundMode(); + Browser* new_browser = QuitBrowserAndRestore(browser()); + NavigateAndCheckStoredData(new_browser, "session_cookies.html"); + DisableBackgroundMode(); + new_browser = QuitBrowserAndRestore(new_browser); + if (browser_defaults::kBrowserAliveWithNoWindows) + NavigateAndCheckStoredData(new_browser, "session_cookies.html"); + else + StoreDataWithPage(new_browser, "session_cookies.html"); +} + +IN_PROC_BROWSER_TEST_F(NoSessionRestoreTest, CookiesClearedOnBrowserClose) { + StoreDataWithPage("cookies.html"); + + // Normally cookies are restored. + Browser* new_browser = QuitBrowserAndRestore(browser()); + NavigateAndCheckStoredData(new_browser, "cookies.html"); + + // ... but not if the content setting is set to clear on exit. + CookieSettings::Factory::GetForProfile(new_browser->profile())-> + SetDefaultCookieSetting(CONTENT_SETTING_SESSION_ONLY); + // ... unless background mode is active. + EnableBackgroundMode(); + new_browser = QuitBrowserAndRestore(new_browser); + NavigateAndCheckStoredData(new_browser, "cookies.html"); + DisableBackgroundMode(); + new_browser = QuitBrowserAndRestore(new_browser); + if (browser_defaults::kBrowserAliveWithNoWindows) + NavigateAndCheckStoredData(new_browser, "cookies.html"); + else + StoreDataWithPage(new_browser, "cookies.html"); +} diff --git a/chrome/browser/sessions/session_data_deleter.cc b/chrome/browser/sessions/session_data_deleter.cc new file mode 100644 index 0000000..2378731 --- /dev/null +++ b/chrome/browser/sessions/session_data_deleter.cc @@ -0,0 +1,169 @@ +// 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 "chrome/browser/browser_shutdown.h" +#include "chrome/browser/net/chrome_url_request_context.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 "webkit/browser/quota/special_storage_policy.h" + +namespace { + +void CookieDeleted(bool success) { + DCHECK(success); +} + +class SessionDataDeleter + : public base::RefCountedThreadSafe<SessionDataDeleter> { + public: + SessionDataDeleter(quota::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>; + ~SessionDataDeleter(); + + // Deletes the local storage described by |usages| for origins which are + // session-only. + void ClearSessionOnlyLocalStorage( + content::StoragePartition* storage_partition, + const std::vector<content::LocalStorageUsageInfo>& 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); + + base::WeakPtr<ChromeURLRequestContext> request_context_; + scoped_refptr<quota::SpecialStoragePolicy> storage_policy_; + const bool delete_only_by_session_only_policy_; + + DISALLOW_COPY_AND_ASSIGN(SessionDataDeleter); +}; + +SessionDataDeleter::SessionDataDeleter( + quota::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) { + 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<content::LocalStorageUsageInfo>& usages) { + for (std::vector<content::LocalStorageUsageInfo>::const_iterator it = + usages.begin(); + it != usages.end(); + ++it) { + if (storage_policy_->IsStorageSessionOnly(it->origin)) + storage_partition->GetDOMStorageContext()->DeleteLocalStorage(it->origin); + } +} + +void SessionDataDeleter::DeleteSessionCookiesOnIOThread( + ProfileIOData* profile_io_data) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + ChromeURLRequestContext* request_context = + profile_io_data->GetMainRequestContext(); + request_context_ = request_context->GetWeakPtr(); + net::CookieMonster* 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) { + ChromeURLRequestContext* request_context = request_context_.get(); + if (!request_context) + return; + + request_context->cookie_store()->GetCookieMonster()->GetAllCookiesAsync( + base::Bind(&SessionDataDeleter::DeleteSessionOnlyOriginCookies, this)); +} + +void SessionDataDeleter::DeleteSessionOnlyOriginCookies( + const net::CookieList& cookies) { + ChromeURLRequestContext* request_context = request_context_.get(); + if (!request_context) + return; + + net::CookieMonster* cookie_monster = + request_context->cookie_store()->GetCookieMonster(); + for (net::CookieList::const_iterator it = cookies.begin(); + it != cookies.end(); + ++it) { + if (storage_policy_->IsStorageSessionOnly( + net::cookie_util::CookieOriginToURL(it->Domain(), + it->IsSecure()))) { + cookie_monster->DeleteCanonicalCookieAsync(*it, + base::Bind(CookieDeleted)); + } + } +} + +} // namespace + +void DeleteSessionOnlyData(Profile* profile) { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); + if (browser_shutdown::IsTryingToQuit()) + return; + +#if defined(OS_ANDROID) + SessionStartupPref::Type startup_pref_type = + SessionStartupPref::GetDefaultStartupType(); +#else + SessionStartupPref::Type startup_pref_type = + StartupBrowserCreator::GetSessionStartupPref( + *CommandLine::ForCurrentProcess(), profile).type; +#endif + + scoped_refptr<SessionDataDeleter> deleter( + new SessionDataDeleter(profile->GetSpecialStoragePolicy(), + startup_pref_type == SessionStartupPref::LAST)); + deleter->Run( + Profile::GetDefaultStoragePartition(profile), + ProfileIOData::FromResourceContext(profile->GetResourceContext())); +} diff --git a/chrome/browser/sessions/session_data_deleter.h b/chrome/browser/sessions/session_data_deleter.h new file mode 100644 index 0000000..710cd7e --- /dev/null +++ b/chrome/browser/sessions/session_data_deleter.h @@ -0,0 +1,15 @@ +// 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. + +#ifndef CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_ +#define CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_ + +class Profile; + +// Clears cookies and local storage for origins that are session-only and clears +// session cookies unless the startup preference is to continue the previous +// session. +void DeleteSessionOnlyData(Profile* profile); + +#endif // CHROME_BROWSER_SESSIONS_SESSION_DATA_DELETER_H_ diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc index 8af2138..0b7aca8 100644 --- a/chrome/browser/sessions/session_service.cc +++ b/chrome/browser/sessions/session_service.cc @@ -16,12 +16,16 @@ #include "base/metrics/histogram.h" #include "base/pickle.h" #include "base/threading/thread.h" +#include "chrome/browser/background/background_mode_manager.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/defaults.h" #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_backend.h" #include "chrome/browser/sessions/session_command.h" +#include "chrome/browser/sessions/session_data_deleter.h" #include "chrome/browser/sessions/session_restore.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/sessions/session_types.h" @@ -338,6 +342,14 @@ void SessionService::WindowClosed(const SessionID& window_id) { else ScheduleCommand(CreateWindowClosedCommand(window_id.id())); } + // Clear session data if the last window for a profile has been closed and + // closing the last window would normally close Chrome, unless background mode + // is active. + if (!has_open_trackable_browsers_ && + !browser_defaults::kBrowserAliveWithNoWindows && + !g_browser_process->background_mode_manager()->IsBackgroundModeActive()) { + DeleteSessionOnlyData(profile()); + } } void SessionService::SetWindowType(const SessionID& window_id, diff --git a/chrome/browser/sessions/session_service_factory.cc b/chrome/browser/sessions/session_service_factory.cc index 05cf198..7e928f9 100644 --- a/chrome/browser/sessions/session_service_factory.cc +++ b/chrome/browser/sessions/session_service_factory.cc @@ -5,6 +5,7 @@ #include "chrome/browser/sessions/session_service_factory.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sessions/session_data_deleter.h" #include "chrome/browser/sessions/session_service.h" #include "components/browser_context_keyed_service/browser_context_dependency_manager.h" @@ -33,6 +34,8 @@ SessionService* SessionServiceFactory::GetForProfileIfExisting( // static void SessionServiceFactory::ShutdownForProfile(Profile* profile) { + DeleteSessionOnlyData(profile); + // We're about to exit, force creation of the session service if it hasn't // been created yet. We do this to ensure session state matches the point in // time the user exited. |