Backed out changeset 829a13b9968c for xpcshell test failures; a=me
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 05 Sep 2012 00:39:24 -0400
changeset 106728 d5acbc9f90a64b133f44df5b9a83717880d28922
parent 106727 829a13b9968c0a6938a4a35df7919dd1209061d0
child 106729 5197b51620318a1c37347ec00b696a86dfdb5c8d
push idunknown
push userunknown
push dateunknown
reviewersme
milestone17.0a2
backs out829a13b9968c0a6938a4a35df7919dd1209061d0
Backed out changeset 829a13b9968c for xpcshell test failures; a=me
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.js
content/base/src/nsContentSink.cpp
docshell/base/nsDocShell.cpp
netwerk/cache/nsCacheEntry.cpp
netwerk/cache/nsCacheEntry.h
netwerk/cache/nsCacheRequest.h
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsCacheService.h
netwerk/cache/nsCacheSession.cpp
netwerk/cache/nsCacheSession.h
netwerk/cache/nsICacheSession.idl
netwerk/cache/nsMemoryCacheDevice.cpp
netwerk/cache/nsMemoryCacheDevice.h
netwerk/protocol/ftp/nsFtpConnectionThread.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpConnectionInfo.cpp
netwerk/protocol/http/nsHttpConnectionInfo.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpHandler.cpp
netwerk/protocol/http/nsHttpHandler.h
netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
netwerk/protocol/wyciwyg/nsWyciwygChannel.h
netwerk/test/unit/test_bug248970_cache.js
xpcom/glue/nsISupportsImpl.h
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.js
@@ -3,32 +3,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 function test() {
   // We need to open a new window for this so that its docshell would get destroyed
   // when clearing the PB mode flag.
   let newWin = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no");
   waitForExplicitFinish();
   SimpleTest.waitForFocus(function() {
-    let notificationCount = 0;
+    let expected = false;
     let observer = {
       observe: function(aSubject, aTopic, aData) {
         is(aTopic, "last-pb-context-exited", "Correct topic should be dispatched");
-        ++notificationCount;
+        is(expected, true, "notification not expected yet");
+        Services.obs.removeObserver(observer, "last-pb-context-exited", false);
+        gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
+        finish();
       }
     };
     Services.obs.addObserver(observer, "last-pb-context-exited", false);
     setPrivateWindow(newWin, true);
-    SimpleTest.is(notificationCount, 0, "last-pb-context-exited should not be fired yet");
-    newWin.gPrivateBrowsingUI.privateWindow = false;
-    newWin.close();
+    expected = true;
+    newWin.close(); // this will cause the docshells to leave PB mode
     newWin = null;
-    window.QueryInterface(Ci.nsIInterfaceRequestor)
-          .getInterface(Ci.nsIDOMWindowUtils)
-          .garbageCollect(); // Make sure that the docshell is destroyed
-    SimpleTest.is(notificationCount, 1, "last-pb-context-exited should be fired once");
-    Services.obs.removeObserver(observer, "last-pb-context-exited", false);
-
-    // cleanup
-    gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
-    finish();
+    SpecialPowers.forceGC();
   }, newWin);
 }
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -11,16 +11,17 @@
 
 #include "nsContentSink.h"
 #include "nsScriptLoader.h"
 #include "nsIDocument.h"
 #include "nsIDOMDocument.h"
 #include "mozilla/css/Loader.h"
 #include "nsStyleLinkElement.h"
 #include "nsIDocShell.h"
+#include "nsILoadContext.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsCPrefetchService.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsIHttpChannel.h"
 #include "nsIContent.h"
 #include "nsIPresShell.h"
 #include "nsPresContext.h"
@@ -1007,16 +1008,23 @@ void
 nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec)
 {
   // Don't bother processing offline manifest for documents
   // without a docshell
   if (!mDocShell) {
     return;
   }
 
+  // If the docshell's in private browsing mode, we don't want to do any
+  // manifest processing.
+  nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(mDocShell);
+  if (loadContext->UsePrivateBrowsing()) {
+    return;
+  }
+
   nsresult rv;
 
   // Grab the application cache the document was loaded from, if any.
   nsCOMPtr<nsIApplicationCache> applicationCache;
 
   nsCOMPtr<nsIApplicationCacheChannel> applicationCacheChannel =
     do_QueryInterface(mDocument->GetChannel());
   if (applicationCacheChannel) {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -9072,16 +9072,20 @@ nsDocShell::GetInheritedPrincipal(bool a
     }
 
     return nullptr;
 }
 
 bool
 nsDocShell::ShouldCheckAppCache(nsIURI *aURI)
 {
+    if (mInPrivateBrowsing) {
+        return false;
+    }
+
     nsCOMPtr<nsIOfflineCacheUpdateService> offlineService =
         do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID);
     if (!offlineService) {
         return false;
     }
 
     bool allowed;
     nsresult rv = offlineService->OfflineAppAllowedForURI(aURI,
--- a/netwerk/cache/nsCacheEntry.cpp
+++ b/netwerk/cache/nsCacheEntry.cpp
@@ -37,16 +37,18 @@ nsCacheEntry::nsCacheEntry(const nsACStr
 {
     MOZ_COUNT_CTOR(nsCacheEntry);
     PR_INIT_CLIST(this);
     PR_INIT_CLIST(&mRequestQ);
     PR_INIT_CLIST(&mDescriptorQ);
 
     if (streamBased) MarkStreamBased();
     SetStoragePolicy(storagePolicy);
+
+    MarkPublic();
 }
 
 
 nsCacheEntry::~nsCacheEntry()
 {
     MOZ_COUNT_DTOR(nsCacheEntry);
     
     if (mData)
--- a/netwerk/cache/nsCacheEntry.h
+++ b/netwerk/cache/nsCacheEntry.h
@@ -111,61 +111,65 @@ public:
         eDoomedMask          = 0x00000100,
         eEntryDirtyMask      = 0x00000200,
         eDataDirtyMask       = 0x00000400,
         eMetaDataDirtyMask   = 0x00000800,
         eStreamDataMask      = 0x00001000,
         eActiveMask          = 0x00002000,
         eInitializedMask     = 0x00004000,
         eValidMask           = 0x00008000,
-        eBindingMask         = 0x00010000
+        eBindingMask         = 0x00010000,
+        ePrivateMask         = 0x00020000
     };
     
     void MarkBinding()         { mFlags |=  eBindingMask; }
     void ClearBinding()        { mFlags &= ~eBindingMask; }
     bool IsBinding()         { return (mFlags & eBindingMask) != 0; }
 
     void MarkEntryDirty()      { mFlags |=  eEntryDirtyMask; }
     void MarkEntryClean()      { mFlags &= ~eEntryDirtyMask; }
     void MarkDataDirty()       { mFlags |=  eDataDirtyMask; }
     void MarkDataClean()       { mFlags &= ~eDataDirtyMask; }
     void MarkMetaDataDirty()   { mFlags |=  eMetaDataDirtyMask; }
     void MarkMetaDataClean()   { mFlags &= ~eMetaDataDirtyMask; }
     void MarkStreamData()      { mFlags |=  eStreamDataMask; }
     void MarkValid()           { mFlags |=  eValidMask; }
     void MarkInvalid()         { mFlags &= ~eValidMask; }
+    void MarkPrivate()         { mFlags |=  ePrivateMask; }
+    void MarkPublic()          { mFlags &= ~ePrivateMask; }
     //    void MarkAllowedInMemory() { mFlags |=  eAllowedInMemoryMask; }
     //    void MarkAllowedOnDisk()   { mFlags |=  eAllowedOnDiskMask; }
 
     bool IsDoomed()          { return (mFlags & eDoomedMask) != 0; }
     bool IsEntryDirty()      { return (mFlags & eEntryDirtyMask) != 0; }
     bool IsDataDirty()       { return (mFlags & eDataDirtyMask) != 0; }
     bool IsMetaDataDirty()   { return (mFlags & eMetaDataDirtyMask) != 0; }
     bool IsStreamData()      { return (mFlags & eStreamDataMask) != 0; }
     bool IsActive()          { return (mFlags & eActiveMask) != 0; }
     bool IsInitialized()     { return (mFlags & eInitializedMask) != 0; }
     bool IsValid()           { return (mFlags & eValidMask) != 0; }
     bool IsInvalid()         { return (mFlags & eValidMask) == 0; }
     bool IsInUse()           { return IsBinding() ||
                                         !(PR_CLIST_IS_EMPTY(&mRequestQ) &&
                                           PR_CLIST_IS_EMPTY(&mDescriptorQ)); }
     bool IsNotInUse()        { return !IsInUse(); }
+    bool IsPrivate()         { return (mFlags & ePrivateMask) != 0; }
 
 
     bool IsAllowedInMemory()
     {
         return (StoragePolicy() ==  nsICache::STORE_ANYWHERE) ||
             (StoragePolicy() == nsICache::STORE_IN_MEMORY);
     }
 
     bool IsAllowedOnDisk()
     {
-        return (StoragePolicy() == nsICache::STORE_ANYWHERE) ||
+        return !IsPrivate() && ((StoragePolicy() == nsICache::STORE_ANYWHERE) ||
             (StoragePolicy() == nsICache::STORE_ON_DISK) ||
-            (StoragePolicy() == nsICache::STORE_ON_DISK_AS_FILE);
+            (StoragePolicy() == nsICache::STORE_ON_DISK_AS_FILE));
     }
 
     bool IsAllowedOffline()
     {
         return (StoragePolicy() == nsICache::STORE_OFFLINE);
     }
 
     nsCacheStoragePolicy  StoragePolicy()
--- a/netwerk/cache/nsCacheRequest.h
+++ b/netwerk/cache/nsCacheRequest.h
@@ -41,16 +41,17 @@ private:
           mProfileDir(session->ProfileDir())
     {
         MOZ_COUNT_CTOR(nsCacheRequest);
         PR_INIT_CLIST(this);
         SetAccessRequested(accessRequested);
         SetStoragePolicy(session->StoragePolicy());
         if (session->IsStreamBased())             MarkStreamBased();
         if (session->WillDoomEntriesIfExpired())  MarkDoomEntriesIfExpired();
+        if (session->IsPrivate())                 MarkPrivate();
         if (blockingMode == nsICache::BLOCKING)    MarkBlockingMode();
         MarkWaitingForValidation();
         NS_IF_ADDREF(mListener);
     }
     
     ~nsCacheRequest()
     {
         MOZ_COUNT_DTOR(nsCacheRequest);
@@ -61,16 +62,17 @@ private:
     }
     
     /**
      * Simple Accessors
      */
     enum CacheRequestInfo {
         eStoragePolicyMask         = 0x000000FF,
         eStreamBasedMask           = 0x00000100,
+        ePrivateMask               = 0x00000200,
         eDoomEntriesIfExpiredMask  = 0x00001000,
         eBlockingModeMask          = 0x00010000,
         eWaitingForValidationMask  = 0x00100000,
         eAccessRequestedMask       = 0xFF000000
     };
 
     void SetAccessRequested(nsCacheAccessMode mode)
     {
@@ -99,19 +101,23 @@ private:
     {
         NS_ASSERTION(policy <= 0xFF, "too many bits in nsCacheStoragePolicy");
         mInfo &= ~eStoragePolicyMask;  // clear storage policy bits
         mInfo |= policy;         // or in new bits
     }
 
     nsCacheStoragePolicy StoragePolicy()
     {
-        return (nsCacheStoragePolicy)(mInfo & 0xFF);
+        return (nsCacheStoragePolicy)(mInfo & eStoragePolicyMask);
     }
 
+    void   MarkPrivate() { mInfo |= ePrivateMask; }
+    void   MarkPublic() { mInfo &= ~ePrivateMask; }
+    bool   IsPrivate() { return (mInfo & ePrivateMask) != 0; }
+
     void   MarkWaitingForValidation() { mInfo |=  eWaitingForValidationMask; }
     void   DoneWaitingForValidation() { mInfo &= ~eWaitingForValidationMask; }
     bool WaitingForValidation()
     {
         return (mInfo & eWaitingForValidationMask) != 0;
     }
 
     nsresult
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -27,17 +27,16 @@
 #include "nsIFile.h"
 #include "nsIOService.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsThreadUtils.h"
 #include "nsProxyRelease.h"
 #include "nsVoidArray.h"
 #include "nsDeleteDir.h"
-#include "nsIPrivateBrowsingService.h"
 #include "nsNetCID.h"
 #include <math.h>  // for log()
 #include "mozilla/Services.h"
 #include "nsITimer.h"
 
 #include "mozilla/FunctionTimer.h"
 
 #include "mozilla/net/NeckoCommon.h"
@@ -75,17 +74,17 @@ using namespace mozilla;
 
 #define SANITIZE_ON_SHUTDOWN_PREF   "privacy.sanitize.sanitizeOnShutdown"
 #define CLEAR_ON_SHUTDOWN_PREF      "privacy.clearOnShutdown.cache"
 
 static const char * observerList[] = { 
     "profile-before-change",
     "profile-do-change",
     NS_XPCOM_SHUTDOWN_OBSERVER_ID,
-    NS_PRIVATE_BROWSING_SWITCH_TOPIC
+    "last-pb-context-exited"
 };
 static const char * prefList[] = { 
     DISK_CACHE_ENABLE_PREF,
     DISK_CACHE_SMART_SIZE_ENABLED_PREF,
     DISK_CACHE_CAPACITY_PREF,
     DISK_CACHE_DIR_PREF,
     DISK_CACHE_MAX_ENTRY_SIZE_PREF,
     DISK_CACHE_USE_OLD_MAX_SMART_SIZE_PREF,
@@ -126,17 +125,16 @@ public:
         , mDiskCacheMaxEntrySize(-1) // -1 means "no limit"
         , mSmartSizeEnabled(false)
         , mUseOldMaxSmartSize(false)
         , mOfflineCacheEnabled(false)
         , mOfflineCacheCapacity(0)
         , mMemoryCacheEnabled(true)
         , mMemoryCacheCapacity(-1)
         , mMemoryCacheMaxEntrySize(-1) // -1 means "no limit"
-        , mInPrivateBrowsing(false)
         , mCacheCompressionLevel(CACHE_COMPRESSION_LEVEL)
         , mSanitizeOnShutdown(false)
         , mClearCacheOnShutdown(false)
     {
     }
 
     virtual ~nsCacheProfilePrefObserver() {}
     
@@ -185,18 +183,16 @@ private:
     bool                    mOfflineCacheEnabled;
     int32_t                 mOfflineCacheCapacity; // in kilobytes
     nsCOMPtr<nsIFile>       mOfflineCacheParentDirectory;
     
     bool                    mMemoryCacheEnabled;
     int32_t                 mMemoryCacheCapacity; // in kilobytes
     int32_t                 mMemoryCacheMaxEntrySize; // in kilobytes
 
-    bool                    mInPrivateBrowsing;
-
     int32_t                 mCacheCompressionLevel;
 
     bool                    mSanitizeOnShutdown;
     bool                    mClearCacheOnShutdown;
 };
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheProfilePrefObserver, nsIObserver)
 
@@ -322,22 +318,16 @@ nsCacheProfilePrefObserver::Install()
     if (!branch) return NS_ERROR_FAILURE;
 
     for (unsigned int i=0; i<ArrayLength(prefList); i++) {
         rv = branch->AddObserver(prefList[i], this, false);
         if (NS_FAILED(rv))
             rv2 = rv;
     }
 
-    // determine the initial status of the private browsing mode
-    nsCOMPtr<nsIPrivateBrowsingService> pbs =
-      do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
-    if (pbs)
-      pbs->GetPrivateBrowsingEnabled(&mInPrivateBrowsing);
-
     // Determine if we have a profile already
     //     Install() is called *after* the profile-after-change notification
     //     when there is only a single profile, or it is specified on the
     //     commandline at startup.
     //     In that case, we detect the presence of a profile by the existence
     //     of the NS_APP_USER_PROFILE_50_DIR directory.
 
     nsCOMPtr<nsIFile> directory;
@@ -420,23 +410,19 @@ nsCacheProfilePrefObserver::Observe(nsIS
         if (NS_FAILED(rv))  
             return rv;
 
         // which preference changed?
         if (!strcmp(DISK_CACHE_ENABLE_PREF, data.get())) {
 
             rv = branch->GetBoolPref(DISK_CACHE_ENABLE_PREF,
                                      &mDiskCacheEnabled);
-            if (!mInPrivateBrowsing) {
-                rv = branch->GetBoolPref(DISK_CACHE_ENABLE_PREF,
-                                         &mDiskCacheEnabled);
-                if (NS_FAILED(rv))  
-                    return rv;
-                nsCacheService::SetDiskCacheEnabled(DiskCacheEnabled());
-            }
+            if (NS_FAILED(rv))  
+                return rv;
+            nsCacheService::SetDiskCacheEnabled(DiskCacheEnabled());
 
         } else if (!strcmp(DISK_CACHE_CAPACITY_PREF, data.get())) {
 
             int32_t capacity = 0;
             rv = branch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &capacity);
             if (NS_FAILED(rv))  
                 return rv;
             mDiskCacheCapacity = NS_MAX(0, capacity);
@@ -482,22 +468,20 @@ nsCacheProfilePrefObserver::Observe(nsIS
             // XXX notification that the pref change won't take effect until
             // XXX the next time the profile changes (browser launch)
 #endif            
         } else
 
         // which preference changed?
         if (!strcmp(OFFLINE_CACHE_ENABLE_PREF, data.get())) {
 
-            if (!mInPrivateBrowsing) {
-                rv = branch->GetBoolPref(OFFLINE_CACHE_ENABLE_PREF,
-                                         &mOfflineCacheEnabled);
-                if (NS_FAILED(rv))  return rv;
-                nsCacheService::SetOfflineCacheEnabled(OfflineCacheEnabled());
-            }
+            rv = branch->GetBoolPref(OFFLINE_CACHE_ENABLE_PREF,
+                                     &mOfflineCacheEnabled);
+            if (NS_FAILED(rv))  return rv;
+            nsCacheService::SetOfflineCacheEnabled(OfflineCacheEnabled());
 
         } else if (!strcmp(OFFLINE_CACHE_CAPACITY_PREF, data.get())) {
 
             int32_t capacity = 0;
             rv = branch->GetIntPref(OFFLINE_CACHE_CAPACITY_PREF, &capacity);
             if (NS_FAILED(rv))  return rv;
             mOfflineCacheCapacity = NS_MAX(0, capacity);
             nsCacheService::SetOfflineCacheCapacity(mOfflineCacheCapacity);
@@ -547,46 +531,18 @@ nsCacheProfilePrefObserver::Observe(nsIS
             nsCacheService::SetDiskCacheEnabled(DiskCacheEnabled());
         } else if (!strcmp(CLEAR_ON_SHUTDOWN_PREF, data.get())) {
             rv = branch->GetBoolPref(CLEAR_ON_SHUTDOWN_PREF,
                                      &mClearCacheOnShutdown);
             if (NS_FAILED(rv))
                 return rv;
             nsCacheService::SetDiskCacheEnabled(DiskCacheEnabled());
         }
-    } else if (!strcmp(NS_PRIVATE_BROWSING_SWITCH_TOPIC, topic)) {
-        if (!strcmp(NS_PRIVATE_BROWSING_ENTER, data.get())) {
-            mInPrivateBrowsing = true;
-
-            nsCacheService::OnEnterExitPrivateBrowsing();
-
-            mDiskCacheEnabled = false;
-            nsCacheService::SetDiskCacheEnabled(DiskCacheEnabled());
-
-            mOfflineCacheEnabled = false;
-            nsCacheService::SetOfflineCacheEnabled(OfflineCacheEnabled());
-        } else if (!strcmp(NS_PRIVATE_BROWSING_LEAVE, data.get())) {
-            mInPrivateBrowsing = false;
-
-            nsCacheService::OnEnterExitPrivateBrowsing();
-
-            nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
-            if (NS_FAILED(rv))  
-                return rv;
-
-            mDiskCacheEnabled = true; // by default enabled
-            (void) branch->GetBoolPref(DISK_CACHE_ENABLE_PREF,
-                                       &mDiskCacheEnabled);
-            nsCacheService::SetDiskCacheEnabled(DiskCacheEnabled());
-
-            mOfflineCacheEnabled = true; // by default enabled
-            (void) branch->GetBoolPref(OFFLINE_CACHE_ENABLE_PREF,
-                                       &mOfflineCacheEnabled);
-            nsCacheService::SetOfflineCacheEnabled(OfflineCacheEnabled());
-        }
+    } else if (!strcmp("last-pb-context-exited", topic)) {
+        nsCacheService::LeavePrivateBrowsing();
     }
 
     return NS_OK;
 }
 
 // Returns default ("smart") size (in KB) of cache, given available disk space
 // (also in KB)
 static uint32_t
@@ -709,20 +665,18 @@ nsCacheProfilePrefObserver::PermittedToS
 
 
 nsresult
 nsCacheProfilePrefObserver::ReadPrefs(nsIPrefBranch* branch)
 {
     nsresult rv = NS_OK;
 
     // read disk cache device prefs
-    if (!mInPrivateBrowsing) {
-        mDiskCacheEnabled = true;  // presume disk cache is enabled
-        (void) branch->GetBoolPref(DISK_CACHE_ENABLE_PREF, &mDiskCacheEnabled);
-    }
+    mDiskCacheEnabled = true;  // presume disk cache is enabled
+    (void) branch->GetBoolPref(DISK_CACHE_ENABLE_PREF, &mDiskCacheEnabled);
 
     mDiskCacheCapacity = DISK_CACHE_CAPACITY;
     (void)branch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &mDiskCacheCapacity);
     mDiskCacheCapacity = NS_MAX(0, mDiskCacheCapacity);
 
     (void) branch->GetIntPref(DISK_CACHE_MAX_ENTRY_SIZE_PREF,
                               &mDiskCacheMaxEntrySize);
     mDiskCacheMaxEntrySize = NS_MAX(-1, mDiskCacheMaxEntrySize);
@@ -793,21 +747,19 @@ nsCacheProfilePrefObserver::ReadPrefs(ns
             rv = branch->SetBoolPref(DISK_CACHE_SMART_SIZE_FIRST_RUN_PREF, 
                                      false);
             if (NS_FAILED(rv)) 
                 NS_WARNING("Failed setting first_run pref in ReadPrefs.");
         }
     }
 
     // read offline cache device prefs
-    if (!mInPrivateBrowsing) {
-        mOfflineCacheEnabled = true;  // presume offline cache is enabled
-        (void) branch->GetBoolPref(OFFLINE_CACHE_ENABLE_PREF,
-                                   &mOfflineCacheEnabled);
-    }
+    mOfflineCacheEnabled = true;  // presume offline cache is enabled
+    (void) branch->GetBoolPref(OFFLINE_CACHE_ENABLE_PREF,
+                              &mOfflineCacheEnabled);
 
     mOfflineCacheCapacity = OFFLINE_CACHE_CAPACITY;
     (void)branch->GetIntPref(OFFLINE_CACHE_CAPACITY_PREF,
                              &mOfflineCacheCapacity);
     mOfflineCacheCapacity = NS_MAX(0, mOfflineCacheCapacity);
 
     (void) branch->GetComplexValue(OFFLINE_CACHE_DIR_PREF,     // ignore error
                                    NS_GET_IID(nsIFile),
@@ -2151,16 +2103,19 @@ nsCacheService::ActivateEntry(nsCacheReq
             goto error;
         }
 
         entry = new nsCacheEntry(request->mKey,
                                  request->IsStreamBased(),
                                  request->StoragePolicy());
         if (!entry)
             return NS_ERROR_OUT_OF_MEMORY;
+
+        if (request->IsPrivate())
+            entry->MarkPrivate();
         
         entry->Fetched();
         ++mTotalEntries;
 
         // XXX  we could perform an early bind in some cases based on storage policy
     }
 
     if (!entry->IsActive()) {
@@ -2369,17 +2324,17 @@ nsCacheService::OnProfileShutdown(bool c
     if (!gService->mInitialized) {
         // The cache service has been shut down, but someone is still holding
         // a reference to it. Ignore this call.
         return;
     }
     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_ONPROFILESHUTDOWN));
     gService->mClearingEntries = true;
 
-    gService->DoomActiveEntries();
+    gService->DoomActiveEntries(nullptr);
     gService->ClearDoomList();
 
     // Make sure to wait for any pending cache-operations before
     // proceeding with destructive actions (bug #620660)
     (void) SyncWithCacheIOThread();
 
     if (gService->mDiskDevice && gService->mEnableDiskDevice) {
         if (cleanse)
@@ -2940,41 +2895,50 @@ nsCacheService::DeactivateAndClearEntry(
     entry->DetachDescriptors();
     
     entry->MarkInactive();  // so we don't call Remove() while we're enumerating
     gService->DeactivateEntry(entry);
     
     return PL_DHASH_REMOVE; // and continue enumerating
 }
 
+struct ActiveEntryArgs
+{
+    nsTArray<nsCacheEntry*>* mActiveArray;
+    nsCacheService::DoomCheckFn mCheckFn;
+};
+
 void
-nsCacheService::DoomActiveEntries()
+nsCacheService::DoomActiveEntries(DoomCheckFn check)
 {
     nsAutoTArray<nsCacheEntry*, 8> array;
-
-    mActiveEntries.VisitEntries(RemoveActiveEntry, &array);
+    ActiveEntryArgs args = { &array, check };
+
+    mActiveEntries.VisitEntries(RemoveActiveEntry, &args);
 
     uint32_t count = array.Length();
     for (uint32_t i=0; i < count; ++i)
         DoomEntry_Internal(array[i], true);
 }
 
-
 PLDHashOperator
 nsCacheService::RemoveActiveEntry(PLDHashTable *    table,
                                   PLDHashEntryHdr * hdr,
                                   uint32_t          number,
                                   void *            arg)
 {
     nsCacheEntry * entry = ((nsCacheEntryHashTableEntry *)hdr)->cacheEntry;
     NS_ASSERTION(entry, "### active entry = nullptr!");
 
-    nsTArray<nsCacheEntry*> * array = (nsTArray<nsCacheEntry*> *) arg;
-    NS_ASSERTION(array, "### array = nsnull!");
-    array->AppendElement(entry);
+    ActiveEntryArgs* args = static_cast<ActiveEntryArgs*>(arg);
+    if (args->mCheckFn && !args->mCheckFn(entry))
+        return PL_DHASH_NEXT;
+
+    NS_ASSERTION(args->mActiveArray, "### array = nullptr!");
+    args->mActiveArray->AppendElement(entry);
 
     // entry is being removed from the active entry list
     entry->MarkInactive();
     return PL_DHASH_REMOVE; // and continue enumerating
 }
 
 
 #if defined(PR_LOGGING)
@@ -2994,30 +2958,16 @@ nsCacheService::LogCacheStatistics()
     CACHE_LOG_ALWAYS(("\n"));
     CACHE_LOG_ALWAYS(("    Deactivate Failures         = %d\n",
                       mDeactivateFailures));
     CACHE_LOG_ALWAYS(("    Deactivated Unbound Entries = %d\n",
                       mDeactivatedUnboundEntries));
 }
 #endif
 
-void
-nsCacheService::OnEnterExitPrivateBrowsing()
-{
-    if (!gService)  return;
-    nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_LEAVEPRIVATEBROWSING));
-
-    gService->DoomActiveEntries();
-
-    if (gService->mMemoryDevice) {
-        // clear memory cache
-        gService->mMemoryDevice->EvictEntries(nullptr);
-    }
-}
-
 nsresult
 nsCacheService::SetDiskSmartSize()
 {
     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_SETDISKSMARTSIZE));
 
     if (!gService) return NS_ERROR_NOT_AVAILABLE;
 
     return gService->SetDiskSmartSize_Locked();
@@ -3045,8 +2995,27 @@ nsCacheService::SetDiskSmartSize_Locked(
                                     mObserver->UseOldMaxSmartSize());
         DispatchToCacheIOThread(event);
     } else {
         return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
 }
+
+static bool
+IsEntryPrivate(nsCacheEntry* entry)
+{
+    return entry->IsPrivate();
+}
+
+void
+nsCacheService::LeavePrivateBrowsing()
+{
+    nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_LEAVEPRIVATEBROWSING));
+
+    gService->DoomActiveEntries(IsEntryPrivate);
+
+    if (gService->mMemoryDevice) {
+        // clear memory cache
+        gService->mMemoryDevice->EvictPrivateEntries();
+    }
+}
--- a/netwerk/cache/nsCacheService.h
+++ b/netwerk/cache/nsCacheService.h
@@ -163,29 +163,30 @@ public:
     static void      SetOfflineCacheEnabled(bool    enabled);
     // Sets the offline cache capacity (in kilobytes)
     static void      SetOfflineCacheCapacity(int32_t  capacity);
 
     static void      SetMemoryCache();
 
     static void      SetCacheCompressionLevel(int32_t level);
 
-    static void      OnEnterExitPrivateBrowsing();
-
     // Starts smart cache size computation if disk device is available
     static nsresult  SetDiskSmartSize();
 
     nsresult         Init();
     void             Shutdown();
 
     static void      AssertOwnsLock()
     { gService->mLock.AssertCurrentThreadOwns(); }
 
+    static void      LeavePrivateBrowsing();
     bool             IsDoomListEmpty();
 
+    typedef bool (*DoomCheckFn)(nsCacheEntry* entry);
+
 private:
     friend class nsCacheServiceAutoLock;
     friend class nsOfflineCacheDevice;
     friend class nsProcessRequestEvent;
     friend class nsSetSmartSizeEvent;
     friend class nsBlockOnCacheThreadEvent;
     friend class nsSetDiskSmartSizeCallback;
     friend class nsDoomEvent;
@@ -243,17 +244,17 @@ private:
                                     bool                       calledFromOpenCacheEntry,
                                     nsICacheEntryDescriptor ** result);
 
     nsresult         ProcessPendingRequests(nsCacheEntry * entry);
 
     void             ClearPendingRequests(nsCacheEntry * entry);
     void             ClearDoomList(void);
     void             ClearActiveEntries(void);
-    void             DoomActiveEntries(void);
+    void             DoomActiveEntries(DoomCheckFn check);
 
     static
     PLDHashOperator  DeactivateAndClearEntry(PLDHashTable *    table,
                                              PLDHashEntryHdr * hdr,
                                              uint32_t          number,
                                              void *            arg);
     static
     PLDHashOperator  RemoveActiveEntry(PLDHashTable *    table,
--- a/netwerk/cache/nsCacheSession.cpp
+++ b/netwerk/cache/nsCacheSession.cpp
@@ -16,16 +16,18 @@ nsCacheSession::nsCacheSession(const cha
     : mClientID(clientID),
       mInfo(0)
 {
   SetStoragePolicy(storagePolicy);
 
   if (streamBased) MarkStreamBased();
   else SetStoragePolicy(nsICache::STORE_IN_MEMORY);
 
+  MarkPublic();
+
   MarkDoomEntriesIfExpired();
 }
 
 nsCacheSession::~nsCacheSession()
 {
   /* destructor code */
     // notify service we are going away?
 }
@@ -118,8 +120,23 @@ NS_IMETHODIMP nsCacheSession::IsStorageE
     return nsCacheService::IsStorageEnabledForPolicy(StoragePolicy(), result);
 }
 
 NS_IMETHODIMP nsCacheSession::DoomEntry(const nsACString &key,
                                         nsICacheListener *listener)
 {
     return nsCacheService::DoomEntry(this, key, listener);
 }
+
+NS_IMETHODIMP nsCacheSession::GetIsPrivate(bool* aPrivate)
+{
+    *aPrivate = IsPrivate();
+    return NS_OK;
+}
+
+NS_IMETHODIMP nsCacheSession::SetIsPrivate(bool aPrivate)
+{
+    if (aPrivate)
+        MarkPrivate();
+    else
+        MarkPublic();
+    return NS_OK;
+}
--- a/netwerk/cache/nsCacheSession.h
+++ b/netwerk/cache/nsCacheSession.h
@@ -23,27 +23,31 @@ public:
     nsCacheSession(const char * clientID, nsCacheStoragePolicy storagePolicy, bool streamBased);
     virtual ~nsCacheSession();
     
     nsCString *           ClientID()      { return &mClientID; }
 
     enum SessionInfo {
         eStoragePolicyMask        = 0x000000FF,
         eStreamBasedMask          = 0x00000100,
-        eDoomEntriesIfExpiredMask = 0x00001000
+        eDoomEntriesIfExpiredMask = 0x00001000,
+        ePrivateMask              = 0x00010000
     };
 
     void   MarkStreamBased()  { mInfo |=  eStreamBasedMask; }
     void   ClearStreamBased() { mInfo &= ~eStreamBasedMask; }
     bool IsStreamBased()    { return (mInfo & eStreamBasedMask) != 0; }
 
     void   MarkDoomEntriesIfExpired()  { mInfo |=  eDoomEntriesIfExpiredMask; }
     void   ClearDoomEntriesIfExpired() { mInfo &= ~eDoomEntriesIfExpiredMask; }
     bool WillDoomEntriesIfExpired()  { return (0 != (mInfo & eDoomEntriesIfExpiredMask)); }
 
+    void   MarkPrivate() { mInfo |= ePrivateMask; }
+    void   MarkPublic() { mInfo &= ~ePrivateMask; }
+    bool IsPrivate() { return (mInfo & ePrivateMask) != 0; }
     nsCacheStoragePolicy  StoragePolicy()
     {
         return (nsCacheStoragePolicy)(mInfo & eStoragePolicyMask);
     }
 
     void SetStoragePolicy(nsCacheStoragePolicy policy)
     {
         NS_ASSERTION(policy <= 0xFF, "too many bits in nsCacheStoragePolicy");
--- a/netwerk/cache/nsICacheSession.idl
+++ b/netwerk/cache/nsICacheSession.idl
@@ -73,9 +73,15 @@ interface nsICacheSession : nsISupports
     boolean isStorageEnabled();
 
     /**
      * Asynchronously doom an entry specified by the key. Listener will be
      * notified about the status of the operation. Null may be passed if caller
      * doesn't care about the result.
      */
     void doomEntry(in ACString key, in nsICacheListener listener);
+
+    /**
+     * Private entries will be doomed when the last private browsing session
+     * finishes.
+     */
+    attribute boolean isPrivate;
 };
--- a/netwerk/cache/nsMemoryCacheDevice.cpp
+++ b/netwerk/cache/nsMemoryCacheDevice.cpp
@@ -437,47 +437,78 @@ nsMemoryCacheDevice::Visit(nsICacheVisit
 
             entry = (nsCacheEntry *)PR_NEXT_LINK(entry);
         }
     }
     return NS_OK;
 }
 
 
+static bool
+IsEntryPrivate(nsCacheEntry* entry, void* args)
+{
+    return entry->IsPrivate();
+}
+
+struct ClientIDArgs {
+    const char* clientID;
+    uint32_t prefixLength;
+};
+
+static bool
+EntryMatchesClientID(nsCacheEntry* entry, void* args)
+{
+    const char * clientID = static_cast<ClientIDArgs*>(args)->clientID;
+    uint32_t prefixLength = static_cast<ClientIDArgs*>(args)->prefixLength;
+    const char * key = entry->Key()->get();
+    return !clientID || nsCRT::strncmp(clientID, key, prefixLength) == 0;
+}
+
 nsresult
-nsMemoryCacheDevice::EvictEntries(const char * clientID)
+nsMemoryCacheDevice::DoEvictEntries(bool (*matchFn)(nsCacheEntry* entry, void* args), void* args)
 {
     nsCacheEntry * entry;
-    uint32_t prefixLength = (clientID ? strlen(clientID) : 0);
 
     for (int i = kQueueCount - 1; i >= 0; --i) {
         PRCList * elem = PR_LIST_HEAD(&mEvictionList[i]);
         while (elem != &mEvictionList[i]) {
             entry = (nsCacheEntry *)elem;
             elem = PR_NEXT_LINK(elem);
 
-            const char * key = entry->Key()->get();
-            if (clientID && nsCRT::strncmp(clientID, key, prefixLength) != 0)
+            if (!matchFn(entry, args))
                 continue;
             
             if (entry->IsInUse()) {
                 nsresult rv = nsCacheService::DoomEntry(entry);
                 if (NS_FAILED(rv)) {
-                    CACHE_LOG_WARNING(("memCache->EvictEntries() aborted: rv =%x", rv));
+                    CACHE_LOG_WARNING(("memCache->DoEvictEntries() aborted: rv =%x", rv));
                     return rv;
                 }
             } else {
                 EvictEntry(entry, DELETE_ENTRY);
             }
         }
     }
 
     return NS_OK;
 }
 
+nsresult
+nsMemoryCacheDevice::EvictEntries(const char * clientID)
+{
+    ClientIDArgs args = {clientID, clientID ? uint32_t(strlen(clientID)) : 0};
+    return DoEvictEntries(&EntryMatchesClientID, &args);
+}
+
+nsresult
+nsMemoryCacheDevice::EvictPrivateEntries()
+{
+    return DoEvictEntries(&IsEntryPrivate, NULL);
+}
+
 
 // WARNING: SetCapacity can get called before Init()
 void
 nsMemoryCacheDevice::SetCapacity(int32_t  capacity)
 {
     int32_t hardLimit = capacity * 1024;  // convert k into bytes
     int32_t softLimit = (hardLimit * 9) / 10;
     AdjustMemoryLimits(softLimit, hardLimit);
--- a/netwerk/cache/nsMemoryCacheDevice.h
+++ b/netwerk/cache/nsMemoryCacheDevice.h
@@ -46,16 +46,17 @@ public:
     virtual nsresult GetFileForEntry( nsCacheEntry *    entry,
                                       nsIFile **        result );
 
     virtual nsresult OnDataSizeChange( nsCacheEntry * entry, int32_t deltaSize );
 
     virtual nsresult Visit( nsICacheVisitor * visitor );
 
     virtual nsresult EvictEntries(const char * clientID);
+    nsresult EvictPrivateEntries();
     
     void             SetCapacity(int32_t  capacity);
     void             SetMaxEntrySize(int32_t  maxSizeInKilobytes);
 
     bool             EntryIsTooBig(int64_t entrySize);
 
     size_t           TotalSize();
 
@@ -64,16 +65,19 @@ private:
     enum      { DELETE_ENTRY        = true,
                 DO_NOT_DELETE_ENTRY = false };
 
     void      AdjustMemoryLimits( int32_t  softLimit, int32_t  hardLimit);
     void      EvictEntry( nsCacheEntry * entry , bool deleteEntry);
     void      EvictEntriesIfNecessary();
     int       EvictionList(nsCacheEntry * entry, int32_t  deltaSize);
 
+    typedef bool (*EvictionMatcherFn)(nsCacheEntry* entry, void* args);
+    nsresult DoEvictEntries(EvictionMatcherFn matchFn, void* args);
+
 #ifdef DEBUG
     void      CheckEntryCount();
 #endif
     /*
      *  Data members
      */
     enum {
         kQueueCount = 24   // entries > 2^23 (8Mb) start in last queue
--- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
+++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
@@ -2216,24 +2216,29 @@ nsFtpState::CheckCache()
     // In some cases, we don't want to use the cache:
     if (mChannel->UploadStream() || mChannel->ResumeRequested())
         return false;
 
     nsCOMPtr<nsICacheService> cache = do_GetService(NS_CACHESERVICE_CONTRACTID);
     if (!cache)
         return false;
 
+    bool isPrivate = NS_UsePrivateBrowsing(mChannel);
+    const char* sessionName = isPrivate ? "FTP-private" : "FTP";
+    nsCacheStoragePolicy policy =
+        isPrivate ? nsICache::STORE_IN_MEMORY : nsICache::STORE_ANYWHERE;
     nsCOMPtr<nsICacheSession> session;
-    cache->CreateSession("FTP",
-                         nsICache::STORE_ANYWHERE,
+    cache->CreateSession(sessionName,
+                         policy,
                          nsICache::STREAM_BASED,
                          getter_AddRefs(session));
     if (!session)
         return false;
     session->SetDoomEntriesIfExpired(false);
+    session->SetIsPrivate(isPrivate);
 
     // Set cache access requested:
     nsCacheAccessMode accessReq;
     if (NS_IsOffline()) {
         accessReq = nsICache::ACCESS_READ; // can only read
     } else if (mChannel->HasLoadFlag(nsIRequest::LOAD_BYPASS_CACHE)) {
         accessReq = nsICache::ACCESS_WRITE; // replace cache entry
     } else {
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -12,16 +12,17 @@
 #include "nsNetUtil.h"
 
 #include "nsICachingChannel.h"
 #include "nsISeekableStream.h"
 #include "nsITimedChannel.h"
 #include "nsIEncodedChannel.h"
 #include "nsIResumableChannel.h"
 #include "nsIApplicationCacheChannel.h"
+#include "nsILoadContext.h"
 #include "nsEscape.h"
 #include "nsStreamListenerWrapper.h"
 
 #include "prnetdb.h"
 
 namespace mozilla {
 namespace net {
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -74,21 +74,24 @@ AccumulateCacheHitTelemetry(mozilla::Tel
     mozilla::Telemetry::Accumulate(
             mozilla::Telemetry::HTTP_CACHE_DISPOSITION_2, hitOrMiss);
     if (deviceHistogram != UNKNOWN_DEVICE) {
         mozilla::Telemetry::Accumulate(deviceHistogram, hitOrMiss);
     }
 }
 
 const char *
-GetCacheSessionNameForStoragePolicy(nsCacheStoragePolicy storagePolicy)
+GetCacheSessionNameForStoragePolicy(nsCacheStoragePolicy storagePolicy,
+                                    bool isPrivate)
 {
+    MOZ_ASSERT(!isPrivate || storagePolicy == nsICache::STORE_IN_MEMORY);
+
     switch (storagePolicy) {
     case nsICache::STORE_IN_MEMORY:
-        return "HTTP-memory-only";
+        return isPrivate ? "HTTP-memory-only-PB" : "HTTP-memory-only";
     case nsICache::STORE_OFFLINE:
         return "HTTP-offline";
     default:
         return "HTTP";
     }
 }
 
 // Computes and returns a SHA1 hash of the input buffer. The input buffer
@@ -182,30 +185,32 @@ AutoRedirectVetoNotifier::ReportRedirect
 }
 
 class HttpCacheQuery : public nsRunnable, public nsICacheListener
 {
 public:
     HttpCacheQuery(nsHttpChannel * channel,
                    const nsACString & clientID,
                    nsCacheStoragePolicy storagePolicy,
+                   bool usingPrivateBrowsing,
                    const nsACString & cacheKey,
                    nsCacheAccessMode accessToRequest,
                    bool noWait,
                    bool usingSSL,
                    bool loadedFromApplicationCache)
         // in
         : mChannel(channel)
         , mHasQueryString(HasQueryString(channel->mRequestHead.Method(),
                                          channel->mURI))
         , mLoadFlags(channel->mLoadFlags)
         , mCacheForOfflineUse(!!channel->mApplicationCacheForWrite)
         , mFallbackChannel(channel->mFallbackChannel)
         , mClientID(clientID)
         , mStoragePolicy(storagePolicy)
+        , mUsingPrivateBrowsing(usingPrivateBrowsing)
         , mCacheKey(cacheKey)
         , mAccessToRequest(accessToRequest)
         , mNoWait(noWait)
         , mUsingSSL(usingSSL)
         , mLoadedFromApplicationCache(loadedFromApplicationCache)
         // internal
         , mCacheAccess(0)
         , mStatus(NS_ERROR_NOT_INITIALIZED)
@@ -250,16 +255,17 @@ private:
 
     nsCOMPtr<nsICacheListener> mChannel;
     const bool mHasQueryString;
     const uint32_t mLoadFlags;
     const bool mCacheForOfflineUse;
     const bool mFallbackChannel;
     const InfallableCopyCString mClientID;
     const nsCacheStoragePolicy mStoragePolicy;
+    const bool mUsingPrivateBrowsing;
     const InfallableCopyCString mCacheKey;
     const nsCacheAccessMode mAccessToRequest;
     const bool mNoWait;
     const bool mUsingSSL;
     const bool mLoadedFromApplicationCache;
 
     // Used only internally 
     nsCOMPtr<nsIEventTarget> mCacheThread;
@@ -533,16 +539,17 @@ nsHttpChannel::SpeculativeConnect()
     
     nsCOMPtr<nsIInterfaceRequestor> callbacks;
     NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
                                            getter_AddRefs(callbacks));
     if (!callbacks)
         return;
 
     mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
+    mConnectionInfo->SetPrivate(mPrivateBrowsing);
     gHttpHandler->SpeculativeConnect(mConnectionInfo,
                                      callbacks, NS_GetCurrentThread());
 }
 
 void
 nsHttpChannel::DoNotifyListenerCleanup()
 {
     // We don't need this info anymore
@@ -827,16 +834,17 @@ nsHttpChannel::SetupTransaction()
     // See bug #466080. Transfer LOAD_ANONYMOUS flag to socket-layer.
     if (mLoadFlags & LOAD_ANONYMOUS)
         mCaps |= NS_HTTP_LOAD_ANONYMOUS;
 
     if (mTimingEnabled)
         mCaps |= NS_HTTP_TIMING_ENABLED;
 
     mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
+    mConnectionInfo->SetPrivate(mPrivateBrowsing);
 
     if (mUpgradeProtocolCallback) {
         mRequestHead.SetHeader(nsHttp::Upgrade, mUpgradeProtocol, false);
         mRequestHead.SetHeader(nsHttp::Connection,
                                nsDependentCString(nsHttp::Upgrade.get()),
                                true);
         mCaps |=  NS_HTTP_STICKY_CONNECTION;
         mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
@@ -2427,17 +2435,17 @@ nsHttpChannel::OpenCacheEntry(bool using
         nsCAutoString appCacheClientID;
         rv = mApplicationCache->GetClientID(appCacheClientID);
         if (NS_SUCCEEDED(rv)) {
             // We open with ACCESS_READ only, because we don't want to overwrite
             // the offline cache entry non-atomically. ACCESS_READ will prevent
             // us from writing to the offline cache as a normal cache entry.
             mCacheQuery = new HttpCacheQuery(
                                 this, appCacheClientID,
-                                nsICache::STORE_OFFLINE,
+                                nsICache::STORE_OFFLINE, mPrivateBrowsing,
                                 cacheKey, nsICache::ACCESS_READ,
                                 mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY,
                                 usingSSL, true);
 
             mOnCacheEntryAvailableCallback =
                 &nsHttpChannel::OnOfflineCacheEntryAvailable;
 
             rv = mCacheQuery->Dispatch();
@@ -2530,29 +2538,29 @@ nsresult
 nsHttpChannel::OpenNormalCacheEntry(bool usingSSL)
 {
     NS_ASSERTION(!mCacheEntry, "We have already mCacheEntry");
 
     nsresult rv;
 
     nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
     nsDependentCString clientID(
-        GetCacheSessionNameForStoragePolicy(storagePolicy));
+        GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing));
 
     nsCAutoString cacheKey;
     GenerateCacheKey(mPostID, cacheKey);
 
     nsCacheAccessMode accessRequested;
     rv = DetermineCacheAccess(&accessRequested);
     if (NS_FAILED(rv))
         return rv;
  
     mCacheQuery = new HttpCacheQuery(
                                 this, clientID, storagePolicy,
-                                cacheKey, accessRequested,
+                                mPrivateBrowsing, cacheKey, accessRequested,
                                 mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY,
                                 usingSSL, false);
 
     mOnCacheEntryAvailableCallback =
         &nsHttpChannel::OnNormalCacheEntryAvailable;
 
     rv = mCacheQuery->Dispatch();
     if (NS_SUCCEEDED(rv))
@@ -2835,16 +2843,19 @@ HttpCacheQuery::Run()
             do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
         nsCOMPtr<nsICacheSession> session;
         if (NS_SUCCEEDED(rv)) {
             rv = serv->CreateSession(mClientID.get(), mStoragePolicy,
                                      nsICache::STREAM_BASED,
                                      getter_AddRefs(session));
         }
         if (NS_SUCCEEDED(rv)) {
+            rv = session->SetIsPrivate(mUsingPrivateBrowsing);
+        }
+        if (NS_SUCCEEDED(rv)) {
             rv = session->SetDoomEntriesIfExpired(false);
         }
         if (NS_SUCCEEDED(rv)) {
             // AsyncOpenCacheEntry isn't really async when its called on the
             // cache service thread.
             rv = session->AsyncOpenCacheEntry(mCacheKey, mAccessToRequest, this,
                                               mNoWait);
         }
@@ -5836,43 +5847,48 @@ nsHttpChannel::DoInvalidateCacheEntry(co
     // Following comments 24,32 and 33 in bug #327765, we only care about
     // the cache in the protocol-handler, not the application cache.
     // The logic below deviates from the original logic in OpenCacheEntry on
     // one point by using only READ_ONLY access-policy. I think this is safe.
 
     // First, find session holding the cache-entry - use current storage-policy
     nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
     const char * clientID =
-        GetCacheSessionNameForStoragePolicy(storagePolicy);
+        GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing);
 
     LOG(("DoInvalidateCacheEntry [channel=%p session=%s policy=%d key=%s]",
          this, clientID, int(storagePolicy), key.get()));
 
     nsresult rv;
     nsCOMPtr<nsICacheService> serv =
         do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
     nsCOMPtr<nsICacheSession> session;
     if (NS_SUCCEEDED(rv)) {
         rv = serv->CreateSession(clientID, storagePolicy,  
                                  nsICache::STREAM_BASED,
                                  getter_AddRefs(session));
     }
     if (NS_SUCCEEDED(rv)) {
+        rv = session->SetIsPrivate(mPrivateBrowsing);
+    }
+    if (NS_SUCCEEDED(rv)) {
         rv = session->DoomEntry(key, nullptr);
     }
 
     LOG(("DoInvalidateCacheEntry [channel=%p session=%s policy=%d key=%s rv=%d]",
          this, clientID, int(storagePolicy), key.get(), int(rv)));
 }
 
 nsCacheStoragePolicy
 nsHttpChannel::DetermineStoragePolicy()
 {
     nsCacheStoragePolicy policy = nsICache::STORE_ANYWHERE;
-    if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
+    if (mPrivateBrowsing)
+        policy = nsICache::STORE_IN_MEMORY;
+    else if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
         policy = nsICache::STORE_IN_MEMORY;
 
     return policy;
 }
 
 nsresult
 nsHttpChannel::DetermineCacheAccess(nsCacheAccessMode *_retval)
 {
@@ -5893,11 +5909,12 @@ nsHttpChannel::DetermineCacheAccess(nsCa
 
     return NS_OK;
 }
 
 void
 nsHttpChannel::AsyncOnExamineCachedResponse()
 {
     gHttpHandler->OnExamineCachedResponse(this);
+
 }
 
 } } // namespace mozilla::net
--- a/netwerk/protocol/http/nsHttpConnectionInfo.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.cpp
@@ -28,17 +28,17 @@ nsHttpConnectionInfo::SetOriginServer(co
         keyHost = ProxyHost();
         keyPort = ProxyPort();
     }
     else {
         keyHost = Host();
         keyPort = Port();
     }
 
-    mHashKey.AssignLiteral("...");
+    mHashKey.AssignLiteral("....");
     mHashKey.Append(keyHost);
     mHashKey.Append(':');
     mHashKey.AppendInt(keyPort);
 
     if (mUsingHttpProxy)
         mHashKey.SetCharAt('P', 0);
     if (mUsingSSL)
         mHashKey.SetCharAt('S', 1);
@@ -53,14 +53,15 @@ nsHttpConnectionInfo::SetOriginServer(co
     }
 }
 
 nsHttpConnectionInfo*
 nsHttpConnectionInfo::Clone() const
 {
     nsHttpConnectionInfo* clone = new nsHttpConnectionInfo(mHost, mPort, mProxyInfo, mUsingSSL);
 
-    // Make sure the anonymous flag is transferred!
-    clone->SetAnonymous(mHashKey.CharAt(2) == 'A');
+    // Make sure the anonymous and private flags are transferred!
+    clone->SetAnonymous(GetAnonymous());
+    clone->SetPrivate(GetPrivate());
 
     return clone;
 }
 
--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
@@ -100,16 +100,18 @@ public:
     nsProxyInfo  *ProxyInfo()            { return mProxyInfo; }
     bool          UsingHttpProxy() const { return mUsingHttpProxy; }
     bool          UsingSSL() const       { return mUsingSSL; }
     bool          UsingConnect() const   { return mUsingConnect; }
     int32_t       DefaultPort() const    { return mUsingSSL ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT; }
     void          SetAnonymous(bool anon)         
                                          { mHashKey.SetCharAt(anon ? 'A' : '.', 2); }
     bool          GetAnonymous() const   { return mHashKey.CharAt(2) == 'A'; }
+    void          SetPrivate(bool priv)  { mHashKey.SetCharAt(priv ? 'P' : '.', 3); }
+    bool          GetPrivate() const     { return mHashKey.CharAt(3) == 'P'; }
 
     const nsCString &GetHost() { return mHost; }
 
 private:
     nsrefcnt               mRef;
     nsCString              mHashKey;
     nsCString              mHost;
     int32_t                mPort;
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -1051,25 +1051,37 @@ nsHttpConnectionMgr::ReportFailedToProce
         rv = uri->SchemeIs("http", &isHttp);
     if (NS_SUCCEEDED(rv))
         rv = uri->GetAsciiHost(host);
     if (NS_SUCCEEDED(rv))
         rv = uri->GetPort(&port);
     if (NS_FAILED(rv) || !isHttp || host.IsEmpty())
         return;
 
-    // report the event for both the anonymous and non-anonymous
-    // versions of this host
+    // report the event for all the permutations of anonymous and
+    // private versions of this host
     nsRefPtr<nsHttpConnectionInfo> ci =
         new nsHttpConnectionInfo(host, port, nullptr, usingSSL);
     ci->SetAnonymous(false);
+    ci->SetPrivate(false);
     PipelineFeedbackInfo(ci, RedCorruptedContent, nullptr, 0);
 
-    ci = new nsHttpConnectionInfo(host, port, nullptr, usingSSL);
+    ci = ci->Clone();
+    ci->SetAnonymous(false);
+    ci->SetPrivate(true);
+    PipelineFeedbackInfo(ci, RedCorruptedContent, nullptr, 0);
+
+    ci = ci->Clone();
     ci->SetAnonymous(true);
+    ci->SetPrivate(false);
+    PipelineFeedbackInfo(ci, RedCorruptedContent, nullptr, 0);
+
+    ci = ci->Clone();
+    ci->SetAnonymous(true);
+    ci->SetPrivate(true);
     PipelineFeedbackInfo(ci, RedCorruptedContent, nullptr, 0);
 }
 
 // we're at the active connection limit if any one of the following conditions is true:
 //  (1) at max-connections
 //  (2) keep-alive enabled and at max-persistent-connections-per-server/proxy
 //  (3) keep-alive disabled and at max-connections-per-server
 bool
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -149,17 +149,16 @@ nsHttpHandler::nsHttpHandler()
     , mPipelineRescheduleOnTimeout(true)
     , mPipelineRescheduleTimeout(PR_MillisecondsToInterval(1500))
     , mPipelineReadTimeout(PR_MillisecondsToInterval(30000))
     , mRedirectionLimit(10)
     , mPhishyUserPassLength(1)
     , mQoSBits(0x00)
     , mPipeliningOverSSL(false)
     , mEnforceAssocReq(false)
-    , mInPrivateBrowsingMode(PRIVATE_BROWSING_UNKNOWN)
     , mLastUniqueID(NowInSeconds())
     , mSessionStartTime(0)
     , mLegacyAppName("Mozilla")
     , mLegacyAppVersion("5.0")
     , mProduct("Gecko")
     , mUserAgentIsDirty(true)
     , mUseCache(true)
     , mPromptTempRedirect(true)
@@ -296,17 +295,16 @@ nsHttpHandler::Init()
                                   NS_HTTP_STARTUP_TOPIC);    
     
     mObserverService = mozilla::services::GetObserverService();
     if (mObserverService) {
         mObserverService->AddObserver(this, "profile-change-net-teardown", true);
         mObserverService->AddObserver(this, "profile-change-net-restore", true);
         mObserverService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, true);
         mObserverService->AddObserver(this, "net:clear-active-logins", true);
-        mObserverService->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
         mObserverService->AddObserver(this, "net:prune-dead-connections", true);
         mObserverService->AddObserver(this, "net:failed-to-process-uri-content", true);
     }
  
     return NS_OK;
 }
 
 nsresult
@@ -403,33 +401,16 @@ nsHttpHandler::IsAcceptableEncoding(cons
     // an "x-" prefix before matching the encoding to one we claim
     // to accept.
     if (!PL_strncasecmp(enc, "x-", 2))
         enc += 2;
 
     return nsHttp::FindToken(mAcceptEncodings.get(), enc, HTTP_LWS ",") != nullptr;
 }
 
-bool
-nsHttpHandler::InPrivateBrowsingMode()
-{
-    if (PRIVATE_BROWSING_UNKNOWN == mInPrivateBrowsingMode) {
-        // figure out if we're starting in private browsing mode
-        nsCOMPtr<nsIPrivateBrowsingService> pbs =
-            do_GetService(NS_PRIVATE_BROWSING_SERVICE_CONTRACTID);
-        if (!pbs)
-            return PRIVATE_BROWSING_OFF;
-
-        bool p = false;
-        pbs->GetPrivateBrowsingEnabled(&p);
-        mInPrivateBrowsingMode = p ? PRIVATE_BROWSING_ON : PRIVATE_BROWSING_OFF;
-    }
-    return PRIVATE_BROWSING_ON == mInPrivateBrowsingMode;
-}
-
 nsresult
 nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
 {
     if (!mStreamConvSvc) {
         nsresult rv;
         mStreamConvSvc = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
         if (NS_FAILED(rv)) return rv;
     }
@@ -1536,24 +1517,16 @@ nsHttpHandler::Observe(nsISupports *subj
     }
     else if (strcmp(topic, "profile-change-net-restore") == 0) {
         // initialize connection manager
         InitConnectionMgr();
     }
     else if (strcmp(topic, "net:clear-active-logins") == 0) {
         mAuthCache.ClearAll();
     }
-    else if (strcmp(topic, NS_PRIVATE_BROWSING_SWITCH_TOPIC) == 0) {
-        if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_ENTER).Equals(data))
-            mInPrivateBrowsingMode = PRIVATE_BROWSING_ON;
-        else if (NS_LITERAL_STRING(NS_PRIVATE_BROWSING_LEAVE).Equals(data))
-            mInPrivateBrowsingMode = PRIVATE_BROWSING_OFF;
-        if (mConnMgr)
-            mConnMgr->ClosePersistentConnections();
-    }
     else if (strcmp(topic, "net:prune-dead-connections") == 0) {
         if (mConnMgr) {
             mConnMgr->PruneDeadConnections();
         }
     }
     else if (strcmp(topic, "net:failed-to-process-uri-content") == 0) {
         nsCOMPtr<nsIURI> uri = do_QueryInterface(subject);
         if (uri && mConnMgr)
--- a/netwerk/protocol/http/nsHttpHandler.h
+++ b/netwerk/protocol/http/nsHttpHandler.h
@@ -17,17 +17,16 @@
 #include "nsCOMPtr.h"
 #include "nsWeakReference.h"
 
 #include "nsIHttpProtocolHandler.h"
 #include "nsIProtocolProxyService.h"
 #include "nsIIOService.h"
 #include "nsIObserver.h"
 #include "nsIObserverService.h"
-#include "nsIPrivateBrowsingService.h"
 #include "nsIStreamConverterService.h"
 #include "nsICacheSession.h"
 #include "nsICookieService.h"
 #include "nsIIDNService.h"
 #include "nsITimer.h"
 #include "nsIStrictTransportSecurityService.h"
 #include "nsISpeculativeConnect.h"
 
@@ -158,19 +157,16 @@ public:
 
     nsresult SpeculativeConnect(nsHttpConnectionInfo *ci,
                                 nsIInterfaceRequestor *callbacks,
                                 nsIEventTarget *target)
     {
         return mConnMgr->SpeculativeConnect(ci, callbacks, target);
     }
 
-    // for anything that wants to know if we're in private browsing mode.
-    bool InPrivateBrowsingMode();
-
     //
     // The HTTP handler caches pointers to specific XPCOM services, and
     // provides the following helper routines for accessing those services:
     //
     nsresult GetStreamConverterService(nsIStreamConverterService **);
     nsresult GetIOService(nsIIOService** service);
     nsICookieService * GetCookieService(); // not addrefed
     nsIStrictTransportSecurityService * GetSTSService();
@@ -309,23 +305,16 @@ private:
     // the userpass field of the URL to obscure the actual origin server.
     uint8_t  mPhishyUserPassLength;
 
     uint8_t  mQoSBits;
 
     bool mPipeliningOverSSL;
     bool mEnforceAssocReq;
 
-    // cached value of whether or not the browser is in private browsing mode.
-    enum {
-        PRIVATE_BROWSING_OFF = false,
-        PRIVATE_BROWSING_ON = true,
-        PRIVATE_BROWSING_UNKNOWN = 2
-    } mInPrivateBrowsingMode;
-
     nsCString mAccept;
     nsCString mAcceptLanguages;
     nsCString mAcceptEncodings;
 
     nsXPIDLCString mDefaultSocketType;
 
     // cache support
     uint32_t                  mLastUniqueID;
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
@@ -31,17 +31,17 @@ WyciwygChannelChild::WyciwygChannelChild
   : mStatus(NS_OK)
   , mIsPending(false)
   , mCanceled(false)
   , mLoadFlags(LOAD_NORMAL)
   , mContentLength(-1)
   , mCharsetSource(kCharsetUninitialized)
   , mState(WCC_NEW)
   , mIPCOpen(false)
-  , mEventQ(this)
+  , mEventQ(NS_ISUPPORTS_CAST(nsIWyciwygChannel*, this))
 {
   LOG(("Creating WyciwygChannelChild @%x\n", this));
 }
 
 WyciwygChannelChild::~WyciwygChannelChild()
 {
   LOG(("Destroying WyciwygChannelChild @%x\n", this));
 }
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -78,16 +78,17 @@ private:
 
 
 // nsWyciwygChannel methods 
 nsWyciwygChannel::nsWyciwygChannel()
   : mStatus(NS_OK),
     mIsPending(false),
     mCharsetAndSourceSet(false),
     mNeedToWriteCharset(false),
+    mPrivateBrowsing(false),
     mCharsetSource(kCharsetUninitialized),
     mContentLength(-1),
     mLoadFlags(LOAD_NORMAL)
 {
 }
 
 nsWyciwygChannel::~nsWyciwygChannel() 
 {
@@ -266,16 +267,19 @@ NS_IMETHODIMP
 nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
 {
   mCallbacks = aNotificationCallbacks;
   NS_QueryNotificationCallbacks(mCallbacks,
                                 mLoadGroup,
                                 NS_GET_IID(nsIProgressEventSink),
                                 getter_AddRefs(mProgressSink));
 
+  // Will never change unless SetNotificationCallbacks called again, so cache
+  mPrivateBrowsing = NS_UsePrivateBrowsing(this);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
 {
   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
 
@@ -658,28 +662,31 @@ nsWyciwygChannel::OpenCacheEntry(const n
   nsresult rv = NS_ERROR_FAILURE;
   // Get cache service
   nsCOMPtr<nsICacheService> cacheService =
     do_GetService(NS_CACHESERVICE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // honor security settings
   nsCacheStoragePolicy storagePolicy;
-  if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
+  if (mPrivateBrowsing || mLoadFlags & INHIBIT_PERSISTENT_CACHING)
     storagePolicy = nsICache::STORE_IN_MEMORY;
   else
     storagePolicy = nsICache::STORE_ANYWHERE;
 
   nsCOMPtr<nsICacheSession> cacheSession;
   // Open a stream based cache session.
-  rv = cacheService->CreateSession("wyciwyg", storagePolicy, true,
+  const char* sessionName = mPrivateBrowsing ? "wyciwyg-private" : "wyciwyg";
+  rv = cacheService->CreateSession(sessionName, storagePolicy, true,
                                    getter_AddRefs(cacheSession));
   if (!cacheSession) 
     return NS_ERROR_FAILURE;
 
+  cacheSession->SetIsPrivate(mPrivateBrowsing);
+
   if (aAccessMode == nsICache::ACCESS_WRITE)
     rv = cacheSession->OpenCacheEntry(aCacheKey, aAccessMode, false,
                                       getter_AddRefs(mCacheEntry));
   else
     rv = cacheSession->AsyncOpenCacheEntry(aCacheKey, aAccessMode, this, false);
 
   return rv;
 }
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
@@ -67,16 +67,17 @@ protected:
 
     void NotifyListener();
     bool IsOnCacheIOThread();
 
     nsresult                            mStatus;
     bool                                mIsPending;
     bool                                mCharsetAndSourceSet;
     bool                                mNeedToWriteCharset;
+    bool                                mPrivateBrowsing;
     int32_t                             mCharsetSource;
     nsCString                           mCharset;
     int32_t                             mContentLength;
     uint32_t                            mLoadFlags;
     nsCOMPtr<nsIURI>                    mURI;
     nsCOMPtr<nsIURI>                    mOriginalURI;
     nsCOMPtr<nsISupports>               mOwner;
     nsCOMPtr<nsIInterfaceRequestor>     mCallbacks;
--- a/netwerk/test/unit/test_bug248970_cache.js
+++ b/netwerk/test/unit/test_bug248970_cache.js
@@ -5,46 +5,27 @@
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 // names for cache devices
 const kDiskDevice = "disk";
 const kMemoryDevice = "memory";
 const kOfflineDevice = "offline";
+const kPrivate = "private";
 
 const kCacheA = "cache-A";
 const kCacheA2 = "cache-A2";
 const kCacheB = "cache-B";
 const kCacheC = "cache-C";
 const kTestContent = "test content";
 
 // the name for our cache session
 const kPrivateBrowsing = "PrivateBrowsing";
 
-var _PBSvc;
-function get_privatebrowsing_service() {
-  if (_PBSvc)
-    return _PBSvc;
-
-  try {
-    _PBSvc = Cc["@mozilla.org/privatebrowsing;1"].
-             getService(Ci.nsIPrivateBrowsingService);
-    return _PBSvc;
-  } catch (e) {}
-
-  return null;
-}
-
-
-
-
-
-
-
 function check_devices_available(devices) {
   var cs = get_cache_service();
   var found_devices = [];
 
   var visitor = {
     visitDevice: function (deviceID, deviceInfo) {
       found_devices.push(deviceID);
       return false;
@@ -97,29 +78,31 @@ function make_input_stream_scriptable(in
   var wrapper = Cc["@mozilla.org/scriptableinputstream;1"].
                 createInstance(Ci.nsIScriptableInputStream);
   wrapper.init(input);
   return wrapper;
 }
 
 const entries = [
 // key       content       device          should exist after leaving PB
-  [kCacheA,  kTestContent, kMemoryDevice,  false],
+  [kCacheA,  kTestContent, kMemoryDevice,  true],
+  [kCacheA2, kTestContent, kPrivate,       false],
   [kCacheB,  kTestContent, kDiskDevice,    true],
   [kCacheC,  kTestContent, kOfflineDevice, true]
 ]
 
 function get_storage_policy(device)
 {
   switch (device) {
     case kDiskDevice:
       return Ci.nsICache.STORE_ON_DISK;
     case kOfflineDevice:
       return Ci.nsICache.STORE_OFFLINE;
     case kMemoryDevice:
+    case kPrivate:
       return Ci.nsICache.STORE_IN_MEMORY;
   }
   do_throw("unknown device");
 }
 
 var store_idx;
 var store_cb = null;
 function store_entries(cb)
@@ -133,16 +116,19 @@ function store_entries(cb)
     do_execute_soon(store_cb);
     return;
   }
 
   var cache = get_cache_service();
   var session = cache.createSession(kPrivateBrowsing,
                                     get_storage_policy(entries[store_idx][2]),
                                     Ci.nsICache.STREAM_BASED);
+  if (entries[store_idx][2] == kPrivate) {
+    session.isPrivate = true;
+  }
 
   session.asyncOpenCacheEntry(entries[store_idx][0],
                               Ci.nsICache.ACCESS_WRITE,
                               store_data);
 }
 
 var store_data = {
   onCacheEntryAvailable: function oCEA(entry, access, status) {
@@ -177,16 +163,19 @@ function check_entries(cb, pbExited)
     do_execute_soon(check_cb);
     return;
   }
 
   var cache = get_cache_service();
   var session = cache.createSession(kPrivateBrowsing,
                                     get_storage_policy(entries[check_idx][2]),
                                     Ci.nsICache.STREAM_BASED);
+  if (entries[check_idx][2] == kPrivate) {
+    session.isPrivate = true;
+  }
 
   session.asyncOpenCacheEntry(entries[check_idx][0],
                               Ci.nsICache.ACCESS_READ,
                               check_data);
 }
 
 var check_data = {
   onCacheEntryAvailable: function oCEA(entry, access, status) {
@@ -223,38 +212,22 @@ function run_test2() {
   // Make sure all three cache devices are available initially
   check_devices_available([kMemoryDevice, kDiskDevice, kOfflineDevice]);
 
   // Check if cache-A, cache-A2, cache-B and cache-C are available
   check_entries(run_test3, false);
 }
 
 function run_test3() {
-  var pb = get_privatebrowsing_service();
-  if (pb) { // Private Browsing might not be available
-    var prefBranch = Cc["@mozilla.org/preferences-service;1"].
-                     getService(Ci.nsIPrefBranch);
-    prefBranch.setBoolPref("browser.privatebrowsing.keep_current_session", true);
-
-    // Enter private browsing mode
-    pb.privateBrowsingEnabled = true;
-
-    // Make sure only the memory device is available
-    check_devices_available([kMemoryDevice]);
-
-    // Make sure the memory device is empty
-    do_check_eq(get_device_entry_count(kMemoryDevice), 0);
+  // Simulate all private browsing instances being closed
+  var obsvc = Cc["@mozilla.org/observer-service;1"].
+    getService(Ci.nsIObserverService);
+  obsvc.notifyObservers(null, "last-pb-context-exited", null);
 
-    // Exit private browsing mode
-    pb.privateBrowsingEnabled = false;
-
-    // Make sure all three cache devices are available after leaving the private mode
-    check_devices_available([kMemoryDevice, kDiskDevice, kOfflineDevice]);
+  // Make sure all three cache devices are still available
+  check_devices_available([kMemoryDevice, kDiskDevice, kOfflineDevice]);
 
-    // Make sure the memory device is empty
-    do_check_eq(get_device_entry_count(kMemoryDevice), 0);
+  // Make sure the memory device is not empty
+  do_check_eq(get_device_entry_count(kMemoryDevice), 1);
 
-    // Check if cache-A is gone, and cache-B and cache-C are still available
-    check_entries(do_test_finished, true);
-    
-    prefBranch.clearUserPref("browser.privatebrowsing.keep_current_session");
-  }
+  // Check if cache-A is gone, and cache-B and cache-C are still available
+  check_entries(do_test_finished, true);
 }
--- a/xpcom/glue/nsISupportsImpl.h
+++ b/xpcom/glue/nsISupportsImpl.h
@@ -1178,16 +1178,22 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(
   NS_INTERFACE_TABLE_TAIL_INHERITING(Super)
 
 #define NS_IMPL_QUERY_INTERFACE_INHERITED9(Class,Super,i1,i2,i3,i4,i5,i6,     \
                                            i7,i8,i9)                          \
   NS_INTERFACE_TABLE_HEAD(Class)                                              \
   NS_INTERFACE_TABLE_INHERITED9(Class, i1, i2, i3, i4, i5, i6, i7, i8, i9)    \
   NS_INTERFACE_TABLE_TAIL_INHERITING(Super)
 
+#define NS_IMPL_QUERY_INTERFACE_INHERITED10(Class,Super,i1,i2,i3,i4,i5,i6,       \
+                                            i7,i8,i9,i10)                        \
+  NS_INTERFACE_TABLE_HEAD(Class)                                                 \
+  NS_INTERFACE_TABLE_INHERITED10(Class, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10) \
+  NS_INTERFACE_TABLE_TAIL_INHERITING(Super)
+
 /**
  * Convenience macros for implementing all nsISupports methods for
  * a simple class.
  * @param _class The name of the class implementing the method
  * @param _classiiddef The name of the #define symbol that defines the IID
  * for the class (e.g. NS_ISUPPORTS_IID)
  */
 
@@ -1300,16 +1306,21 @@ NS_IMETHODIMP_(nsrefcnt) Class::Release(
     NS_IMPL_QUERY_INTERFACE_INHERITED8(Class, Super, i1, i2, i3, i4, i5, i6, i7, i8) \
     NS_IMPL_ADDREF_INHERITED(Class, Super)                                    \
     NS_IMPL_RELEASE_INHERITED(Class, Super)                                   \
 
 #define NS_IMPL_ISUPPORTS_INHERITED9(Class, Super, i1, i2, i3, i4, i5, i6, i7, i8, i9) \
     NS_IMPL_QUERY_INTERFACE_INHERITED9(Class, Super, i1, i2, i3, i4, i5, i6, i7, i8, i9) \
     NS_IMPL_ADDREF_INHERITED(Class, Super)                                    \
     NS_IMPL_RELEASE_INHERITED(Class, Super)                                   \
+
+#define NS_IMPL_ISUPPORTS_INHERITED10(Class, Super, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10) \
+    NS_IMPL_QUERY_INTERFACE_INHERITED10(Class, Super, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10) \
+    NS_IMPL_ADDREF_INHERITED(Class, Super)                                    \
+    NS_IMPL_RELEASE_INHERITED(Class, Super)                                   \
 /*
  * Macro to glue together a QI that starts with an interface table
  * and segues into an interface map (e.g. it uses singleton classinfo
  * or tearoffs).
  */
 #define NS_INTERFACE_TABLE_TO_MAP_SEGUE \
   if (rv == NS_OK) return rv; \
   nsISupports* foundInterface;