Backed out changeset 849137ee7609 (bug 787743) because of build failures; a=me
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 04 Sep 2012 23:53:48 -0400
changeset 104675 98bde61218406497c1b61126a87fb1b18d70c53a
parent 104674 849137ee7609871f2279245e13bf18cf23ba3278
child 104676 2bbf690626ab31a618a231bc8d7085c5d2ee4e97
push id1354
push usereakhgari@mozilla.com
push dateWed, 05 Sep 2012 03:54:32 +0000
treeherdermozilla-beta@98bde6121840 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme
bugs787743
milestone16.0
backs out849137ee7609871f2279245e13bf18cf23ba3278
Backed out changeset 849137ee7609 (bug 787743) because of build failures; a=me
browser/components/privatebrowsing/test/browser/browser_privatebrowsing_lastpbcontextexited.js
content/base/src/nsContentSink.cpp
docshell/base/nsDocShell.cpp
netwerk/base/public/Makefile.in
netwerk/base/public/nsIPrivateBrowsingConsumer.idl
netwerk/base/src/PrivateBrowsingConsumer.h
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/FTPChannelChild.cpp
netwerk/protocol/ftp/FTPChannelChild.h
netwerk/protocol/ftp/FTPChannelParent.cpp
netwerk/protocol/ftp/FTPChannelParent.h
netwerk/protocol/ftp/PFTPChannel.ipdl
netwerk/protocol/ftp/nsFTPChannel.h
netwerk/protocol/ftp/nsFtpConnectionThread.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
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/PWyciwygChannel.ipdl
netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
netwerk/protocol/wyciwyg/WyciwygChannelChild.h
netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
netwerk/protocol/wyciwyg/WyciwygChannelParent.h
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"
@@ -1006,16 +1007,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
@@ -8913,16 +8913,20 @@ nsDocShell::GetInheritedPrincipal(bool a
     }
 
     return nsnull;
 }
 
 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/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -53,16 +53,17 @@ XPIDLSRCS	= \
 		nsIInputStreamChannel.idl \
                 nsIIOService2.idl \
                 nsIIPCSerializable.idl \
 		nsIMIMEInputStream.idl \
 		nsINetAddr.idl \
                 nsINetworkLinkService.idl \
 		nsIPermission.idl \
 		nsIPermissionManager.idl \
+		nsIPrivateBrowsingConsumer.idl \
 		nsIPrivateBrowsingService.idl \
 		nsIProgressEventSink.idl \
 		nsIPrompt.idl \
 		nsIProtocolProxyService.idl \
 		nsIProtocolProxyService2.idl \
 		nsIProtocolProxyFilter.idl \
 		nsIProtocolProxyCallback.idl \
 		nsIProxiedProtocolHandler.idl \
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIPrivateBrowsingConsumer.idl
@@ -0,0 +1,22 @@
+/* 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 "nsISupports.idl"
+
+[scriptable, uuid(5deb421c-592b-4375-b425-9ac11532aa30)]
+interface nsIPrivateBrowsingConsumer : nsISupports
+{
+  readonly attribute boolean usingPrivateBrowsing;
+
+%{C++
+  /**
+   * De-XPCOMed getter to make call-sites cleaner.
+   */
+  bool UsePrivateBrowsing() {
+    bool usingPB;
+    GetUsingPrivateBrowsing(&usingPB);
+    return usingPB;
+  }
+%}
+};
new file mode 100644
--- /dev/null
+++ b/netwerk/base/src/PrivateBrowsingConsumer.h
@@ -0,0 +1,56 @@
+/* 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/. */
+
+#ifndef mozilla_net_PrivateBrowsingConsumer_h
+#define mozilla_net_PrivateBrowsingConsumer_h
+
+#include "nsIPrivateBrowsingConsumer.h"
+#include "nsILoadContext.h"
+#include "nsNetUtil.h"
+#include "nsXULAppAPI.h"
+
+namespace mozilla {
+namespace net {
+
+class PrivateBrowsingConsumer : public nsIPrivateBrowsingConsumer
+{
+ public:
+  PrivateBrowsingConsumer(nsIChannel* aSelf) : mSelf(aSelf), mUsingPB(false), mOverride(false) {}
+
+  NS_IMETHOD GetUsingPrivateBrowsing(bool *aUsingPB)
+  {
+    *aUsingPB = (mOverride ? mUsingPB : UsingPrivateBrowsingInternal());
+    return NS_OK;
+  }
+  
+  void OverridePrivateBrowsing(bool aUsingPrivateBrowsing)
+  {
+    MOZ_ASSERT(!mOverride);
+    MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
+    mOverride = true;
+    mUsingPB = aUsingPrivateBrowsing;
+  }
+
+ protected:
+  bool UsingPrivateBrowsingInternal()
+  {
+    nsCOMPtr<nsILoadContext> loadContext;
+    NS_QueryNotificationCallbacks(mSelf, loadContext);
+    return loadContext && loadContext->UsePrivateBrowsing();
+  }
+
+ private:
+   nsIChannel* mSelf;
+
+  // Private browsing capabilities can only be determined in content
+  // processes, so when networking occurs these values are used in
+  // lieu of UsingPrivateBrowsing().
+  bool mUsingPB;
+  bool mOverride;
+};
+
+}
+}
+
+#endif // mozilla_net_PrivateBrowsingConsumer_h
--- a/netwerk/cache/nsCacheEntry.cpp
+++ b/netwerk/cache/nsCacheEntry.cpp
@@ -37,16 +37,18 @@ nsCacheEntry::nsCacheEntry(nsCString *  
 {
     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);
     delete mKey;
     
--- 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);
@@ -62,16 +63,17 @@ private:
     }
     
     /**
      * Simple Accessors
      */
     enum CacheRequestInfo {
         eStoragePolicyMask         = 0x000000FF,
         eStreamBasedMask           = 0x00000100,
+        ePrivateMask               = 0x00000200,
         eDoomEntriesIfExpiredMask  = 0x00001000,
         eBlockingModeMask          = 0x00010000,
         eWaitingForValidationMask  = 0x00100000,
         eAccessRequestedMask       = 0xFF000000
     };
 
     void SetAccessRequested(nsCacheAccessMode mode)
     {
@@ -100,19 +102,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"
@@ -72,17 +71,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,
     OFFLINE_CACHE_ENABLE_PREF,
@@ -119,17 +118,16 @@ public:
         , mDiskCacheCapacity(0)
         , mDiskCacheMaxEntrySize(-1) // -1 means "no limit"
         , mSmartSizeEnabled(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() {}
     
@@ -172,18 +170,16 @@ private:
     bool                    mOfflineCacheEnabled;
     PRInt32                 mOfflineCacheCapacity; // in kilobytes
     nsCOMPtr<nsIFile>       mOfflineCacheParentDirectory;
     
     bool                    mMemoryCacheEnabled;
     PRInt32                 mMemoryCacheCapacity; // in kilobytes
     PRInt32                 mMemoryCacheMaxEntrySize; // in kilobytes
 
-    bool                    mInPrivateBrowsing;
-
     PRInt32                 mCacheCompressionLevel;
 
     bool                    mSanitizeOnShutdown;
     bool                    mClearCacheOnShutdown;
 };
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsCacheProfilePrefObserver, nsIObserver)
 
@@ -305,22 +301,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;
@@ -401,23 +391,21 @@ nsCacheProfilePrefObserver::Observe(nsIS
 
         nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(subject, &rv);
         if (NS_FAILED(rv))  
             return rv;
 
         // which preference changed?
         if (!strcmp(DISK_CACHE_ENABLE_PREF, data.get())) {
 
-            if (!mInPrivateBrowsing) {
-                rv = branch->GetBoolPref(DISK_CACHE_ENABLE_PREF,
-                                         &mDiskCacheEnabled);
-                if (NS_FAILED(rv))  
-                    return rv;
-                nsCacheService::SetDiskCacheEnabled(DiskCacheEnabled());
-            }
+            rv = branch->GetBoolPref(DISK_CACHE_ENABLE_PREF,
+                                     &mDiskCacheEnabled);
+            if (NS_FAILED(rv))  
+                return rv;
+            nsCacheService::SetDiskCacheEnabled(DiskCacheEnabled());
 
         } else if (!strcmp(DISK_CACHE_CAPACITY_PREF, data.get())) {
 
             PRInt32 capacity = 0;
             rv = branch->GetIntPref(DISK_CACHE_CAPACITY_PREF, &capacity);
             if (NS_FAILED(rv))  
                 return rv;
             mDiskCacheCapacity = NS_MAX(0, capacity);
@@ -458,22 +446,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())) {
 
             PRInt32 capacity = 0;
             rv = branch->GetIntPref(OFFLINE_CACHE_CAPACITY_PREF, &capacity);
             if (NS_FAILED(rv))  return rv;
             mOfflineCacheCapacity = NS_MAX(0, capacity);
             nsCacheService::SetOfflineCacheCapacity(mOfflineCacheCapacity);
@@ -523,48 +509,20 @@ 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 PRUint32
 SmartCacheSize(const PRUint32 availKB)
 {
@@ -680,20 +638,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);
@@ -761,21 +717,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),
@@ -2062,16 +2016,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()) {
@@ -2280,17 +2237,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(nsnull);
     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)
@@ -2845,42 +2802,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);
 
     PRUint32 count = array.Length();
     for (PRUint32 i=0; i < count; ++i)
         DoomEntry_Internal(array[i], true);
 }
 
-
 PLDHashOperator
 nsCacheService::RemoveActiveEntry(PLDHashTable *    table,
                                   PLDHashEntryHdr * hdr,
                                   PRUint32          number,
                                   void *            arg)
 {
     nsCacheEntry * entry = ((nsCacheEntryHashTableEntry *)hdr)->cacheEntry;
     NS_ASSERTION(entry, "### active entry = nsnull!");
 
-    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 = nsnull!");
+    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)
@@ -2900,30 +2865,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;
-
-    gService->DoomActiveEntries();
-
-    if (gService->mMemoryDevice) {
-        // clear memory cache
-        gService->mMemoryDevice->EvictEntries(nsnull);
-    }
-}
-
 nsresult
 nsCacheService::SetDiskSmartSize()
 {
     nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHESERVICE_SETDISKSMARTSIZE));
 
     if (!gService) return NS_ERROR_NOT_AVAILABLE;
 
     return gService->SetDiskSmartSize_Locked();
@@ -2950,8 +2901,27 @@ nsCacheService::SetDiskSmartSize_Locked(
             new nsGetSmartSizeEvent(cachePath, mDiskDevice->getCacheSize());
         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
@@ -158,27 +158,29 @@ public:
     static void      SetOfflineCacheEnabled(bool    enabled);
     // Sets the offline cache capacity (in kilobytes)
     static void      SetOfflineCacheCapacity(PRInt32  capacity);
 
     static void      SetMemoryCache();
 
     static void      SetCacheCompressionLevel(PRInt32 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();
+
+    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;
@@ -234,17 +236,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,
                                              PRUint32          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;
+    PRUint32 prefixLength;
+};
+
+static bool
+EntryMatchesClientID(nsCacheEntry* entry, void* args)
+{
+    const char * clientID = static_cast<ClientIDArgs*>(args)->clientID;
+    PRUint32 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;
-    PRUint32 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 ? PRUint32(strlen(clientID)) : 0};
+    return DoEvictEntries(&EntryMatchesClientID, &args);
+}
+
+nsresult
+nsMemoryCacheDevice::EvictPrivateEntries()
+{
+    return DoEvictEntries(&IsEntryPrivate, NULL);
+}
+
 
 // WARNING: SetCapacity can get called before Init()
 void
 nsMemoryCacheDevice::SetCapacity(PRInt32  capacity)
 {
     PRInt32 hardLimit = capacity * 1024;  // convert k into bytes
     PRInt32 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, PRInt32 deltaSize );
 
     virtual nsresult Visit( nsICacheVisitor * visitor );
 
     virtual nsresult EvictEntries(const char * clientID);
+    nsresult EvictPrivateEntries();
     
     void             SetCapacity(PRInt32  capacity);
     void             SetMaxEntrySize(PRInt32  maxSizeInKilobytes);
 
     bool             EntryIsTooBig(PRInt64 entrySize);
 
     size_t           TotalSize();
 
@@ -64,16 +65,19 @@ private:
     enum      { DELETE_ENTRY        = true,
                 DO_NOT_DELETE_ENTRY = false };
 
     void      AdjustMemoryLimits( PRInt32  softLimit, PRInt32  hardLimit);
     void      EvictEntry( nsCacheEntry * entry , bool deleteEntry);
     void      EvictEntriesIfNecessary();
     int       EvictionList(nsCacheEntry * entry, PRInt32  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/FTPChannelChild.cpp
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -18,17 +18,18 @@
 
 #undef LOG
 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
 
 namespace mozilla {
 namespace net {
 
 FTPChannelChild::FTPChannelChild(nsIURI* uri)
-: mIPCOpen(false)
+: PrivateBrowsingConsumer(this)
+, mIPCOpen(false)
 , ALLOW_THIS_IN_INITIALIZER_LIST(mEventQ(static_cast<nsIFTPChannel*>(this)))
 , mCanceled(false)
 , mSuspendCount(0)
 , mIsPending(false)
 , mWasOpened(false)
 , mLastModifiedTime(0)
 , mStartPos(0)
 {
@@ -155,17 +156,17 @@ FTPChannelChild::AsyncOpen(::nsIStreamLi
   mListener = listener;
   mListenerContext = aContext;
 
   // add ourselves to the load group. 
   if (mLoadGroup)
     mLoadGroup->AddRequest(this, nsnull);
 
   SendAsyncOpen(nsBaseChannel::URI(), mStartPos, mEntityID,
-                IPC::InputStream(mUploadStream));
+                IPC::InputStream(mUploadStream), UsePrivateBrowsing());
 
   // The socket transport layer in the chrome process now has a logical ref to
   // us until OnStopRequest is called.
   AddIPDLReference();
 
   mIsPending = true;
   mWasOpened = true;
 
--- a/netwerk/protocol/ftp/FTPChannelChild.h
+++ b/netwerk/protocol/ftp/FTPChannelChild.h
@@ -11,16 +11,17 @@
 #include "mozilla/net/PFTPChannelChild.h"
 #include "mozilla/net/ChannelEventQueue.h"
 #include "nsBaseChannel.h"
 #include "nsIFTPChannel.h"
 #include "nsIUploadChannel.h"
 #include "nsIProxiedChannel.h"
 #include "nsIResumableChannel.h"
 #include "nsIChildChannel.h"
+#include "PrivateBrowsingConsumer.h"
 
 #include "nsIStreamListener.h"
 
 namespace mozilla {
 namespace net {
 
 // This class inherits logic from nsBaseChannel that is not needed for an
 // e10s child channel, but it works.  At some point we could slice up
@@ -29,16 +30,17 @@ namespace net {
 
 class FTPChannelChild : public PFTPChannelChild
                       , public nsBaseChannel
                       , public nsIFTPChannel
                       , public nsIUploadChannel
                       , public nsIResumableChannel
                       , public nsIProxiedChannel
                       , public nsIChildChannel
+                      , public PrivateBrowsingConsumer
 {
 public:
   typedef ::nsIStreamListener nsIStreamListener;
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIFTPCHANNEL
   NS_DECL_NSIUPLOADCHANNEL
   NS_DECL_NSIRESUMABLECHANNEL
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -52,17 +52,18 @@ NS_IMPL_ISUPPORTS4(FTPChannelParent,
 //-----------------------------------------------------------------------------
 // FTPChannelParent::PFTPChannelParent
 //-----------------------------------------------------------------------------
 
 bool
 FTPChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
                                 const PRUint64& aStartPos,
                                 const nsCString& aEntityID,
-                                const IPC::InputStream& aUploadStream)
+                                const IPC::InputStream& aUploadStream,
+                                const bool& aUsePrivateBrowsing)
 {
   nsCOMPtr<nsIURI> uri(aURI);
 
 #ifdef DEBUG
   nsCString uriSpec;
   uri->GetSpec(uriSpec);
   LOG(("FTPChannelParent RecvAsyncOpen [this=%x uri=%s]\n",
        this, uriSpec.get()));
@@ -87,16 +88,18 @@ FTPChannelParent::RecvAsyncOpen(const IP
     if (NS_FAILED(rv))
       return SendFailedAsyncOpen(rv);
   }
 
   rv = mChannel->ResumeAt(aStartPos, aEntityID);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
 
+  mChannel->OverridePrivateBrowsing(aUsePrivateBrowsing);
+
   rv = mChannel->AsyncOpen(this, nsnull);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
   
   return true;
 }
 
 bool
--- a/netwerk/protocol/ftp/FTPChannelParent.h
+++ b/netwerk/protocol/ftp/FTPChannelParent.h
@@ -31,17 +31,18 @@ public:
 
   FTPChannelParent();
   virtual ~FTPChannelParent();
 
 protected:
   NS_OVERRIDE virtual bool RecvAsyncOpen(const IPC::URI& uri,
                                          const PRUint64& startPos,
                                          const nsCString& entityID,
-                                         const IPC::InputStream& uploadStream);
+                                         const IPC::InputStream& uploadStream,
+                                         const bool& aUsePrivateBrowsing);
   NS_OVERRIDE virtual bool RecvConnectChannel(const PRUint32& channelId);
   NS_OVERRIDE virtual bool RecvCancel(const nsresult& status);
   NS_OVERRIDE virtual bool RecvSuspend();
   NS_OVERRIDE virtual bool RecvResume();
 
   NS_OVERRIDE virtual void ActorDestroy(ActorDestroyReason why);
 
   nsRefPtr<nsFtpChannel> mChannel;
--- a/netwerk/protocol/ftp/PFTPChannel.ipdl
+++ b/netwerk/protocol/ftp/PFTPChannel.ipdl
@@ -19,17 +19,17 @@ namespace net {
 async protocol PFTPChannel
 {
   manager PNecko;
 
 parent:
   __delete__();
 
   AsyncOpen(URI uri, PRUint64 startPos, nsCString entityID,
-            InputStream uploadStream);
+            InputStream uploadStream, bool usePrivateBrowsing);
   ConnectChannel(PRUint32 channelId);
   Cancel(nsresult status);
   Suspend();
   Resume();
 
 child:
   OnStartRequest(PRInt32 aContentLength, nsCString aContentType,
                  PRTime aLastModified, nsCString aEntityID, URI aURI);
--- a/netwerk/protocol/ftp/nsFTPChannel.h
+++ b/netwerk/protocol/ftp/nsFTPChannel.h
@@ -23,31 +23,34 @@
 #include "nsIStreamListener.h"
 #include "nsIFTPChannel.h"
 #include "nsIUploadChannel.h"
 #include "nsIProxyInfo.h"
 #include "nsIProxiedChannel.h"
 #include "nsIResumableChannel.h"
 #include "nsHashPropertyBag.h"
 #include "nsFtpProtocolHandler.h"
+#include "PrivateBrowsingConsumer.h"
 
 class nsFtpChannel : public nsBaseChannel,
                      public nsIFTPChannel,
                      public nsIUploadChannel,
                      public nsIResumableChannel,
-                     public nsIProxiedChannel
+                     public nsIProxiedChannel,
+                     public mozilla::net::PrivateBrowsingConsumer
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIUPLOADCHANNEL
     NS_DECL_NSIRESUMABLECHANNEL
     NS_DECL_NSIPROXIEDCHANNEL
     
     nsFtpChannel(nsIURI *uri, nsIProxyInfo *pi)
-        : mProxyInfo(pi)
+        : mozilla::net::PrivateBrowsingConsumer(this)
+        , mProxyInfo(pi)
         , mStartPos(0)
         , mResumeRequested(false)
         , mLastModifiedTime(0)
     {
         SetURI(uri);
     }
 
     nsIProxyInfo *ProxyInfo() {
--- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
+++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp
@@ -2212,24 +2212,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 = mChannel->UsePrivateBrowsing();
+    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,26 +12,28 @@
 #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 {
 
 HttpBaseChannel::HttpBaseChannel()
-  : mStartPos(LL_MAXUINT)
+  : PrivateBrowsingConsumer(this)
+  , mStartPos(LL_MAXUINT)
   , mStatus(NS_OK)
   , mLoadFlags(LOAD_NORMAL)
   , mPriority(PRIORITY_NORMAL)
   , mCaps(0)
   , mRedirectionLimit(gHttpHandler->RedirectionLimit())
   , mApplyConversion(true)
   , mCanceled(false)
   , mIsPending(false)
@@ -133,27 +135,28 @@ HttpBaseChannel::Init(nsIURI *aURI,
 
   return rv;
 }
 
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS_INHERITED9(HttpBaseChannel,
-                             nsHashPropertyBag, 
-                             nsIRequest,
-                             nsIChannel,
-                             nsIEncodedChannel,
-                             nsIHttpChannel,
-                             nsIHttpChannelInternal,
-                             nsIUploadChannel,
-                             nsIUploadChannel2,
-                             nsISupportsPriority,
-                             nsITraceableChannel)
+NS_IMPL_ISUPPORTS_INHERITED10(HttpBaseChannel,
+                              nsHashPropertyBag, 
+                              nsIRequest,
+                              nsIChannel,
+                              nsIEncodedChannel,
+                              nsIHttpChannel,
+                              nsIHttpChannelInternal,
+                              nsIUploadChannel,
+                              nsIUploadChannel2,
+                              nsISupportsPriority,
+                              nsITraceableChannel,
+                              nsIPrivateBrowsingConsumer)
 
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpBaseChannel::GetName(nsACString& aName)
 {
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -23,16 +23,17 @@
 #include "nsIProgressEventSink.h"
 #include "nsIURI.h"
 #include "nsIStringEnumerator.h"
 #include "nsISupportsPriority.h"
 #include "nsIApplicationCache.h"
 #include "nsIResumableChannel.h"
 #include "nsITraceableChannel.h"
 #include "mozilla/net/NeckoCommon.h"
+#include "PrivateBrowsingConsumer.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace net {
 
 /*
  * This class is a partial implementation of nsIHttpChannel.  It contains code
  * shared by nsHttpChannel and HttpChannelChild. 
@@ -44,16 +45,17 @@ class HttpBaseChannel : public nsHashPro
                       , public nsIEncodedChannel
                       , public nsIHttpChannel
                       , public nsIHttpChannelInternal
                       , public nsIUploadChannel
                       , public nsIUploadChannel2
                       , public nsISupportsPriority
                       , public nsIResumableChannel
                       , public nsITraceableChannel
+                      , public PrivateBrowsingConsumer
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIUPLOADCHANNEL
   NS_DECL_NSIUPLOADCHANNEL2
   NS_DECL_NSITRACEABLECHANNEL
 
   HttpBaseChannel();
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1036,17 +1036,17 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
 
   SendAsyncOpen(IPC::URI(mURI), IPC::URI(mOriginalURI),
                 IPC::URI(mDocumentURI), IPC::URI(mReferrer), mLoadFlags,
                 mClientSetRequestHeaders, mRequestHead.Method(),
                 IPC::InputStream(mUploadStream), mUploadStreamHasHeaders,
                 mPriority, mRedirectionLimit, mAllowPipelining,
                 mForceAllowThirdPartyCookie, mSendResumeAt,
                 mStartPos, mEntityID, mChooseApplicationCache, 
-                appCacheClientId, mAllowSpdy);
+                appCacheClientId, mAllowSpdy, UsePrivateBrowsing());
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIHttpChannel
 //-----------------------------------------------------------------------------
 
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -106,17 +106,18 @@ HttpChannelParent::RecvAsyncOpen(const I
                                  const PRUint8&             redirectionLimit,
                                  const bool&              allowPipelining,
                                  const bool&              forceAllowThirdPartyCookie,
                                  const bool&                doResumeAt,
                                  const PRUint64&            startPos,
                                  const nsCString&           entityID,
                                  const bool&                chooseApplicationCache,
                                  const nsCString&           appCacheClientID,
-                                 const bool&                allowSpdy)
+                                 const bool&                allowSpdy,
+                                 const bool&                usingPrivateBrowsing)
 {
   nsCOMPtr<nsIURI> uri(aURI);
   nsCOMPtr<nsIURI> originalUri(aOriginalURI);
   nsCOMPtr<nsIURI> docUri(aDocURI);
   nsCOMPtr<nsIURI> referrerUri(aReferrerURI);
 
   nsCString uriSpec;
   uri->GetSpec(uriSpec);
@@ -203,16 +204,18 @@ HttpChannelParent::RecvAsyncOpen(const I
                                                            &setChooseApplicationCache);
 
         if (setChooseApplicationCache && NS_SUCCEEDED(rv))
           appCacheChan->SetChooseApplicationCache(true);
       }
     }
   }
 
+  httpChan->OverridePrivateBrowsing(usingPrivateBrowsing);
+
   rv = httpChan->AsyncOpen(channelListener, nsnull);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
 
   return true;
 }
 
 bool
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -58,17 +58,18 @@ protected:
                              const PRUint8&             redirectionLimit,
                              const bool&              allowPipelining,
                              const bool&              forceAllowThirdPartyCookie,
                              const bool&                doResumeAt,
                              const PRUint64&            startPos,
                              const nsCString&           entityID,
                              const bool&                chooseApplicationCache,
                              const nsCString&           appCacheClientID,
-                             const bool&                allowSpdy);
+                             const bool&                allowSpdy,
+                             const bool&                usingPrivateBrowsing);
 
   virtual bool RecvConnectChannel(const PRUint32& channelId);
   virtual bool RecvSetPriority(const PRUint16& priority);
   virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset);
   virtual bool RecvSuspend();
   virtual bool RecvResume();
   virtual bool RecvCancel(const nsresult& status);
   virtual bool RecvRedirect2Verify(const nsresult& result,
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -44,17 +44,18 @@ parent:
             PRUint8             redirectionLimit,
             bool                allowPipelining,
             bool                forceAllowThirdPartyCookie,
             bool                resumeAt,
             PRUint64            startPos,
             nsCString           entityID,
             bool                chooseApplicationCache,
             nsCString           appCacheClientID,
-            bool                allowSpdy);
+            bool                allowSpdy,
+            bool                usePrivateBrowsing);
 
   // Used to connect redirected-to channel on the parent with redirected-to
   // channel on the child.
   ConnectChannel(PRUint32 channelId);
 
   SetPriority(PRUint16 priority);
 
   SetCacheTokenCachedCharset(nsCString charset);
--- 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 PRUint32 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(UsingPrivateBrowsing());
     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(UsingPrivateBrowsing());
 
     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;
@@ -2434,17 +2442,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, UsingPrivateBrowsing(),
                                 cacheKey, nsICache::ACCESS_READ,
                                 mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY,
                                 usingSSL, true);
 
             mOnCacheEntryAvailableCallback =
                 &nsHttpChannel::OnOfflineCacheEntryAvailable;
 
             rv = mCacheQuery->Dispatch();
@@ -2535,31 +2543,32 @@ nsHttpChannel::OnOfflineCacheEntryAvaila
 
 nsresult
 nsHttpChannel::OpenNormalCacheEntry(bool usingSSL)
 {
     NS_ASSERTION(!mCacheEntry, "We have already mCacheEntry");
 
     nsresult rv;
 
-    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
+    bool isPrivate = UsingPrivateBrowsing();
+    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy(isPrivate);
     nsDependentCString clientID(
-        GetCacheSessionNameForStoragePolicy(storagePolicy));
+        GetCacheSessionNameForStoragePolicy(storagePolicy, isPrivate));
 
     nsCAutoString cacheKey;
     GenerateCacheKey(mPostID, cacheKey);
 
     nsCacheAccessMode accessRequested;
     rv = DetermineCacheAccess(&accessRequested);
     if (NS_FAILED(rv))
         return rv;
  
     mCacheQuery = new HttpCacheQuery(
                                 this, clientID, storagePolicy,
-                                cacheKey,
+                                UsingPrivateBrowsing(), cacheKey,
                                 accessRequested,
                                 mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY,
                                 usingSSL, false);
 
     mOnCacheEntryAvailableCallback =
         &nsHttpChannel::OnNormalCacheEntryAvailable;
 
     rv = mCacheQuery->Dispatch();
@@ -2843,16 +2852,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);
         }
@@ -5832,44 +5844,51 @@ nsHttpChannel::DoInvalidateCacheEntry(co
 {
     // NOTE:
     // 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);
+    bool isPrivate = UsingPrivateBrowsing();
+    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy(isPrivate);
+    const char * clientID = GetCacheSessionNameForStoragePolicy(storagePolicy,
+                                                                isPrivate);
 
     LOG(("DoInvalidateCacheEntry [channel=%p session=%s policy=%d key=%s]",
          this, clientID, PRIntn(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(UsingPrivateBrowsing());
+    }
+    if (NS_SUCCEEDED(rv)) {
         rv = session->DoomEntry(key, nsnull);
     }
 
     LOG(("DoInvalidateCacheEntry [channel=%p session=%s policy=%d key=%s rv=%d]",
          this, clientID, PRIntn(storagePolicy), key.get(), PRIntn(rv)));
 }
 
 nsCacheStoragePolicy
-nsHttpChannel::DetermineStoragePolicy()
+nsHttpChannel::DetermineStoragePolicy(bool isPrivate)
 {
     nsCacheStoragePolicy policy = nsICache::STORE_ANYWHERE;
-    if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
+    if (isPrivate)
+        policy = nsICache::STORE_IN_MEMORY;
+    else if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
         policy = nsICache::STORE_IN_MEMORY;
 
     return policy;
 }
 
 nsresult
 nsHttpChannel::DetermineCacheAccess(nsCacheAccessMode *_retval)
 {
@@ -5890,11 +5909,12 @@ nsHttpChannel::DetermineCacheAccess(nsCa
 
     return NS_OK;
 }
 
 void
 nsHttpChannel::AsyncOnExamineCachedResponse()
 {
     gHttpHandler->OnExamineCachedResponse(this);
+
 }
 
 } } // namespace mozilla::net
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -140,16 +140,26 @@ public: /* internal necko use only */
              , mCacheKey(key)
         {}
 
         nsresult MarkAsForeign();
     };
 
     OfflineCacheEntryAsForeignMarker* GetOfflineCacheEntryAsForeignMarker();
 
+    /**
+     * Returns true if this channel is operating in private browsing mode,
+     * false otherwise.
+     */
+    bool UsingPrivateBrowsing() {
+        bool usingPB;
+        GetUsingPrivateBrowsing(&usingPB);
+        return usingPB;
+    }
+
 private:
     typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result);
 
     bool     RequestIsConditional();
     nsresult Connect();
     nsresult ContinueConnect();
     void     SpeculativeConnect();
     nsresult SetupTransaction();
@@ -218,17 +228,17 @@ private:
     void     UpdateInhibitPersistentCachingFlag();
     nsresult InitOfflineCacheEntry();
     nsresult AddCacheEntryHeaders(nsICacheEntryDescriptor *entry);
     nsresult StoreAuthorizationMetaData(nsICacheEntryDescriptor *entry);
     nsresult FinalizeCacheEntry();
     nsresult InstallCacheListener(PRUint32 offset = 0);
     nsresult InstallOfflineCacheListener();
     void     MaybeInvalidateCacheEntryForSubsequentGet();
-    nsCacheStoragePolicy DetermineStoragePolicy();
+    nsCacheStoragePolicy DetermineStoragePolicy(bool isPrivate);
     nsresult DetermineCacheAccess(nsCacheAccessMode *_retval);
     void     AsyncOnExamineCachedResponse();
 
     // Handle the bogus Content-Encoding Apache sometimes sends
     void ClearBogusContentEncodingIfNeeded();
 
     // byte range request specific methods
     nsresult ProcessPartialContent();
--- 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
@@ -99,17 +99,19 @@ public:
     PRInt32       Port() const           { return mPort; }
     nsProxyInfo  *ProxyInfo()            { return mProxyInfo; }
     bool          UsingHttpProxy() const { return mUsingHttpProxy; }
     bool          UsingSSL() const       { return mUsingSSL; }
     bool          UsingConnect() const   { return mUsingConnect; }
     PRInt32       DefaultPort() const    { return mUsingSSL ? NS_HTTPS_DEFAULT_PORT : NS_HTTP_DEFAULT_PORT; }
     void          SetAnonymous(bool anon)         
                                          { mHashKey.SetCharAt(anon ? 'A' : '.', 2); }
-    bool          GetAnonymous()         { return mHashKey.CharAt(2) == 'A'; }
+    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;
     PRInt32                mPort;
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -1056,25 +1056,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, nsnull, usingSSL);
     ci->SetAnonymous(false);
+    ci->SetPrivate(false);
     PipelineFeedbackInfo(ci, RedCorruptedContent, nsnull, 0);
 
-    ci = new nsHttpConnectionInfo(host, port, nsnull, usingSSL);
+    ci = ci->Clone();
+    ci->SetAnonymous(false);
+    ci->SetPrivate(true);
+    PipelineFeedbackInfo(ci, RedCorruptedContent, nsnull, 0);
+
+    ci = ci->Clone();
     ci->SetAnonymous(true);
+    ci->SetPrivate(false);
+    PipelineFeedbackInfo(ci, RedCorruptedContent, nsnull, 0);
+
+    ci = ci->Clone();
+    ci->SetAnonymous(true);
+    ci->SetPrivate(true);
     PipelineFeedbackInfo(ci, RedCorruptedContent, nsnull, 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
@@ -150,17 +150,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)
@@ -305,17 +304,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
@@ -414,33 +412,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 ",") != nsnull;
 }
 
-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;
     }
@@ -1593,24 +1574,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();
@@ -310,23 +306,16 @@ private:
     // the userpass field of the URL to obscure the actual origin server.
     PRUint8  mPhishyUserPassLength;
 
     PRUint8  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
     PRUint32                  mLastUniqueID;
--- a/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
+++ b/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
@@ -16,17 +16,18 @@ protocol PWyciwygChannel
 {
   manager PNecko;
 
 parent:
   __delete__();
 
   Init(URI uri);
   AsyncOpen(URI      originalURI,
-            PRUint32 loadFlags);
+            PRUint32 loadFlags,
+            bool     usingPrivateBrowsing);
 
   // methods corresponding to those of nsIWyciwygChannel
   WriteToCacheEntry(nsString data);
   CloseCacheEntry(nsresult reason);
   SetCharsetAndSource(PRInt32 source, nsCString charset);
   SetSecurityInfo(nsCString securityInfo);
   Cancel(nsresult status);
 
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
@@ -19,25 +19,26 @@ namespace net {
 
 NS_IMPL_ISUPPORTS3(WyciwygChannelChild,
                    nsIRequest,
                    nsIChannel,
                    nsIWyciwygChannel);
 
 
 WyciwygChannelChild::WyciwygChannelChild()
-  : mStatus(NS_OK)
+  : PrivateBrowsingConsumer(this)
+  , 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));
 }
@@ -556,17 +557,17 @@ WyciwygChannelChild::AsyncOpen(nsIStream
 
   mListener = aListener;
   mListenerContext = aContext;
   mIsPending = true;
 
   if (mLoadGroup)
     mLoadGroup->AddRequest(this, nsnull);
 
-  SendAsyncOpen(IPC::URI(mOriginalURI), mLoadFlags);
+  SendAsyncOpen(IPC::URI(mOriginalURI), mLoadFlags, UsePrivateBrowsing());
 
   mState = WCC_OPENED;
 
   return NS_OK;
 }
 
 
 //-----------------------------------------------------------------------------
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.h
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h
@@ -5,16 +5,17 @@
 #ifndef mozilla_net_WyciwygChannelChild_h
 #define mozilla_net_WyciwygChannelChild_h
 
 #include "mozilla/net/PWyciwygChannelChild.h"
 #include "mozilla/net/ChannelEventQueue.h"
 #include "nsIWyciwygChannel.h"
 #include "nsIChannel.h"
 #include "nsIProgressEventSink.h"
+#include "PrivateBrowsingConsumer.h"
 
 namespace mozilla {
 namespace net {
 
 // TODO: replace with IPDL states
 enum WyciwygChannelChildState {
   WCC_NEW,
   WCC_INIT,
@@ -29,16 +30,17 @@ enum WyciwygChannelChildState {
   WCC_ONWRITE,
   WCC_ONCLOSED
 };
 
 
 // Header file contents
 class WyciwygChannelChild : public PWyciwygChannelChild
                           , public nsIWyciwygChannel
+                          , public PrivateBrowsingConsumer
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUEST
   NS_DECL_NSICHANNEL
   NS_DECL_NSIWYCIWYGCHANNEL
 
   WyciwygChannelChild();
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
@@ -73,17 +73,18 @@ WyciwygChannelParent::RecvInit(const IPC
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   return true;
 }
 
 bool
 WyciwygChannelParent::RecvAsyncOpen(const IPC::URI& aOriginal,
-                                    const PRUint32& aLoadFlags)
+                                    const PRUint32& aLoadFlags,
+                                    const bool& aUsingPrivateBrowsing)
 {
   nsCOMPtr<nsIURI> original(aOriginal);
 
   LOG(("WyciwygChannelParent RecvAsyncOpen [this=%x]\n", this));
 
   if (!mChannel)
     return true;
 
@@ -92,16 +93,19 @@ WyciwygChannelParent::RecvAsyncOpen(cons
   rv = mChannel->SetOriginalURI(original);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   rv = mChannel->SetLoadFlags(aLoadFlags);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
+  static_cast<nsWyciwygChannel*>(mChannel.get())->
+    OverridePrivateBrowsing(aUsingPrivateBrowsing);
+
   rv = mChannel->AsyncOpen(this, nsnull);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   return true;
 }
 
 bool
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
@@ -23,17 +23,18 @@ public:
   NS_DECL_NSISTREAMLISTENER
 
   WyciwygChannelParent();
   virtual ~WyciwygChannelParent();
 
 protected:
   virtual bool RecvInit(const IPC::URI& uri);
   virtual bool RecvAsyncOpen(const IPC::URI& original,
-                             const PRUint32& loadFlags);
+                             const PRUint32& loadFlags,
+                             const bool& usingPrivateBrowsing);
   virtual bool RecvWriteToCacheEntry(const nsString& data);
   virtual bool RecvCloseCacheEntry(const nsresult& reason);
   virtual bool RecvSetCharsetAndSource(const PRInt32& source,
                                        const nsCString& charset);
   virtual bool RecvSetSecurityInfo(const nsCString& securityInfo);
   virtual bool RecvCancel(const nsresult& statusCode);
 
   virtual void ActorDestroy(ActorDestroyReason why);
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -74,20 +74,22 @@ public:
   }
 private:
   nsresult mReason;
 };
 
 
 // nsWyciwygChannel methods 
 nsWyciwygChannel::nsWyciwygChannel()
-  : mStatus(NS_OK),
+  : PrivateBrowsingConsumer(this),
+    mStatus(NS_OK),
     mIsPending(false),
     mCharsetAndSourceSet(false),
     mNeedToWriteCharset(false),
+    mPrivate(false),
     mCharsetSource(kCharsetUninitialized),
     mContentLength(-1),
     mLoadFlags(LOAD_NORMAL)
 {
 }
 
 nsWyciwygChannel::~nsWyciwygChannel() 
 {
@@ -389,16 +391,19 @@ NS_IMETHODIMP
 nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData)
 {
   // URIs not thread-safe, so get spec now in case we need it
   nsCAutoString spec;
   nsresult rv = mURI->GetAsciiSpec(spec);
   if (NS_FAILED(rv)) 
     return rv;
 
+  // UsePrivateBrowsing deals with non-threadsafe objects
+  mPrivate = UsePrivateBrowsing();
+
   return mCacheIOTarget->Dispatch(new nsWyciwygWriteEvent(this, aData, spec),
                                   NS_DISPATCH_NORMAL);
 }
 
 nsresult
 nsWyciwygChannel::WriteToCacheEntryInternal(const nsAString &aData, const nsACString& spec)
 {
   NS_ASSERTION(IsOnCacheIOThread(), "wrong thread");
@@ -658,28 +663,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 (mPrivate || 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 = mPrivate ? "wyciwyg-private" : "wyciwyg";
+  rv = cacheService->CreateSession(sessionName, storagePolicy, true,
                                    getter_AddRefs(cacheSession));
   if (!cacheSession) 
     return NS_ERROR_FAILURE;
 
+  cacheSession->SetIsPrivate(mPrivate);
+
   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
@@ -19,24 +19,26 @@
 #include "nsIInputStreamPump.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIProgressEventSink.h"
 #include "nsIStreamListener.h"
 #include "nsICacheListener.h"
 #include "nsICacheEntryDescriptor.h"
 #include "nsIURI.h"
 #include "nsIEventTarget.h"
+#include "PrivateBrowsingConsumer.h"
 
 extern PRLogModuleInfo * gWyciwygLog;
 
 //-----------------------------------------------------------------------------
 
 class nsWyciwygChannel: public nsIWyciwygChannel,
                         public nsIStreamListener,
-                        public nsICacheListener
+                        public nsICacheListener,
+                        public mozilla::net::PrivateBrowsingConsumer
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIREQUEST
     NS_DECL_NSICHANNEL
     NS_DECL_NSIWYCIWYGCHANNEL
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
@@ -65,16 +67,17 @@ protected:
 
     void NotifyListener();
     bool IsOnCacheIOThread();
 
     nsresult                            mStatus;
     bool                                mIsPending;
     bool                                mCharsetAndSourceSet;
     bool                                mNeedToWriteCharset;
+    bool                                mPrivate;
     PRInt32                             mCharsetSource;
     nsCString                           mCharset;
     PRInt32                             mContentLength;
     PRUint32                            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
@@ -1123,16 +1123,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)
  */
 
@@ -1245,16 +1251,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;