Bug 722857 - Determine private browsing status for DOMStorage from owning docshell if available, and receive updates if its privacy status changes. r=mayhemer
authorJosh Matthews <josh@joshmatthews.net>
Fri, 25 May 2012 12:20:31 +0100
changeset 94956 5a903d496ab0a4096001dfc8cf30b11e97f739b6
parent 94955 8da4ff25a24a16a52d624a1b7f3586babef6bd81
child 94957 70cde80fa0954179c84214dbd7f84a94cb0a46d0
push id22770
push userryanvm@gmail.com
push dateSat, 26 May 2012 12:07:39 +0000
treeherdermozilla-central@cd62c4b8f500 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs722857
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 722857 - Determine private browsing status for DOMStorage from owning docshell if available, and receive updates if its privacy status changes. r=mayhemer
docshell/base/nsDocShell.cpp
dom/base/nsGlobalWindow.cpp
dom/indexedDB/CheckPermissionsHelper.cpp
dom/interfaces/storage/nsIDOMStorageManager.idl
dom/interfaces/storage/nsPIDOMStorage.h
dom/src/storage/PStorage.ipdl
dom/src/storage/StorageChild.cpp
dom/src/storage/StorageChild.h
dom/src/storage/StorageParent.cpp
dom/src/storage/StorageParent.h
dom/src/storage/nsDOMStorage.cpp
dom/src/storage/nsDOMStorage.h
dom/src/storage/nsDOMStorageDBWrapper.cpp
dom/src/storage/nsDOMStorageDBWrapper.h
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2395,17 +2395,17 @@ nsDocShell::GetSessionStorageForPrincipa
             do_CreateInstance("@mozilla.org/dom/storage;2");
         if (!newstorage)
             return NS_ERROR_OUT_OF_MEMORY;
 
         nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
         if (!pistorage)
             return NS_ERROR_FAILURE;
 
-        rv = pistorage->InitAsSessionStorage(aPrincipal, aDocumentURI);
+        rv = pistorage->InitAsSessionStorage(aPrincipal, aDocumentURI, mInPrivateBrowsing);
         if (NS_FAILED(rv))
             return rv;
 
         mStorages.Put(origin, newstorage);
 
         newstorage.swap(*aStorage);
 #if defined(PR_LOGGING) && defined(DEBUG)
         PR_LOG(gDocShellLog, PR_LOG_DEBUG,
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -99,16 +99,17 @@
 #include "nsPIDOMStorage.h"
 #include "nsDOMString.h"
 #include "nsIEmbeddingSiteWindow2.h"
 #include "nsThreadUtils.h"
 #include "nsEventStateManager.h"
 #include "nsIHttpProtocolHandler.h"
 #include "nsIJSContextStack.h"
 #include "nsIJSRuntimeService.h"
+#include "nsILoadContext.h"
 #include "nsIMarkupDocumentViewer.h"
 #include "nsIPresShell.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsIProgrammingLanguage.h"
 #include "nsIServiceManager.h"
 #include "nsIScriptGlobalObjectOwner.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScrollableFrame.h"
@@ -2238,16 +2239,29 @@ nsGlobalWindow::SetDocShell(nsIDocShell*
         mChromeEventHandler = piWindow->GetChromeEventHandler();
       }
       else NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
     }
 
     bool docShellActive;
     mDocShell->GetIsActive(&docShellActive);
     mIsBackground = !docShellActive;
+
+    if (mLocalStorage) {
+      nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_GetInterface(mLocalStorage);
+      if (obs) {
+        mDocShell->AddWeakPrivacyTransitionObserver(obs);
+      }
+    }
+    if (mSessionStorage) {
+      nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_GetInterface(mSessionStorage);
+      if (obs) {
+        mDocShell->AddWeakPrivacyTransitionObserver(obs);
+      }
+    }
   }
 }
 
 void
 nsGlobalWindow::SetOpenerWindow(nsIDOMWindow* aOpener,
                                 bool aOriginalOpener)
 {
   FORWARD_TO_OUTER_VOID(SetOpenerWindow, (aOpener, aOriginalOpener));
@@ -8079,16 +8093,21 @@ nsGlobalWindow::GetSessionStorage(nsIDOM
     if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
       PR_LogPrint("nsGlobalWindow %p tried to get a new sessionStorage %p", this, mSessionStorage.get());
     }
 #endif
 
     if (!mSessionStorage) {
       return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
     }
+
+    nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_GetInterface(mSessionStorage);
+    if (obs) {
+      docShell->AddWeakPrivacyTransitionObserver(obs);
+    }
   }
 
 #ifdef PR_LOGGING
     if (PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) {
       PR_LogPrint("nsGlobalWindow %p returns %p sessionStorage", this, mSessionStorage.get());
     }
 #endif
 
@@ -8108,37 +8127,45 @@ nsGlobalWindow::GetLocalStorage(nsIDOMSt
     return NS_OK;
   }
 
   if (!mLocalStorage) {
     *aLocalStorage = nsnull;
 
     nsresult rv;
 
-    bool unused;
-    if (!nsDOMStorage::CanUseStorage(&unused))
+    if (!nsDOMStorage::CanUseStorage())
       return NS_ERROR_DOM_SECURITY_ERR;
 
     nsIPrincipal *principal = GetPrincipal();
     if (!principal)
       return NS_OK;
 
     nsCOMPtr<nsIDOMStorageManager> storageManager =
       do_GetService("@mozilla.org/dom/storagemanager;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsString documentURI;
     if (mDocument) {
       mDocument->GetDocumentURI(documentURI);
     }
 
+    nsIDocShell* docShell = GetDocShell();
+    nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
+
     rv = storageManager->GetLocalStorageForPrincipal(principal,
                                                      documentURI,
+                                                     loadContext && loadContext->UsePrivateBrowsing(),
                                                      getter_AddRefs(mLocalStorage));
     NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_GetInterface(mLocalStorage);
+    if (obs) {
+      docShell->AddWeakPrivacyTransitionObserver(obs);
+    }
   }
 
   NS_ADDREF(*aLocalStorage = mLocalStorage);
   return NS_OK;
 }
 
 //*****************************************************************************
 // nsGlobalWindow::nsIDOMStorageIndexedDB
--- a/dom/indexedDB/CheckPermissionsHelper.cpp
+++ b/dom/indexedDB/CheckPermissionsHelper.cpp
@@ -2,16 +2,18 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CheckPermissionsHelper.h"
 
 #include "nsIDOMWindow.h"
+#include "nsILoadContext.h"
+#include "nsIWebNavigation.h"
 #include "nsIObserverService.h"
 #include "nsIPermissionManager.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIURI.h"
 
 #include "nsContentUtils.h"
 #include "nsDOMStorage.h"
@@ -51,17 +53,19 @@ GetIndexedDBPermissions(const nsACString
 
   nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(aWindow));
   NS_ENSURE_TRUE(sop, nsIPermissionManager::DENY_ACTION);
 
   if (nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) {
     return nsIPermissionManager::ALLOW_ACTION;
   }
 
-  if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) {
+  nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
+  if (loadContext && loadContext->UsePrivateBrowsing()) {
     // TODO Support private browsing indexedDB?
     return nsIPermissionManager::DENY_ACTION;
   }
 
   nsCOMPtr<nsIURI> uri;
   nsresult rv = NS_NewURI(getter_AddRefs(uri), aASCIIOrigin);
   NS_ENSURE_SUCCESS(rv, nsIPermissionManager::DENY_ACTION);
 
--- a/dom/interfaces/storage/nsIDOMStorageManager.idl
+++ b/dom/interfaces/storage/nsIDOMStorageManager.idl
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMStorage;
 interface nsIPrincipal;
 
-[scriptable, uuid(fd91ec36-7da8-43bb-b8f2-4b57a862a467)]
+[scriptable, uuid(1541da6c-a9fb-4a8f-af9d-4493c981491d)]
 interface nsIDOMStorageManager : nsISupports
 {
   /**
    * Return the amount of disk space used by a domain.  Usage is checked
    * against the domain of the page that set the key (the owner domain), not
    * the domain of the storage object.
    *
    * @param aOwnerDomain The domain to check.
@@ -28,10 +28,11 @@ interface nsIDOMStorageManager : nsISupp
   void clearOfflineApps();
 
   /**
    * Returns instance of localStorage object for aURI's origin.
    * This method ensures there is always only a single instance
    * for a single origin.
    */
   nsIDOMStorage getLocalStorageForPrincipal(in nsIPrincipal aPrincipal,
-                                            in DOMString aDocumentURI);
+                                            in DOMString aDocumentURI,
+                                            [optional] in bool aPrivate);
 };
--- a/dom/interfaces/storage/nsPIDOMStorage.h
+++ b/dom/interfaces/storage/nsPIDOMStorage.h
@@ -24,18 +24,20 @@ public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_PIDOMSTORAGE_IID)
 
   typedef enum {
     Unknown = 0,
     LocalStorage = 1,
     SessionStorage = 2
   } nsDOMStorageType;
 
-  virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) = 0;
-  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI) = 0;
+  virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                        bool aPrivate) = 0;
+  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                      bool aPrivate) = 0;
 
   virtual already_AddRefed<nsIDOMStorage> Clone() = 0;
   virtual already_AddRefed<nsIDOMStorage> Fork(const nsSubstring &aDocumentURI) = 0;
   virtual bool IsForkOf(nsIDOMStorage* aThat) = 0;
 
   virtual nsTArray<nsString> *GetKeys() = 0;
 
   virtual nsIPrincipal* Principal() = 0;
--- a/dom/src/storage/PStorage.ipdl
+++ b/dom/src/storage/PStorage.ipdl
@@ -30,18 +30,18 @@ union StorageItem
 // arguments for any given call to the parent, and returns the result.
 sync protocol PStorage
 {
   manager PContent;
 
 parent:
   __delete__();
 
-  Init(bool useDB, bool canUseChromePersist, bool sessionOnly, nsCString domain,
-       nsCString scopeDBKey, nsCString quotaDomainDBKey,
+  Init(bool useDB, bool canUseChromePersist, bool sessionOnly, bool isPrivate,
+       nsCString domain, nsCString scopeDBKey, nsCString quotaDomainDBKey,
        nsCString quotaETLDplus1DomainDBKey, PRUint32 storageType);
   
   sync GetKeys(bool callerSecure)
       returns (nsString[] keys);
   sync GetLength(bool callerSecure, bool sessionOnly)
       returns (PRUint32 length, nsresult rv);
   sync GetKey(bool callerSecure, bool sessionOnly, PRUint32 index)
       returns (nsString key, nsresult rv);
@@ -55,12 +55,14 @@ parent:
       returns (PRInt32 oldCount, nsresult rv);
 
   sync GetDBValue(nsString key)
       returns (nsString value, bool secure, nsresult rv);
   sync SetDBValue(nsString key, nsString value, bool secure)
       returns (nsresult rv);
   sync SetSecure(nsString key, bool secure)
       returns (nsresult rv);
+
+  UpdatePrivateState(bool enabled);
 };
 
 }
 }
--- a/dom/src/storage/StorageChild.cpp
+++ b/dom/src/storage/StorageChild.cpp
@@ -10,17 +10,19 @@
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_1(StorageChild, mStorage)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(StorageChild)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StorageChild)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIPrivacyTransitionObserver)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrivacyTransitionObserver)
 NS_INTERFACE_MAP_END
 
 NS_IMETHODIMP_(nsrefcnt) StorageChild::Release(void)
 {
   NS_PRECONDITION(0 != mRefCnt, "dup release");
   NS_ASSERT_OWNINGTHREAD(StorageChild);
   nsISupports* base = NS_CYCLE_COLLECTION_CLASSNAME(StorageChild)::Upcast(this);
   nsrefcnt count = mRefCnt.decr(base);
@@ -74,31 +76,31 @@ StorageChild::CacheStoragePermissions()
 }
 
 void
 StorageChild::InitRemote()
 {
   ContentChild* child = ContentChild::GetSingleton();
   AddIPDLReference();
   child->SendPStorageConstructor(this, null_t());
-  SendInit(mUseDB, mCanUseChromePersist, mSessionOnly, mDomain, mScopeDBKey,
+  SendInit(mUseDB, mCanUseChromePersist, mSessionOnly, mInPrivateBrowsing, mDomain, mScopeDBKey,
            mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType);
 }
 
 void
-StorageChild::InitAsSessionStorage(nsIURI* aDomainURI)
+StorageChild::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
 {
-  DOMStorageBase::InitAsSessionStorage(aDomainURI);
+  DOMStorageBase::InitAsSessionStorage(aDomainURI, aPrivate);
   InitRemote();
 }
 
 void
-StorageChild::InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist)
+StorageChild::InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate)
 {
-  DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist);
+  DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist, aPrivate);
   InitRemote();
 }
 
 nsTArray<nsString>*
 StorageChild::GetKeys(bool aCallerSecure)
 {
   InfallibleTArray<nsString> remoteKeys;
   SendGetKeys(aCallerSecure, &remoteKeys);
@@ -229,15 +231,23 @@ StorageChild::SetSecure(const nsAString&
 nsresult
 StorageChild::CloneFrom(bool aCallerSecure, DOMStorageBase* aThat)
 {
   StorageChild* other = static_cast<StorageChild*>(aThat);
   ContentChild* child = ContentChild::GetSingleton();
   StorageClone clone(nsnull, other, aCallerSecure);
   AddIPDLReference();
   child->SendPStorageConstructor(this, clone);
-  SendInit(mUseDB, mCanUseChromePersist, mSessionOnly, mDomain, mScopeDBKey,
-           mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType);
+  SendInit(mUseDB, mCanUseChromePersist, mSessionOnly, mInPrivateBrowsing, mDomain,
+           mScopeDBKey, mQuotaDomainDBKey, mQuotaETLDplus1DomainDBKey, mStorageType);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+StorageChild::PrivateModeChanged(bool enabled)
+{
+  mInPrivateBrowsing = enabled;
+  SendUpdatePrivateState(enabled);
   return NS_OK;
 }
 
 }
 }
--- a/dom/src/storage/StorageChild.h
+++ b/dom/src/storage/StorageChild.h
@@ -11,26 +11,28 @@
 #include "nsDOMStorage.h"
 #include "nsCycleCollectionParticipant.h"
 
 namespace mozilla {
 namespace dom {
 
 class StorageChild : public PStorageChild
                    , public DOMStorageBase
+                   , public nsSupportsWeakReference
 {
 public:
-  NS_DECL_CYCLE_COLLECTION_CLASS(StorageChild)
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(StorageChild, nsIPrivacyTransitionObserver)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_NSIPRIVACYTRANSITIONOBSERVER
   
   StorageChild(nsDOMStorage* aOwner);
   StorageChild(nsDOMStorage* aOwner, StorageChild& aOther);
 
-  virtual void InitAsSessionStorage(nsIURI* aDomainURI);
-  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist);
+  virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
+  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
 
   virtual bool CacheStoragePermissions();
   
   virtual nsTArray<nsString>* GetKeys(bool aCallerSecure);
   virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength);
   virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey);
   virtual nsIDOMStorageItem* GetValue(bool aCallerSecure, const nsAString& aKey,
                                       nsresult* rv);
--- a/dom/src/storage/StorageParent.cpp
+++ b/dom/src/storage/StorageParent.cpp
@@ -25,29 +25,37 @@ StorageParent::StorageParent(const Stora
     mStorage->CloneFrom(clone.callerSecure(), other->mStorage);
   }
 }
 
 bool
 StorageParent::RecvInit(const bool& aUseDB,
                         const bool& aCanUseChromePersist,
                         const bool& aSessionOnly,
+                        const bool& aPrivate,
                         const nsCString& aDomain,
                         const nsCString& aScopeDBKey,
                         const nsCString& aQuotaDomainDBKey,
                         const nsCString& aQuotaETLDplus1DomainDBKey,
                         const PRUint32& aStorageType)
 {
-  mStorage->InitFromChild(aUseDB, aCanUseChromePersist, aSessionOnly, aDomain,
+  mStorage->InitFromChild(aUseDB, aCanUseChromePersist, aSessionOnly, aPrivate, aDomain,
                           aScopeDBKey, aQuotaDomainDBKey, aQuotaETLDplus1DomainDBKey,
                           aStorageType);
   return true;
 }
 
 bool
+StorageParent::RecvUpdatePrivateState(const bool& aEnabled)
+{
+  mStorage->PrivateModeChanged(aEnabled);
+  return true;
+}
+
+bool
 StorageParent::RecvGetKeys(const bool& aCallerSecure, InfallibleTArray<nsString>* aKeys)
 {
   // Callers are responsible for deallocating the array returned by mStorage->GetKeys
   nsAutoPtr<nsTArray<nsString> > keys(mStorage->GetKeys(aCallerSecure));
   aKeys->SwapElements(*keys);
   return true;
 }
 
--- a/dom/src/storage/StorageParent.h
+++ b/dom/src/storage/StorageParent.h
@@ -40,21 +40,24 @@ private:
                       nsresult* rv);
   bool RecvSetDBValue(const nsString& aKey, const nsString& aValue,
                       const bool& aSecure, nsresult* rv);
   bool RecvSetSecure(const nsString& aKey, const bool& aSecure, nsresult* rv);
 
   bool RecvInit(const bool& aUseDB,
                 const bool& aCanUseChromePersist,
                 const bool& aSessionOnly,
+                const bool& aPrivate,
                 const nsCString& aDomain,
                 const nsCString& aScopeDBKey,
                 const nsCString& aQuotaDomainDBKey,
                 const nsCString& aQuotaETLDplus1DomainDBKey,
                 const PRUint32& aStorageType);
 
+  bool RecvUpdatePrivateState(const bool& aEnabled);
+
   nsRefPtr<DOMStorageImpl> mStorage;
 };
 
 }
 }
 
 #endif
--- a/dom/src/storage/nsDOMStorage.cpp
+++ b/dom/src/storage/nsDOMStorage.cpp
@@ -1,17 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "StorageChild.h"
 #include "StorageParent.h"
+#include "mozilla/dom/ContentChild.h"
 #include "nsXULAppAPI.h"
 using mozilla::dom::StorageChild;
+using mozilla::dom::ContentChild;
 
 #include "prnetdb.h"
 #include "nsCOMPtr.h"
 #include "nsDOMError.h"
 #include "nsDOMClassInfoID.h"
 #include "nsDOMJSUtils.h"
 #include "nsUnicharUtils.h"
 #include "nsIDocument.h"
@@ -214,17 +216,16 @@ nsSessionStorageEntry::~nsSessionStorage
 
 //
 // nsDOMStorageManager
 //
 
 nsDOMStorageManager* nsDOMStorageManager::gStorageManager;
 
 nsDOMStorageManager::nsDOMStorageManager()
-  : mInPrivateBrowsing(false)
 {
 }
 
 NS_IMPL_ISUPPORTS3(nsDOMStorageManager,
                    nsIDOMStorageManager,
                    nsIObserver,
                    nsISupportsWeakReference)
 
@@ -247,29 +248,29 @@ nsDOMStorageManager::Initialize()
   if (!os)
     return NS_OK;
 
   nsresult rv;
   rv = os->AddObserver(gStorageManager, "cookie-changed", true);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = os->AddObserver(gStorageManager, "offline-app-removed", true);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = os->AddObserver(gStorageManager, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
-  NS_ENSURE_SUCCESS(rv, rv);
   rv = os->AddObserver(gStorageManager, "profile-after-change", true);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = os->AddObserver(gStorageManager, "perm-changed", true);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = os->AddObserver(gStorageManager, "browser:purge-domain-data", true);
   NS_ENSURE_SUCCESS(rv, rv);
   // Used for temporary table flushing
   rv = os->AddObserver(gStorageManager, "profile-before-change", true);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = os->AddObserver(gStorageManager, NS_DOMSTORAGE_FLUSH_TIMER_TOPIC, true);
   NS_ENSURE_SUCCESS(rv, rv);
+  rv = os->AddObserver(gStorageManager, "last-pb-context-exited", true);
+  NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 //static
 nsDOMStorageManager*
 nsDOMStorageManager::GetInstance()
 {
@@ -356,20 +357,16 @@ GetOfflineDomains(nsTArray<nsString>& aD
 }
 
 nsresult
 nsDOMStorageManager::Observe(nsISupports *aSubject,
                              const char *aTopic,
                              const PRUnichar *aData)
 {
   if (!strcmp(aTopic, "profile-after-change")) {
-    nsCOMPtr<nsIPrivateBrowsingService> pbs =
-      do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
-    if (pbs)
-      pbs->GetPrivateBrowsingEnabled(&gStorageManager->mInPrivateBrowsing);
   }
   else if (!strcmp(aTopic, "offline-app-removed")) {
     nsresult rv = DOMStorageImpl::InitDB();
     NS_ENSURE_SUCCESS(rv, rv);
     return DOMStorageImpl::gStorageDB->RemoveOwner(NS_ConvertUTF16toUTF8(aData),
                                                    true);
   } else if (!strcmp(aTopic, "cookie-changed") &&
              !nsCRT::strcmp(aData, NS_LITERAL_STRING("cleared").get())) {
@@ -378,26 +375,16 @@ nsDOMStorageManager::Observe(nsISupports
     nsresult rv = DOMStorageImpl::InitDB();
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Remove global storage for domains that aren't marked for offline use.
     nsTArray<nsString> domains;
     rv = GetOfflineDomains(domains);
     NS_ENSURE_SUCCESS(rv, rv);
     return DOMStorageImpl::gStorageDB->RemoveOwners(domains, true, false);
-  } else if (!strcmp(aTopic, NS_PRIVATE_BROWSING_SWITCH_TOPIC)) {
-    mStorages.EnumerateEntries(ClearStorage, nsnull);
-    if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).get()))
-      mInPrivateBrowsing = true;
-    else if (!nsCRT::strcmp(aData, NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).get()))
-      mInPrivateBrowsing = false;
-    nsresult rv = DOMStorageImpl::InitDB();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    return DOMStorageImpl::gStorageDB->DropPrivateBrowsingStorages();
   } else if (!strcmp(aTopic, "perm-changed")) {
     // Check for cookie permission change
     nsCOMPtr<nsIPermission> perm(do_QueryInterface(aSubject));
     if (perm) {
       nsCAutoString type;
       perm->GetType(type);
       if (type != NS_LITERAL_CSTRING("cookie"))
         return NS_OK;
@@ -466,30 +453,34 @@ nsDOMStorageManager::Observe(nsISupports
     }
   } else if (!strcmp(aTopic, NS_DOMSTORAGE_FLUSH_FORCE_TOPIC)) {
     if (DOMStorageImpl::gStorageDB) {
       DebugOnly<nsresult> rv =
         DOMStorageImpl::gStorageDB->FlushAndDeleteTemporaryTables(true);
       NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
                        "DOMStorage: temporary table commit failed");
     }
+  } else if (!strcmp(aTopic, "last-pb-context-exited")) {
+    if (DOMStorageImpl::gStorageDB) {
+      return DOMStorageImpl::gStorageDB->DropPrivateBrowsingStorages();
+    }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMStorageManager::GetUsage(const nsAString& aDomain,
                               PRInt32 *aUsage)
 {
   nsresult rv = DOMStorageImpl::InitDB();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return DOMStorageImpl::gStorageDB->GetUsage(NS_ConvertUTF16toUTF8(aDomain),
-                                              false, aUsage);
+                                              false, aUsage, false);
 }
 
 NS_IMETHODIMP
 nsDOMStorageManager::ClearOfflineApps()
 {
     nsresult rv = DOMStorageImpl::InitDB();
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -497,28 +488,29 @@ nsDOMStorageManager::ClearOfflineApps()
     rv = GetOfflineDomains(domains);
     NS_ENSURE_SUCCESS(rv, rv);
     return DOMStorageImpl::gStorageDB->RemoveOwners(domains, true, true);
 }
 
 NS_IMETHODIMP
 nsDOMStorageManager::GetLocalStorageForPrincipal(nsIPrincipal *aPrincipal,
                                                  const nsSubstring &aDocumentURI,
+                                                 bool aPrivate,
                                                  nsIDOMStorage **aResult)
 {
   NS_ENSURE_ARG_POINTER(aPrincipal);
   *aResult = nsnull;
 
   nsresult rv;
 
   nsRefPtr<nsDOMStorage2> storage = new nsDOMStorage2();
   if (!storage)
     return NS_ERROR_OUT_OF_MEMORY;
 
-  rv = storage->InitAsLocalStorage(aPrincipal, aDocumentURI);
+  rv = storage->InitAsLocalStorage(aPrincipal, aDocumentURI, aPrivate);
   if (NS_FAILED(rv))
     return rv;
 
   *aResult = storage.get();
   storage.forget();
 
   return NS_OK;
 }
@@ -565,65 +557,79 @@ NS_IMPL_CYCLE_COLLECTION_1(nsDOMStorage,
 DOMCI_DATA(StorageObsolete, nsDOMStorage)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMStorage)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMStorage)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorage)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorageObsolete)
   NS_INTERFACE_MAP_ENTRY(nsIDOMStorageObsolete)
   NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage)
+  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(StorageObsolete)
 NS_INTERFACE_MAP_END
 
+NS_IMETHODIMP
+nsDOMStorage::GetInterface(const nsIID & aIID, void **result)
+{
+  nsresult rv = mStorageImpl->QueryInterface(aIID, result);
+  if (NS_SUCCEEDED(rv))
+    return rv;
+  return QueryInterface(aIID, result);
+}
+
 nsresult
 NS_NewDOMStorage2(nsISupports* aOuter, REFNSIID aIID, void** aResult)
 {
   nsDOMStorage2* storage = new nsDOMStorage2();
   return storage->QueryInterface(aIID, aResult);
 }
 
 DOMStorageBase::DOMStorageBase()
   : mStorageType(nsPIDOMStorage::Unknown)
   , mUseDB(false)
   , mSessionOnly(true)
   , mCanUseChromePersist(false)
+  , mInPrivateBrowsing(false)
 {
 }
 
 DOMStorageBase::DOMStorageBase(DOMStorageBase& aThat)
   : mStorageType(aThat.mStorageType)
   , mUseDB(false) // Clones don't use the DB
   , mSessionOnly(true)
   , mDomain(aThat.mDomain)
   , mScopeDBKey(aThat.mScopeDBKey)
   , mQuotaETLDplus1DomainDBKey(aThat.mQuotaETLDplus1DomainDBKey)
   , mQuotaDomainDBKey(aThat.mQuotaDomainDBKey)
   , mCanUseChromePersist(aThat.mCanUseChromePersist)
+  , mInPrivateBrowsing(aThat.mInPrivateBrowsing)
 {
 }
 
 void
-DOMStorageBase::InitAsSessionStorage(nsIURI* aDomainURI)
+DOMStorageBase::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
 {
   // No need to check for a return value. If this would fail we would not get
   // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
   // nsDOMStorage::CanUseStorage before we query the storage manager for a new
   // sessionStorage. It calls GetAsciiHost on innermost URI. If it fails, we
   // won't get to InitAsSessionStorage.
   aDomainURI->GetAsciiHost(mDomain);
 
   mUseDB = false;
   mScopeDBKey.Truncate();
   mQuotaDomainDBKey.Truncate();
   mStorageType = nsPIDOMStorage::SessionStorage;
+  mInPrivateBrowsing = aPrivate;
 }
 
 void
 DOMStorageBase::InitAsLocalStorage(nsIURI* aDomainURI,
-                                   bool aCanUseChromePersist)
+                                   bool aCanUseChromePersist,
+                                   bool aPrivate)
 {
   // No need to check for a return value. If this would fail we would not get
   // here as we call GetPrincipalURIAndHost (nsDOMStorage.cpp:88) from
   // nsDOMStorage::CanUseStorage before we query the storage manager for a new
   // localStorage. It calls GetAsciiHost on innermost URI. If it fails, we won't
   // get to InitAsLocalStorage. Actually, mDomain will get replaced with
   // mPrincipal in bug 455070. It is not even used for localStorage.
   aDomainURI->GetAsciiHost(mDomain);
@@ -637,16 +643,17 @@ DOMStorageBase::InitAsLocalStorage(nsIUR
   mUseDB = !mScopeDBKey.IsEmpty();
 
   nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
                                                 true, false, mQuotaDomainDBKey);
   nsDOMStorageDBWrapper::CreateQuotaDomainDBKey(mDomain,
                                                 true, true, mQuotaETLDplus1DomainDBKey);
   mCanUseChromePersist = aCanUseChromePersist;
   mStorageType = nsPIDOMStorage::LocalStorage;
+  mInPrivateBrowsing = aPrivate;
 }
 
 PLDHashOperator
 SessionStorageTraverser(nsSessionStorageEntry* aEntry, void* userArg) {
   nsCycleCollectionTraversalCallback *cb = 
       static_cast<nsCycleCollectionTraversalCallback*>(userArg);
 
   cb->NoteXPCOMChild((nsIDOMStorageItem *) aEntry->mItem);
@@ -662,17 +669,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
     tmp->mItems.EnumerateEntries(SessionStorageTraverser, &cb);
   }
 }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMStorageImpl)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMStorageImpl)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMStorageImpl)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIPrivacyTransitionObserver)
+  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrivacyTransitionObserver)
 NS_INTERFACE_MAP_END
 
 DOMStorageImpl::DOMStorageImpl(nsDOMStorage* aStorage)
 {
   Init(aStorage);
 }
 
 DOMStorageImpl::DOMStorageImpl(nsDOMStorage* aStorage, DOMStorageImpl& aThat)
@@ -718,59 +727,62 @@ DOMStorageImpl::InitDB()
     }
   }
 
   return NS_OK;
 }
 
 void
 DOMStorageImpl::InitFromChild(bool aUseDB, bool aCanUseChromePersist,
-                              bool aSessionOnly, const nsACString& aDomain,
+                              bool aSessionOnly, bool aPrivate,
+                              const nsACString& aDomain,
                               const nsACString& aScopeDBKey,
                               const nsACString& aQuotaDomainDBKey,
                               const nsACString& aQuotaETLDplus1DomainDBKey,
                               PRUint32 aStorageType)
 {
   mUseDB = aUseDB;
   mCanUseChromePersist = aCanUseChromePersist;
   mSessionOnly = aSessionOnly;
+  mInPrivateBrowsing = aPrivate;
   mDomain = aDomain;
   mScopeDBKey = aScopeDBKey;
   mQuotaDomainDBKey = aQuotaDomainDBKey;
   mQuotaETLDplus1DomainDBKey = aQuotaETLDplus1DomainDBKey;
   mStorageType = static_cast<nsPIDOMStorage::nsDOMStorageType>(aStorageType);
 }
 
 void
 DOMStorageImpl::SetSessionOnly(bool aSessionOnly)
 {
   mSessionOnly = aSessionOnly;
 }
 
 void
-DOMStorageImpl::InitAsSessionStorage(nsIURI* aDomainURI)
+DOMStorageImpl::InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate)
 {
-  DOMStorageBase::InitAsSessionStorage(aDomainURI);
+  DOMStorageBase::InitAsSessionStorage(aDomainURI, aPrivate);
 }
 
 void
 DOMStorageImpl::InitAsLocalStorage(nsIURI* aDomainURI,
-                                   bool aCanUseChromePersist)
+                                   bool aCanUseChromePersist,
+                                   bool aPrivate)
 {
-  DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist);
+  DOMStorageBase::InitAsLocalStorage(aDomainURI, aCanUseChromePersist, aPrivate);
 }
 
 bool
 DOMStorageImpl::CacheStoragePermissions()
 {
   // If this is a cross-process situation, we don't have a real storage owner.
   // All the correct checks have been done on the child, so we just need to
   // make sure that our session-only status is correctly updated.
   if (!mOwner)
-    return nsDOMStorage::CanUseStorage(&mSessionOnly);
+    return CanUseStorage();
   
   return mOwner->CacheStoragePermissions();
 }
 
 bool
 DOMStorageImpl::CanUseChromePersist()
 {
   return mCanUseChromePersist;
@@ -1250,16 +1262,26 @@ DOMStorageImpl::Clear(bool aCallerSecure
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   *aOldCount = oldCount;
   mItems.Clear();
   return NS_OK;
 }
 
+NS_IMETHODIMP
+DOMStorageImpl::PrivateModeChanged(bool enabled)
+{
+  mInPrivateBrowsing = enabled;
+  CanUseStorage(); // cause mSessionOnly to update as well
+  mItems.Clear();
+  mItemsCachedVersion = 0;
+  return NS_OK;
+}
+
 nsDOMStorage::nsDOMStorage()
   : mStorageType(nsPIDOMStorage::Unknown)
   , mEventBroadcaster(nsnull)
 {
   if (XRE_GetProcessType() != GeckoProcessType_Default)
     mStorageImpl = new StorageChild(this);
   else
     mStorageImpl = new DOMStorageImpl(this);
@@ -1308,61 +1330,70 @@ GetDomainURI(nsIPrincipal *aPrincipal, b
   if (!innerURI)
     return NS_ERROR_UNEXPECTED;
   innerURI.forget(_domain);
 
   return NS_OK;
 }
 
 nsresult
-nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
+nsDOMStorage::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                   bool aPrivate)
 {
   nsCOMPtr<nsIURI> domainURI;
   nsresult rv = GetDomainURI(aPrincipal, true, getter_AddRefs(domainURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mDocumentURI = aDocumentURI;
   mPrincipal = aPrincipal;
 
   mStorageType = SessionStorage;
 
-  mStorageImpl->InitAsSessionStorage(domainURI);
+  mStorageImpl->InitAsSessionStorage(domainURI, aPrivate);
   return NS_OK;
 }
 
 nsresult
-nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
+nsDOMStorage::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                 bool aPrivate)
 {
   nsCOMPtr<nsIURI> domainURI;
   nsresult rv = GetDomainURI(aPrincipal, false, getter_AddRefs(domainURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   mDocumentURI = aDocumentURI;
   mPrincipal = aPrincipal;
 
   mStorageType = LocalStorage;
 
   bool canUseChromePersist = false;
   nsCOMPtr<nsIURI> URI;
   if (NS_SUCCEEDED(aPrincipal->GetURI(getter_AddRefs(URI))) && URI) {
     canUseChromePersist = URICanUseChromePersist(URI);
   }
   
-  mStorageImpl->InitAsLocalStorage(domainURI, canUseChromePersist);
+  mStorageImpl->InitAsLocalStorage(domainURI, canUseChromePersist, aPrivate);
   return NS_OK;
 }
 
+bool
+DOMStorageBase::CanUseStorage()
+{
+  return nsDOMStorage::CanUseStorage(this);
+}
+
 //static
 bool
-nsDOMStorage::CanUseStorage(bool* aSessionOnly)
+nsDOMStorage::CanUseStorage(DOMStorageBase* aStorage /* = NULL */)
 {
-  // check if the calling domain can use storage. Downgrade to session
-  // only if only session storage may be used.
-  NS_ASSERTION(aSessionOnly, "null session flag");
-  *aSessionOnly = false;
+  if (aStorage) {
+    // check if the calling domain can use storage. Downgrade to session
+    // only if only session storage may be used.
+    aStorage->mSessionOnly = false;
+  }
 
   if (!Preferences::GetBool(kStorageEnabled)) {
     return false;
   }
 
   // chrome can always use storage regardless of permission preferences
   if (nsContentUtils::IsCallerChrome())
     return true;
@@ -1393,43 +1424,44 @@ nsDOMStorage::CanUseStorage(bool* aSessi
 
   if (perm == nsIPermissionManager::DENY_ACTION)
     return false;
 
   // In private browsing mode we ougth to behave as in session-only cookies
   // mode to prevent detection of being in private browsing mode and ensuring
   // that there will be no traces left.
   if (perm == nsICookiePermission::ACCESS_SESSION ||
-      nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode()) {
-    *aSessionOnly = true;
+      (aStorage && aStorage->IsPrivate())) {
+    if (aStorage)
+      aStorage->mSessionOnly = true;
   }
   else if (perm != nsIPermissionManager::ALLOW_ACTION) {
     PRUint32 cookieBehavior = Preferences::GetUint(kCookiesBehavior);
     PRUint32 lifetimePolicy = Preferences::GetUint(kCookiesLifetimePolicy);
 
     // Treat "ask every time" as "reject always".
     // Chrome persistent pages can bypass this check.
     if ((cookieBehavior == BEHAVIOR_REJECT || lifetimePolicy == ASK_BEFORE_ACCEPT) &&
         !URICanUseChromePersist(subjectURI))
       return false;
 
-    if (lifetimePolicy == ACCEPT_SESSION)
-      *aSessionOnly = true;
+    if (lifetimePolicy == ACCEPT_SESSION && aStorage)
+      aStorage->mSessionOnly = true;
   }
 
   return true;
 }
 
 bool
 nsDOMStorage::CacheStoragePermissions()
 {
   // Bug 488446, disallowing storage use when in session only mode.
   // This is temporary fix before we find complete solution for storage
   // behavior in private browsing mode or session-only cookies mode.
-  if (!CanUseStorage(&mStorageImpl->mSessionOnly))
+  if (!mStorageImpl->CanUseStorage())
     return false;
 
   nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
   if (!ssm)
     return false;
 
   nsCOMPtr<nsIPrincipal> subjectPrincipal;
   nsresult rv = ssm->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal));
@@ -1696,53 +1728,65 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 DOMCI_DATA(Storage, nsDOMStorage2)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMStorage2)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMStorage2)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStorage2)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMStorage)
   NS_INTERFACE_MAP_ENTRY(nsIDOMStorage)
   NS_INTERFACE_MAP_ENTRY(nsPIDOMStorage)
+  NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(Storage)
 NS_INTERFACE_MAP_END
 
+NS_IMETHODIMP
+nsDOMStorage2::GetInterface(const nsIID & aIID, void **result)
+{
+  nsresult rv = mStorage->GetInterface(aIID, result);
+  if (NS_SUCCEEDED(rv))
+    return rv;
+  return QueryInterface(aIID, result);;
+}
+
 nsDOMStorage2::nsDOMStorage2()
 {
 }
 
 nsDOMStorage2::nsDOMStorage2(nsDOMStorage2& aThat)
 {
   mStorage = new nsDOMStorage(*aThat.mStorage.get());
   mPrincipal = aThat.mPrincipal;
 }
 
 nsresult
-nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
+nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                    bool aPrivate)
 {
   mStorage = new nsDOMStorage();
   if (!mStorage)
     return NS_ERROR_OUT_OF_MEMORY;
 
   mPrincipal = aPrincipal;
   mDocumentURI = aDocumentURI;
 
-  return mStorage->InitAsSessionStorage(aPrincipal, aDocumentURI);
+  return mStorage->InitAsSessionStorage(aPrincipal, aDocumentURI, aPrivate);
 }
 
 nsresult
-nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI)
+nsDOMStorage2::InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                  bool aPrivate)
 {
   mStorage = new nsDOMStorage();
   if (!mStorage)
     return NS_ERROR_OUT_OF_MEMORY;
 
   mPrincipal = aPrincipal;
   mDocumentURI = aDocumentURI;
 
-  return mStorage->InitAsLocalStorage(aPrincipal, aDocumentURI);
+  return mStorage->InitAsLocalStorage(aPrincipal, aDocumentURI, aPrivate);
 }
 
 already_AddRefed<nsIDOMStorage>
 nsDOMStorage2::Clone()
 {
   nsDOMStorage2* storage = new nsDOMStorage2(*this);
   if (!storage)
     return nsnull;
@@ -1902,17 +1946,17 @@ nsDOMStorage2::Clear()
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStorageItem)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStorageItem)
   {
     tmp->mStorage = nsnull;
   }
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStorageItem)
   {
-    cb.NoteXPCOMChild((nsISupports*) tmp->mStorage);
+    cb.NoteXPCOMChild(tmp->mStorage);
   }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMStorageItem)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMStorageItem)
 
 DOMCI_DATA(StorageItem, nsDOMStorageItem)
 
--- a/dom/src/storage/nsDOMStorage.h
+++ b/dom/src/storage/nsDOMStorage.h
@@ -7,28 +7,30 @@
 #define nsDOMStorage_h___
 
 #include "nscore.h"
 #include "nsAutoPtr.h"
 #include "nsIDOMStorageObsolete.h"
 #include "nsIDOMStorage.h"
 #include "nsIDOMStorageItem.h"
 #include "nsIPermissionManager.h"
+#include "nsIPrivacyTransitionObserver.h"
 #include "nsInterfaceHashtable.h"
 #include "nsVoidArray.h"
 #include "nsTArray.h"
 #include "nsPIDOMStorage.h"
 #include "nsIDOMToString.h"
 #include "nsDOMEvent.h"
 #include "nsIDOMStorageEvent.h"
 #include "nsIDOMStorageManager.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIObserver.h"
 #include "nsITimer.h"
 #include "nsWeakReference.h"
+#include "nsIInterfaceRequestor.h"
 
 #include "nsDOMStorageDBWrapper.h"
 
 #define IS_PERMISSION_ALLOWED(perm) \
       ((perm) != nsIPermissionManager::UNKNOWN_ACTION && \
       (perm) != nsIPermissionManager::DENY_ACTION)
 
 class nsDOMStorage;
@@ -82,66 +84,70 @@ public:
 
   nsDOMStorageManager();
 
   void AddToStoragesHash(DOMStorageImpl* aStorage);
   void RemoveFromStoragesHash(DOMStorageImpl* aStorage);
 
   nsresult ClearAllStorages();
 
-  bool InPrivateBrowsingMode() { return mInPrivateBrowsing; }
-
   static nsresult Initialize();
   static nsDOMStorageManager* GetInstance();
   static void Shutdown();
   static void ShutdownDB();
 
   /**
    * Checks whether there is any data waiting to be flushed from a temp table.
    */
   bool UnflushedDataExists();
 
   static nsDOMStorageManager* gStorageManager;
 
 protected:
 
   nsTHashtable<nsDOMStorageEntry> mStorages;
-  bool mInPrivateBrowsing;
 };
 
-class DOMStorageBase : public nsISupports
+class DOMStorageBase : public nsIPrivacyTransitionObserver
 {
 public:
   DOMStorageBase();
   DOMStorageBase(DOMStorageBase&);
 
-  virtual void InitAsSessionStorage(nsIURI* aDomainURI);
-  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist);
+  virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
+  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
 
   virtual nsTArray<nsString>* GetKeys(bool aCallerSecure) = 0;
   virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength) = 0;
   virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey) = 0;
   virtual nsIDOMStorageItem* GetValue(bool aCallerSecure, const nsAString& aKey,
                                       nsresult* rv) = 0;
   virtual nsresult SetValue(bool aCallerSecure, const nsAString& aKey,
                             const nsAString& aData, nsAString& aOldValue) = 0;
   virtual nsresult RemoveValue(bool aCallerSecure, const nsAString& aKey,
                                nsAString& aOldValue) = 0;
   virtual nsresult Clear(bool aCallerSecure, PRInt32* aOldCount) = 0;
-  
+
+  // Call nsDOMStorage::CanUseStorage with |this|
+  bool CanUseStorage();
+
   // If true, the contents of the storage should be stored in the
   // database, otherwise this storage should act like a session
   // storage.
   // This call relies on mSessionOnly, and should only be used
   // after a CacheStoragePermissions() call.  See the comments
   // for mSessionOnly below.
   bool UseDB() {
     return mUseDB;
   }
 
+  bool IsPrivate() {
+    return mInPrivateBrowsing;
+  }
+
   // retrieve the value and secure state corresponding to a key out of storage.
   virtual nsresult
   GetDBValue(const nsAString& aKey,
              nsAString& aValue,
              bool* aSecure) = 0;
 
   // set the value corresponding to a key in the storage. If
   // aSecure is false, then attempts to modify a secure value
@@ -193,31 +199,33 @@ protected:
 
   // keys are used for database queries.
   // see comments of the getters bellow.
   nsCString mScopeDBKey;
   nsCString mQuotaETLDplus1DomainDBKey;
   nsCString mQuotaDomainDBKey;
 
   bool mCanUseChromePersist;
+  bool mInPrivateBrowsing;
 };
 
 class DOMStorageImpl : public DOMStorageBase
-
+                     , public nsSupportsWeakReference
 {
 public:
-  NS_DECL_CYCLE_COLLECTION_CLASS(DOMStorageImpl)
+  NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DOMStorageImpl, nsIPrivacyTransitionObserver)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_NSIPRIVACYTRANSITIONOBSERVER
 
   DOMStorageImpl(nsDOMStorage*);
   DOMStorageImpl(nsDOMStorage*, DOMStorageImpl&);
   ~DOMStorageImpl();
 
-  virtual void InitAsSessionStorage(nsIURI* aDomainURI);
-  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist);
+  virtual void InitAsSessionStorage(nsIURI* aDomainURI, bool aPrivate);
+  virtual void InitAsLocalStorage(nsIURI* aDomainURI, bool aCanUseChromePersist, bool aPrivate);
 
   bool SessionOnly() {
     return mSessionOnly;
   }
 
   virtual nsTArray<nsString>* GetKeys(bool aCallerSecure);
   virtual nsresult GetLength(bool aCallerSecure, PRUint32* aLength);
   virtual nsresult GetKey(bool aCallerSecure, PRUint32 aIndex, nsAString& aKey);
@@ -278,17 +286,17 @@ private:
   friend class nsDOMStoragePersistentDB;
   friend class StorageParent;
 
   void Init(nsDOMStorage*);
 
   // Cross-process storage implementations never have InitAs(Session|Local|Global)Storage
   // called, so the appropriate initialization needs to happen from the child.
   void InitFromChild(bool aUseDB, bool aCanUseChromePersist, bool aSessionOnly,
-                     const nsACString& aDomain,
+                     bool aPrivate, const nsACString& aDomain,
                      const nsACString& aScopeDBKey,
                      const nsACString& aQuotaDomainDBKey,
                      const nsACString& aQuotaETLDplus1DomainDBKey,
                      PRUint32 aStorageType);
   void SetSessionOnly(bool aSessionOnly);
 
   static nsresult InitDB();
 
@@ -301,47 +309,51 @@ private:
 
   // Weak reference to the owning storage instance
   nsDOMStorage* mOwner;
 };
 
 class nsDOMStorage2;
 
 class nsDOMStorage : public nsIDOMStorageObsolete,
-                     public nsPIDOMStorage
+                     public nsPIDOMStorage,
+                     public nsIInterfaceRequestor
 {
 public:
   nsDOMStorage();
   nsDOMStorage(nsDOMStorage& aThat);
   virtual ~nsDOMStorage();
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorage, nsIDOMStorageObsolete)
 
   NS_DECL_NSIDOMSTORAGEOBSOLETE
+  NS_DECL_NSIINTERFACEREQUESTOR
 
   // Helpers for implementing nsIDOMStorage
   nsresult GetItem(const nsAString& key, nsAString& aData);
   nsresult Clear();
 
   // nsPIDOMStorage
-  virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI);
-  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI);
+  virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                        bool aPrivate);
+  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                      bool aPrivate);
   virtual already_AddRefed<nsIDOMStorage> Clone();
   virtual already_AddRefed<nsIDOMStorage> Fork(const nsSubstring &aDocumentURI);
   virtual bool IsForkOf(nsIDOMStorage* aThat);
   virtual nsTArray<nsString> *GetKeys();
   virtual nsIPrincipal* Principal();
   virtual bool CanAccess(nsIPrincipal *aPrincipal);
   virtual nsDOMStorageType StorageType();
 
   // Check whether storage may be used by the caller, and whether it
   // is session only.  Returns true if storage may be used.
   static bool
-  CanUseStorage(bool* aSessionOnly);
+  CanUseStorage(DOMStorageBase* aStorage = nsnull);
 
   // Check whether this URI can use chrome persist storage.  This kind of
   // storage can bypass cookies limits, private browsing and uses the offline
   // apps quota.
   static bool
   URICanUseChromePersist(nsIURI* aURI);
   
   // Check whether storage may be used.  Updates mSessionOnly based on
@@ -376,31 +388,35 @@ public:
   nsDOMStorageType mStorageType;
 
   friend class nsIDOMStorage2;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsDOMStorage2* mEventBroadcaster;
 };
 
 class nsDOMStorage2 : public nsIDOMStorage,
-                      public nsPIDOMStorage
+                      public nsPIDOMStorage,
+                      public nsIInterfaceRequestor
 {
 public:
   // nsISupports
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsDOMStorage2, nsIDOMStorage)
 
   nsDOMStorage2(nsDOMStorage2& aThat);
   nsDOMStorage2();
 
   NS_DECL_NSIDOMSTORAGE
+  NS_DECL_NSIINTERFACEREQUESTOR
 
   // nsPIDOMStorage
-  virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI);
-  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI);
+  virtual nsresult InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                        bool aPrivate);
+  virtual nsresult InitAsLocalStorage(nsIPrincipal *aPrincipal, const nsSubstring &aDocumentURI,
+                                      bool aPrivate);
   virtual already_AddRefed<nsIDOMStorage> Clone();
   virtual already_AddRefed<nsIDOMStorage> Fork(const nsSubstring &aDocumentURI);
   virtual bool IsForkOf(nsIDOMStorage* aThat);
   virtual nsTArray<nsString> *GetKeys();
   virtual nsIPrincipal* Principal();
   virtual bool CanAccess(nsIPrincipal *aPrincipal);
   virtual nsDOMStorageType StorageType();
 
--- a/dom/src/storage/nsDOMStorageDBWrapper.cpp
+++ b/dom/src/storage/nsDOMStorageDBWrapper.cpp
@@ -85,17 +85,17 @@ nsDOMStorageDBWrapper::FlushAndDeleteTem
 
   return NS_FAILED(rv1) ? rv1 : rv2;
 }
 
 #define IMPL_FORWARDER_GUTS(_return, _code)                                \
   PR_BEGIN_MACRO                                                      \
   if (aStorage->CanUseChromePersist())                                \
     _return mChromePersistentDB._code;                                \
-  if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())  \
+  if (aStorage->IsPrivate())                                          \
     _return mPrivateBrowsingDB._code;                                 \
   if (aStorage->SessionOnly())                                        \
     _return mSessionOnlyDB._code;                                     \
   _return mPersistentDB._code;                                        \
   PR_END_MACRO
 
 #define IMPL_FORWARDER(_code)                                  \
   IMPL_FORWARDER_GUTS(return, _code)
@@ -183,19 +183,16 @@ nsresult
 nsDOMStorageDBWrapper::RemoveOwner(const nsACString& aOwner,
                                    bool aIncludeSubDomains)
 {
   nsresult rv;
 
   rv = mPrivateBrowsingDB.RemoveOwner(aOwner, aIncludeSubDomains);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
-    return NS_OK;
-
   rv = mSessionOnlyDB.RemoveOwner(aOwner, aIncludeSubDomains);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mPersistentDB.RemoveOwner(aOwner, aIncludeSubDomains);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return rv;
 }
@@ -205,60 +202,37 @@ nsresult
 nsDOMStorageDBWrapper::RemoveOwners(const nsTArray<nsString> &aOwners,
                                     bool aIncludeSubDomains, bool aMatch)
 {
   nsresult rv;
 
   rv = mPrivateBrowsingDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
-    return NS_OK;
-
   rv = mSessionOnlyDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mPersistentDB.RemoveOwners(aOwners, aIncludeSubDomains, aMatch);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return rv;
 }
 
 nsresult
-nsDOMStorageDBWrapper::RemoveAll()
-{
-  nsresult rv;
-
-  rv = mPrivateBrowsingDB.RemoveAll();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
-    return NS_OK;
-
-  rv = mSessionOnlyDB.RemoveAll();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = mPersistentDB.RemoveAll();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return rv;
-}
-
-nsresult
 nsDOMStorageDBWrapper::GetUsage(DOMStorageImpl* aStorage,
                                 bool aExcludeOfflineFromUsage, PRInt32 *aUsage)
 {
   IMPL_FORWARDER(GetUsage(aStorage, aExcludeOfflineFromUsage, aUsage));
 }
 
 nsresult
 nsDOMStorageDBWrapper::GetUsage(const nsACString& aDomain,
-                                bool aIncludeSubDomains, PRInt32 *aUsage)
+                                bool aIncludeSubDomains, PRInt32 *aUsage, bool aPrivate)
 {
-  if (nsDOMStorageManager::gStorageManager->InPrivateBrowsingMode())
+  if (aPrivate)
     return mPrivateBrowsingDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
 
 #if 0
   // XXX Check where from all this method gets called, not sure this should
   // include any potential session-only data
   nsresult rv;
   rv = mSessionOnlyDB.GetUsage(aDomain, aIncludeSubDomains, aUsage);
   if (NS_SUECEEDED(rv))
--- a/dom/src/storage/nsDOMStorageDBWrapper.h
+++ b/dom/src/storage/nsDOMStorageDBWrapper.h
@@ -140,32 +140,26 @@ public:
    * Removes keys owned by domains that either match or don't match the
    * list.
    */
   nsresult
   RemoveOwners(const nsTArray<nsString>& aOwners,
                bool aIncludeSubDomains, bool aMatch);
 
   /**
-   * Removes all keys from storage. Used when clearing storage.
-   */
-  nsresult
-  RemoveAll();
-
-  /**
     * Returns usage for a storage using its GetQuotaDomainDBKey() as a key.
     */
   nsresult
   GetUsage(DOMStorageImpl* aStorage, bool aExcludeOfflineFromUsage, PRInt32 *aUsage);
 
   /**
     * Returns usage of the domain and optionaly by any subdomain.
     */
   nsresult
-  GetUsage(const nsACString& aDomain, bool aIncludeSubDomains, PRInt32 *aUsage);
+  GetUsage(const nsACString& aDomain, bool aIncludeSubDomains, PRInt32 *aUsage, bool aPrivate);
 
   /**
    * Marks the storage as "cached" after the DOMStorageImpl object has loaded
    * all items to its memory copy of the entries - IsScopeDirty returns false
    * after call of this method for this storage.
    *
    * When a key is changed or deleted in the storage, the storage scope is
    * marked as "dirty" again and makes the DOMStorageImpl object recache its