| Index: chrome/browser/sessions/session_service.cc
|
| diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
|
| index 1c570ac88b87ac2ecf5d90cc2b44e9e4dd8996a0..9aad390df8969892370ff7915afa8eb7adc12fed 100644
|
| --- a/chrome/browser/sessions/session_service.cc
|
| +++ b/chrome/browser/sessions/session_service.cc
|
| @@ -9,13 +9,18 @@
|
| #include <set>
|
| #include <vector>
|
|
|
| +#include "base/command_line.h"
|
| #include "base/file_util.h"
|
| +#include "base/memory/ref_counted.h"
|
| #include "base/memory/scoped_vector.h"
|
| #include "base/message_loop.h"
|
| #include "base/metrics/histogram.h"
|
| #include "base/pickle.h"
|
| #include "base/threading/thread.h"
|
| #include "chrome/browser/extensions/extension_tab_helper.h"
|
| +#include "chrome/browser/net/chrome_cookie_notification_details.h"
|
| +#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
|
| +#include "chrome/browser/prefs/pref_service.h"
|
| #include "chrome/browser/prefs/session_startup_pref.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| #include "chrome/browser/sessions/restore_tab_helper.h"
|
| @@ -29,12 +34,17 @@
|
| #include "chrome/browser/ui/browser_window.h"
|
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
|
| #include "chrome/common/chrome_notification_types.h"
|
| +#include "chrome/common/chrome_switches.h"
|
| #include "chrome/common/extensions/extension.h"
|
| #include "content/browser/tab_contents/navigation_details.h"
|
| #include "content/browser/tab_contents/navigation_entry.h"
|
| #include "content/browser/tab_contents/tab_contents.h"
|
| -#include "content/public/browser/notification_service.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| #include "content/public/browser/notification_details.h"
|
| +#include "content/public/browser/notification_service.h"
|
| +#include "net/base/cookie_monster.h"
|
| +#include "net/url_request/url_request_context.h"
|
| +#include "net/url_request/url_request_context_getter.h"
|
|
|
| #if defined(OS_MACOSX)
|
| #include "chrome/browser/app_controller_cppsafe_mac.h"
|
| @@ -68,6 +78,9 @@ static const int kWritesPerReset = 250;
|
|
|
| namespace {
|
|
|
| +const FilePath::CharType kSessionCookiesDatabaseName[] =
|
| + FILE_PATH_LITERAL("SessionCookies");
|
| +
|
| // The callback from GetLastSession is internally routed to SessionService
|
| // first and then the caller. This is done so that the SessionWindows can be
|
| // recreated from the SessionCommands and the SessionWindows passed to the
|
| @@ -139,6 +152,94 @@ struct PinnedStatePayload {
|
|
|
| } // namespace
|
|
|
| +// |SessionService::SessionCookieStore| stores session cookies in a
|
| +// |CookieMonster| and restores them. The constructor should be called in the
|
| +// UI thread, and all other functions should be called in the IO thread.
|
| +class SessionService::SessionCookieStore
|
| + : public base::RefCountedThreadSafe<
|
| + SessionCookieStore,
|
| + content::BrowserThread::DeleteOnIOThread> {
|
| + public:
|
| + typedef base::Callback<void()> CookieOperationCallback;
|
| +
|
| + explicit SessionCookieStore(const FilePath& path)
|
| + : path_(path) {
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&SessionCookieStore::InitializeOnIOThread, this));
|
| + }
|
| +
|
| + ~SessionCookieStore() {
|
| + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
|
| + }
|
| +
|
| + void RestoreSessionCookies(
|
| + net::URLRequestContextGetter* url_request_context_getter) {
|
| + net::CookieMonster* real_cookie_monster =
|
| + url_request_context_getter->GetURLRequestContext()->cookie_store()->
|
| + GetCookieMonster();
|
| + real_cookie_monster->MergeSessionCookies(session_cookie_monster_);
|
| + }
|
| +
|
| + void ForgetSessionCookies() {
|
| + session_cookie_monster_->DeleteAllAsync(
|
| + net::CookieMonster::DeleteCallback());
|
| + }
|
| +
|
| + class CanonicalCookieWrapper :
|
| + public base::RefCountedThreadSafe<CanonicalCookieWrapper> {
|
| + public:
|
| + explicit CanonicalCookieWrapper(
|
| + const net::CookieMonster::CanonicalCookie* cookie)
|
| + : cookie_(new net::CookieMonster::CanonicalCookie(*cookie)) {}
|
| + ~CanonicalCookieWrapper() {}
|
| +
|
| + scoped_ptr<net::CookieMonster::CanonicalCookie> cookie_;
|
| + };
|
| +
|
| + void AddSessionCookie(CanonicalCookieWrapper* wrapper) {
|
| + // Set the cookie as permanent so that |session_cookie_monster_| syncs it
|
| + // to its backend store.
|
| + wrapper->cookie_->SetPersistent(true);
|
| + net::CookieList cookie_list;
|
| + cookie_list.push_back(*(wrapper->cookie_));
|
| + session_cookie_monster_->InitializeFrom(cookie_list);
|
| + }
|
| +
|
| + void RemoveSessionCookie(CanonicalCookieWrapper* wrapper,
|
| + const CookieOperationCallback& callback) {
|
| + session_cookie_monster_->DeleteCanonicalCookieAsync(
|
| + *(wrapper->cookie_),
|
| + base::Bind(&SessionCookieStore::OnCookieDeleted,
|
| + this,
|
| + callback));
|
| + }
|
| +
|
| + private:
|
| + void InitializeOnIOThread() {
|
| + session_cookie_store_ = new SQLitePersistentCookieStore(path_);
|
| + session_cookie_monster_ =
|
| + new net::CookieMonster(session_cookie_store_.get(), NULL);
|
| + }
|
| +
|
| + void OnCookieDeleted(const CookieOperationCallback& callback,
|
| + bool success) {
|
| + if (!callback.is_null()) {
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::UI, FROM_HERE,
|
| + base::Bind(&SessionCookieStore::InvokeCallback, this, callback));
|
| + }
|
| + }
|
| +
|
| + void InvokeCallback(const CookieOperationCallback& callback) {
|
| + callback.Run();
|
| + }
|
| +
|
| + FilePath path_;
|
| + scoped_refptr<SQLitePersistentCookieStore> session_cookie_store_;
|
| + scoped_refptr<net::CookieMonster> session_cookie_monster_;
|
| +};
|
| +
|
| // SessionService -------------------------------------------------------------
|
|
|
| SessionService::SessionService(Profile* profile)
|
| @@ -147,7 +248,10 @@ SessionService::SessionService(Profile* profile)
|
| move_on_new_browser_(false),
|
| save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
|
| save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
|
| - save_delay_in_hrs_(base::TimeDelta::FromHours(8)) {
|
| + save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
|
| + enable_restore_session_data_(
|
| + CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableRestoreSessionState)) {
|
| Init();
|
| }
|
|
|
| @@ -157,7 +261,10 @@ SessionService::SessionService(const FilePath& save_path)
|
| move_on_new_browser_(false),
|
| save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
|
| save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
|
| - save_delay_in_hrs_(base::TimeDelta::FromHours(8)) {
|
| + save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
|
| + enable_restore_session_data_(
|
| + CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableRestoreSessionState)) {
|
| Init();
|
| }
|
|
|
| @@ -180,6 +287,12 @@ void SessionService::MoveCurrentSessionToLastSession() {
|
|
|
| Save();
|
|
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::IO, FROM_HERE,
|
| + base::Bind(
|
| + &SessionCookieStore::ForgetSessionCookies,
|
| + session_cookie_store_));
|
| +
|
| if (!backend_thread()) {
|
| backend()->MoveCurrentSessionToLastSession();
|
| } else {
|
| @@ -465,6 +578,33 @@ void SessionService::Save() {
|
| }
|
| }
|
|
|
| +void SessionService::RestoreOrResetSessionState(bool restore) {
|
| + // Schedule the restoring or deletion of the session cookies in the IO
|
| + // thread. |RestoreSessionCookies| (or |ForgetSessionCookies|) will be
|
| + // executed be done before any cookies are served, since the cookies will be
|
| + // served on the IO thread.
|
| + if (!session_cookie_store_.get())
|
| + return;
|
| +
|
| + bool restore_session_cookies = enable_restore_session_data_ &&
|
| + restore &&
|
| + profile();
|
| + if (restore_session_cookies) {
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::IO, FROM_HERE,
|
| + base::Bind(
|
| + &SessionCookieStore::RestoreSessionCookies,
|
| + session_cookie_store_,
|
| + make_scoped_refptr(profile()->GetRequestContext())));
|
| + } else {
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::IO, FROM_HERE,
|
| + base::Bind(
|
| + &SessionCookieStore::ForgetSessionCookies,
|
| + session_cookie_store_));
|
| + }
|
| +}
|
| +
|
| void SessionService::Init() {
|
| // Register for the notifications we're interested in.
|
| registrar_.Add(this, content::NOTIFICATION_TAB_PARENTED,
|
| @@ -482,6 +622,13 @@ void SessionService::Init() {
|
| registrar_.Add(
|
| this, chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
|
| content::NotificationService::AllSources());
|
| + if (enable_restore_session_data_ && profile()) {
|
| + registrar_.Add(
|
| + this, chrome::NOTIFICATION_COOKIE_CHANGED,
|
| + content::Source<Profile>(profile()));
|
| + session_cookie_store_ = new SessionCookieStore(
|
| + profile()->GetPath().Append(kSessionCookiesDatabaseName));
|
| + }
|
| }
|
|
|
| bool SessionService::ShouldNewWindowStartSession() {
|
| @@ -650,6 +797,35 @@ void SessionService::Observe(int type,
|
| break;
|
| }
|
|
|
| + case chrome::NOTIFICATION_COOKIE_CHANGED: {
|
| + if (enable_restore_session_data_ && session_cookie_store_.get()) {
|
| + ChromeCookieDetails* cookie_details =
|
| + content::Details<ChromeCookieDetails>(details).ptr();
|
| + if (!cookie_details->cookie->IsPersistent()) {
|
| + scoped_refptr<SessionCookieStore::CanonicalCookieWrapper> cookie =
|
| + new SessionCookieStore::CanonicalCookieWrapper(
|
| + cookie_details->cookie);
|
| + if (cookie_details->removed) {
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::IO, FROM_HERE,
|
| + base::Bind(
|
| + &SessionCookieStore::RemoveSessionCookie,
|
| + session_cookie_store_,
|
| + cookie,
|
| + SessionCookieStore::CookieOperationCallback()));
|
| + } else {
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::IO, FROM_HERE,
|
| + base::Bind(
|
| + &SessionCookieStore::AddSessionCookie,
|
| + session_cookie_store_,
|
| + cookie));
|
| + }
|
| + }
|
| + }
|
| + break;
|
| + }
|
| +
|
| default:
|
| NOTREACHED();
|
| }
|
|
|