Bug 775119 - e10s: implement nsILoadContext in ParentChannels, remove PrivateBrowsingConsumer r=jdm
authorJason Duell <jduell.mcbugs@gmail.com>
Sun, 22 Jul 2012 15:35:33 -0700
changeset 105548 84d63b0129ba891c2dc03f22802ee62e869c349c
parent 105547 d12d918df9d622f3496065608a1815772a2d0df0
child 105549 c6a54c7607ca879c1e72da094ec0cc9cdd31a661
push id1490
push userakeybl@mozilla.com
push dateMon, 08 Oct 2012 18:29:50 +0000
treeherdermozilla-beta@f335e7dacdc1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
bugs775119
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 775119 - e10s: implement nsILoadContext in ParentChannels, remove PrivateBrowsingConsumer r=jdm
netwerk/base/public/Makefile.in
netwerk/base/public/nsIPrivateBrowsingConsumer.idl
netwerk/base/public/nsNetUtil.h
netwerk/base/src/PrivateBrowsingConsumer.h
netwerk/base/src/nsBaseChannel.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/websocket/PWebSocket.ipdl
netwerk/protocol/websocket/WebSocketChannelChild.cpp
netwerk/protocol/websocket/WebSocketChannelParent.cpp
netwerk/protocol/websocket/WebSocketChannelParent.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_cacheflags.js
netwerk/test/unit_ipc/test_cacheflags_wrap.js
netwerk/test/unit_ipc/xpcshell.ini
uriloader/exthandler/nsExternalHelperAppService.cpp
--- a/netwerk/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -53,17 +53,16 @@ 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 \
deleted file mode 100644
--- a/netwerk/base/public/nsIPrivateBrowsingConsumer.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-/* 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;
-  }
-%}
-};
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -69,16 +69,17 @@
 #include "nsIWritablePropertyBag2.h"
 #include "nsIIDNService.h"
 #include "nsIChannelEventSink.h"
 #include "nsIChannelPolicy.h"
 #include "nsISocketProviderService.h"
 #include "nsISocketProvider.h"
 #include "nsIRedirectChannelRegistrar.h"
 #include "nsIMIMEHeaderParam.h"
+#include "nsILoadContext.h"
 #include "mozilla/Services.h"
 
 #ifdef MOZILLA_INTERNAL_API
 
 inline already_AddRefed<nsIIOService>
 do_GetIOService(nsresult* error = 0)
 {
     already_AddRefed<nsIIOService> ret = mozilla::services::GetIOService();
@@ -1292,16 +1293,31 @@ NS_QueryNotificationCallbacks(nsIInterfa
             loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
             if (cbs)
                 cbs->GetInterface(iid, result);
         }
     }
 }
 
 /**
+ * Returns true if channel is using Private Browsing, or false if not.
+ *
+ * Note: you may get a false negative if you call this before AsyncOpen has been
+ * called (technically, before the channel's notificationCallbacks are set: this
+ * is almost always done before AsyncOpen).
+ */
+inline bool
+NS_UsePrivateBrowsing(nsIChannel *channel)
+{
+  nsCOMPtr<nsILoadContext> loadContext;
+  NS_QueryNotificationCallbacks(channel, loadContext);
+  return loadContext && loadContext->UsePrivateBrowsing();
+}
+
+/**
  * Wraps an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2. This
  * method is provided mainly for use by other methods in this file.
  *
  * *aAuthPrompt2 should be set to null before calling this function.
  */
 inline void
 NS_WrapAuthPrompt(nsIAuthPrompt *aAuthPrompt, nsIAuthPrompt2** aAuthPrompt2)
 {
deleted file mode 100644
--- a/netwerk/base/src/PrivateBrowsingConsumer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* 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/base/src/nsBaseChannel.h
+++ b/netwerk/base/src/nsBaseChannel.h
@@ -240,17 +240,16 @@ private:
 
   private:
     nsRefPtr<nsBaseChannel> mChannel;
     nsCOMPtr<nsIChannel> mNewChannel;
   };
   friend class RedirectRunnable;
 
   nsRefPtr<nsInputStreamPump>         mPump;
-  nsCOMPtr<nsIInterfaceRequestor>     mCallbacks;
   nsCOMPtr<nsIProgressEventSink>      mProgressSink;
   nsCOMPtr<nsIURI>                    mOriginalURI;
   nsCOMPtr<nsIURI>                    mURI;
   nsCOMPtr<nsISupports>               mOwner;
   nsCOMPtr<nsISupports>               mSecurityInfo;
   nsCOMPtr<nsIChannel>                mRedirectChannel;
   nsCString                           mContentType;
   nsCString                           mContentCharset;
@@ -259,14 +258,15 @@ private:
   bool                                mSynthProgressEvents;
   bool                                mWasOpened;
   bool                                mWaitingOnAsyncRedirect;
   bool                                mOpenRedirectChannel;
   PRUint32                            mRedirectFlags;
 
 protected:
   nsCOMPtr<nsILoadGroup>              mLoadGroup;
+  nsCOMPtr<nsIInterfaceRequestor>     mCallbacks;
   nsCOMPtr<nsIStreamListener>         mListener;
   nsCOMPtr<nsISupports>               mListenerContext;
   nsresult                            mStatus;
 };
 
 #endif // !nsBaseChannel_h__
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -8,28 +8,28 @@
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/net/FTPChannelChild.h"
 #include "nsFtpProtocolHandler.h"
 
 #include "nsStringStream.h"
 #include "nsMimeTypes.h"
 #include "nsNetUtil.h"
 #include "nsIURIFixup.h"
+#include "nsILoadContext.h"
 #include "nsCDefaultURIFixup.h"
 #include "base/compiler_specific.h"
 
 #undef LOG
 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
 
 namespace mozilla {
 namespace net {
 
 FTPChannelChild::FTPChannelChild(nsIURI* uri)
-: PrivateBrowsingConsumer(this)
-, mIPCOpen(false)
+: 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,18 +155,33 @@ FTPChannelChild::AsyncOpen(::nsIStreamLi
   gNeckoChild->SendPFTPChannelConstructor(this);
   mListener = listener;
   mListenerContext = aContext;
 
   // add ourselves to the load group. 
   if (mLoadGroup)
     mLoadGroup->AddRequest(this, nsnull);
 
+  // Get info from nsILoadContext, if any
+  bool haveLoadContext = false;
+  bool isContent = false;
+  bool usePrivateBrowsing = false;
+  nsCOMPtr<nsILoadContext> loadContext;
+  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
+                                NS_GET_IID(nsILoadContext),
+                                getter_AddRefs(loadContext));
+  if (loadContext) {
+    haveLoadContext = true;
+    loadContext->GetIsContent(&isContent);
+    loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
+  }
+
   SendAsyncOpen(nsBaseChannel::URI(), mStartPos, mEntityID,
-                IPC::InputStream(mUploadStream), UsePrivateBrowsing());
+                IPC::InputStream(mUploadStream), haveLoadContext, isContent, 
+                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,17 +11,16 @@
 #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
@@ -30,17 +29,16 @@ 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
@@ -14,17 +14,20 @@
 
 #undef LOG
 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
 
 namespace mozilla {
 namespace net {
 
 FTPChannelParent::FTPChannelParent()
-: mIPCClosed(false)
+  : mIPCClosed(false)
+  , mHaveLoadContext(false)
+  , mIsContent(false)
+  , mUsePrivateBrowsing(false)
 {
   nsIProtocolHandler* handler;
   CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &handler);
   NS_ASSERTION(handler, "no ftp handler");
 }
 
 FTPChannelParent::~FTPChannelParent()
 {
@@ -38,32 +41,35 @@ FTPChannelParent::ActorDestroy(ActorDest
   // yet, but we must not send any more msgs to child.
   mIPCClosed = true;
 }
 
 //-----------------------------------------------------------------------------
 // FTPChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS4(FTPChannelParent,
+NS_IMPL_ISUPPORTS5(FTPChannelParent,
                    nsIStreamListener,
                    nsIParentChannel,
                    nsIInterfaceRequestor,
+                   nsILoadContext,
                    nsIRequestObserver);
 
 //-----------------------------------------------------------------------------
 // FTPChannelParent::PFTPChannelParent
 //-----------------------------------------------------------------------------
 
 bool
 FTPChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
                                 const PRUint64& aStartPos,
                                 const nsCString& aEntityID,
                                 const IPC::InputStream& aUploadStream,
-                                const bool& aUsePrivateBrowsing)
+                                const bool& haveLoadContext,
+                                const bool& isContent,
+                                const bool& usePrivateBrowsing)
 {
   nsCOMPtr<nsIURI> uri(aURI);
 
 #ifdef DEBUG
   nsCString uriSpec;
   uri->GetSpec(uriSpec);
   LOG(("FTPChannelParent RecvAsyncOpen [this=%x uri=%s]\n",
        this, uriSpec.get()));
@@ -88,17 +94,21 @@ 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);
+  // fields needed to impersonate nsILoadContext
+  mHaveLoadContext = haveLoadContext;
+  mIsContent = isContent;
+  mUsePrivateBrowsing = usePrivateBrowsing;
+  mChannel->SetNotificationCallbacks(this);
 
   rv = mChannel->AsyncOpen(this, nsnull);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
   
   return true;
 }
 
@@ -224,14 +234,70 @@ FTPChannelParent::Delete()
 
 //-----------------------------------------------------------------------------
 // FTPChannelParent::nsIInterfaceRequestor
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 FTPChannelParent::GetInterface(const nsIID& uuid, void** result)
 {
+  // Only support nsILoadContext if child channel's callbacks did too
+  if (uuid.Equals(NS_GET_IID(nsILoadContext)) && !mHaveLoadContext) {
+    return NS_NOINTERFACE;
+  }
+
   return QueryInterface(uuid, result);
 }
 
+//-----------------------------------------------------------------------------
+// FTPChannelParent::nsILoadContext
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+FTPChannelParent::GetAssociatedWindow(nsIDOMWindow**)
+{
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+FTPChannelParent::GetTopWindow(nsIDOMWindow**)
+{
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+FTPChannelParent::IsAppOfType(PRUint32, bool*)
+{
+  // don't expect we need this in parent (Thunderbird/SeaMonkey specific?)
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+FTPChannelParent::GetIsContent(bool *aIsContent)
+{
+  NS_ENSURE_ARG_POINTER(aIsContent);
+
+  *aIsContent = mIsContent;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelParent::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
+{
+  NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
+
+  *aUsePrivateBrowsing = mUsePrivateBrowsing;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelParent::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
+{
+  // We shouldn't need this on parent...
+  return NS_ERROR_UNEXPECTED;
+}
+
+
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/ftp/FTPChannelParent.h
+++ b/netwerk/protocol/ftp/FTPChannelParent.h
@@ -7,50 +7,60 @@
 
 #ifndef mozilla_net_FTPChannelParent_h
 #define mozilla_net_FTPChannelParent_h
 
 #include "mozilla/net/PFTPChannelParent.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "nsIParentChannel.h"
 #include "nsIInterfaceRequestor.h"
+#include "nsILoadContext.h"
 
 class nsFtpChannel;
 
 namespace mozilla {
 namespace net {
 
 class FTPChannelParent : public PFTPChannelParent
                        , public nsIParentChannel
                        , public nsIInterfaceRequestor
+                       , public nsILoadContext
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIPARENTCHANNEL
   NS_DECL_NSIINTERFACEREQUESTOR
+  NS_DECL_NSILOADCONTEXT
 
   FTPChannelParent();
   virtual ~FTPChannelParent();
 
 protected:
   NS_OVERRIDE virtual bool RecvAsyncOpen(const IPC::URI& uri,
                                          const PRUint64& startPos,
                                          const nsCString& entityID,
                                          const IPC::InputStream& uploadStream,
+                                         const bool& haveLoadContext,
+                                         const bool& isContent,
                                          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;
 
   bool mIPCClosed;
+
+  // fields for impersonating nsILoadContext
+  bool mHaveLoadContext       : 1;
+  bool mIsContent             : 1;
+  bool mUsePrivateBrowsing    : 1;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_FTPChannelParent_h
--- a/netwerk/protocol/ftp/PFTPChannel.ipdl
+++ b/netwerk/protocol/ftp/PFTPChannel.ipdl
@@ -18,18 +18,23 @@ namespace net {
 
 async protocol PFTPChannel
 {
   manager PNecko;
 
 parent:
   __delete__();
 
-  AsyncOpen(URI uri, PRUint64 startPos, nsCString entityID,
-            InputStream uploadStream, bool usePrivateBrowsing);
+  AsyncOpen(URI uri,
+            PRUint64 startPos,
+            nsCString entityID,
+            InputStream uploadStream,
+            bool haveLoadContext,
+            bool isContent,
+            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,34 +23,32 @@
 #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"
+#include "nsNetUtil.h"
 
 class nsFtpChannel : public nsBaseChannel,
                      public nsIFTPChannel,
                      public nsIUploadChannel,
                      public nsIResumableChannel,
-                     public nsIProxiedChannel,
-                     public mozilla::net::PrivateBrowsingConsumer
+                     public nsIProxiedChannel
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIUPLOADCHANNEL
     NS_DECL_NSIRESUMABLECHANNEL
     NS_DECL_NSIPROXIEDCHANNEL
     
     nsFtpChannel(nsIURI *uri, nsIProxyInfo *pi)
-        : mozilla::net::PrivateBrowsingConsumer(this)
-        , mProxyInfo(pi)
+        : 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,17 +2212,17 @@ 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();
+    bool isPrivate = NS_UsePrivateBrowsing(mChannel);
     const char* sessionName = isPrivate ? "FTP-private" : "FTP";
     nsCacheStoragePolicy policy =
         isPrivate ? nsICache::STORE_IN_MEMORY : nsICache::STORE_ANYWHERE;
     nsCOMPtr<nsICacheSession> session;
     cache->CreateSession(sessionName,
                          policy,
                          nsICache::STREAM_BASED,
                          getter_AddRefs(session));
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -22,18 +22,17 @@
 #include "nsStreamListenerWrapper.h"
 
 #include "prnetdb.h"
 
 namespace mozilla {
 namespace net {
 
 HttpBaseChannel::HttpBaseChannel()
-  : PrivateBrowsingConsumer(this)
-  , mStartPos(LL_MAXUINT)
+  : mStartPos(LL_MAXUINT)
   , mStatus(NS_OK)
   , mLoadFlags(LOAD_NORMAL)
   , mPriority(PRIORITY_NORMAL)
   , mCaps(0)
   , mRedirectionLimit(gHttpHandler->RedirectionLimit())
   , mApplyConversion(true)
   , mCanceled(false)
   , mIsPending(false)
@@ -44,16 +43,17 @@ HttpBaseChannel::HttpBaseChannel()
   , mUploadStreamHasHeaders(false)
   , mInheritApplicationCache(true)
   , mChooseApplicationCache(false)
   , mLoadedFromApplicationCache(false)
   , mChannelIsForDownload(false)
   , mTracingEnabled(true)
   , mTimingEnabled(false)
   , mAllowSpdy(true)
+  , mPrivateBrowsing(false)
   , mSuspendCount(0)
 {
   LOG(("Creating HttpBaseChannel @%x\n", this));
 
   // grab a reference to the handler to ensure that it doesn't go away.
   NS_ADDREF(gHttpHandler);
 
   // Subfields of unions cannot be targeted in an initializer list
@@ -135,28 +135,27 @@ HttpBaseChannel::Init(nsIURI *aURI,
 
   return rv;
 }
 
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS_INHERITED10(HttpBaseChannel,
-                              nsHashPropertyBag, 
+NS_IMPL_ISUPPORTS_INHERITED9( HttpBaseChannel,
+                              nsHashPropertyBag,
                               nsIRequest,
                               nsIChannel,
                               nsIEncodedChannel,
                               nsIHttpChannel,
                               nsIHttpChannelInternal,
                               nsIUploadChannel,
                               nsIUploadChannel2,
                               nsISupportsPriority,
-                              nsITraceableChannel,
-                              nsIPrivateBrowsingConsumer)
+                              nsITraceableChannel)
 
 //-----------------------------------------------------------------------------
 // HttpBaseChannel::nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpBaseChannel::GetName(nsACString& aName)
 {
@@ -268,16 +267,19 @@ HttpBaseChannel::GetNotificationCallback
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
 {
   mCallbacks = aCallbacks;
   mProgressSink = nsnull;
+
+  // Will never change unless SetNotificationCallbacks called again, so cache
+  mPrivateBrowsing = NS_UsePrivateBrowsing(this);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::GetContentType(nsACString& aContentType)
 {
   if (!mResponseHead) {
     aContentType.Truncate();
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -22,18 +22,18 @@
 #include "nsIUploadChannel2.h"
 #include "nsIProgressEventSink.h"
 #include "nsIURI.h"
 #include "nsIStringEnumerator.h"
 #include "nsISupportsPriority.h"
 #include "nsIApplicationCache.h"
 #include "nsIResumableChannel.h"
 #include "nsITraceableChannel.h"
+#include "nsILoadContext.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. 
@@ -45,17 +45,16 @@ 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();
@@ -181,17 +180,17 @@ public:
 
     const PRNetAddr& GetSelfAddr() { return mSelfAddr; }
     const PRNetAddr& GetPeerAddr() { return mPeerAddr; }
 
 public: /* Necko internal use only... */
 
   bool ShouldRewriteRedirectToGET(PRUint32 httpStatus, nsHttpAtom method);
   bool IsSafeMethod(nsHttpAtom method);
-  
+
 protected:
 
   // Handle notifying listener, removing from loadgroup if request failed.
   void     DoNotifyListener();
   virtual void DoNotifyListenerCleanup() = 0;
 
   nsresult ApplyContentConversions();
 
@@ -260,16 +259,17 @@ protected:
   PRUint32                          mInheritApplicationCache    : 1;
   PRUint32                          mChooseApplicationCache     : 1;
   PRUint32                          mLoadedFromApplicationCache : 1;
   PRUint32                          mChannelIsForDownload       : 1;
   PRUint32                          mTracingEnabled             : 1;
   // True if timing collection is enabled
   PRUint32                          mTimingEnabled              : 1;
   PRUint32                          mAllowSpdy                  : 1;
+  PRUint32                          mPrivateBrowsing            : 1;
 
   // Current suspension depth for this channel object
   PRUint32                          mSuspendCount;
 
   nsAutoPtr<nsTArray<nsCString> >   mRedirectedCachekeys;
 };
 
 // Share some code while working around C++'s absurd inability to handle casting
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1010,16 +1010,28 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
       nsCOMPtr<nsIApplicationCache> appCache;
       rv = appCacheContainer->GetApplicationCache(getter_AddRefs(appCache));
       if (NS_SUCCEEDED(rv) && appCache) {
         appCache->GetClientID(appCacheClientId);
       }
     }
   }
 
+  // Get info from nsILoadContext, if any
+  bool haveLoadContext = false;
+  bool isContent = false;
+  bool usePrivateBrowsing = false;
+  nsCOMPtr<nsILoadContext> loadContext;
+  GetCallback(loadContext);
+  if (loadContext) {
+    haveLoadContext = true;
+    loadContext->GetIsContent(&isContent);
+    loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
+  }
+
   //
   // Send request to the chrome process...
   //
 
   // FIXME: bug 558623: Combine constructor and SendAsyncOpen into one IPC msg
 
   mozilla::dom::TabChild* tabChild = nsnull;
   nsCOMPtr<nsITabChild> iTabChild;
@@ -1035,18 +1047,19 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
   gNeckoChild->SendPHttpChannelConstructor(this, tabChild);
 
   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, UsePrivateBrowsing());
+                mStartPos, mEntityID, mChooseApplicationCache,
+                appCacheClientId, mAllowSpdy, haveLoadContext, isContent,
+                usePrivateBrowsing);
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIHttpChannel
 //-----------------------------------------------------------------------------
 
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -30,16 +30,19 @@ namespace net {
 HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding)
   : mIPCClosed(false)
   , mStoredStatus(0)
   , mStoredProgress(0)
   , mStoredProgressMax(0)
   , mSentRedirect1Begin(false)
   , mSentRedirect1BeginFailed(false)
   , mReceivedRedirect2Verify(false)
+  , mHaveLoadContext(false)
+  , mIsContent(false)
+  , mUsePrivateBrowsing(false)
 {
   // Ensure gHttpHandler is initialized: we need the atom table up and running.
   nsIHttpProtocolHandler* handler;
   CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &handler);
   NS_ASSERTION(handler, "no http handler");
 
   mTabParent = do_QueryObject(static_cast<TabParent*>(iframeEmbedding));
 }
@@ -57,17 +60,18 @@ HttpChannelParent::ActorDestroy(ActorDes
   // to child, or IPDL will kill chrome process, too.
   mIPCClosed = true;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS6(HttpChannelParent,
+NS_IMPL_ISUPPORTS7(HttpChannelParent,
+                   nsILoadContext,
                    nsIInterfaceRequestor,
                    nsIProgressEventSink,
                    nsIRequestObserver,
                    nsIStreamListener,
                    nsIParentChannel,
                    nsIParentRedirectingChannel)
 
 //-----------------------------------------------------------------------------
@@ -80,16 +84,21 @@ HttpChannelParent::GetInterface(const ns
   if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
       aIID.Equals(NS_GET_IID(nsISecureBrowserUI))) {
     if (!mTabParent)
       return NS_NOINTERFACE;
 
     return mTabParent->QueryInterface(aIID, result);
   }
 
+  // Only support nsILoadContext if child channel's callbacks did too
+  if (aIID.Equals(NS_GET_IID(nsILoadContext)) && !mHaveLoadContext) {
+    return NS_NOINTERFACE;
+  }
+
   return QueryInterface(aIID, result);
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::PHttpChannelParent
 //-----------------------------------------------------------------------------
 
 bool 
@@ -107,17 +116,19 @@ HttpChannelParent::RecvAsyncOpen(const I
                                  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&                usingPrivateBrowsing)
+                                 const bool&                haveLoadContext,
+                                 const bool&                isContent,
+                                 const bool&                usePrivateBrowsing)
 {
   nsCOMPtr<nsIURI> uri(aURI);
   nsCOMPtr<nsIURI> originalUri(aOriginalURI);
   nsCOMPtr<nsIURI> docUri(aDocURI);
   nsCOMPtr<nsIURI> referrerUri(aReferrerURI);
 
   nsCString uriSpec;
   uri->GetSpec(uriSpec);
@@ -129,16 +140,21 @@ HttpChannelParent::RecvAsyncOpen(const I
   nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
 
   rv = NS_NewChannel(getter_AddRefs(mChannel), uri, ios, nsnull, nsnull, loadFlags);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
 
+  // fields needed to impersonate nsILoadContext
+  mHaveLoadContext = haveLoadContext;
+  mIsContent = isContent;
+  mUsePrivateBrowsing = usePrivateBrowsing;
+
   nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
 
   if (doResumeAt)
     httpChan->ResumeAt(startPos, entityID);
 
   if (originalUri)
     httpChan->SetOriginalURI(originalUri);
   if (docUri)
@@ -204,18 +220,16 @@ 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
@@ -581,9 +595,60 @@ HttpChannelParent::CompleteRedirect(bool
     // TODO: check return value: assume child dead if failed
     unused << SendRedirect3Complete();
   }
 
   mRedirectChannel = nsnull;
   return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// HttpChannelParent::nsILoadContext
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpChannelParent::GetAssociatedWindow(nsIDOMWindow**)
+{
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+HttpChannelParent::GetTopWindow(nsIDOMWindow**)
+{
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+HttpChannelParent::IsAppOfType(PRUint32, bool*)
+{
+  // don't expect we need this in parent (Thunderbird/SeaMonkey specific?)
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+HttpChannelParent::GetIsContent(bool *aIsContent)
+{
+  NS_ENSURE_ARG_POINTER(aIsContent);
+
+  *aIsContent = mIsContent;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpChannelParent::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
+{
+  NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
+
+  *aUsePrivateBrowsing = mUsePrivateBrowsing;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpChannelParent::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
+{
+  // We shouldn't need this on parent...
+  return NS_ERROR_UNEXPECTED;
+}
+
+
 }} // mozilla::net
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -26,25 +26,27 @@ namespace mozilla {
 namespace net {
 
 class HttpChannelParentListener;
 
 class HttpChannelParent : public PHttpChannelParent
                         , public nsIParentRedirectingChannel
                         , public nsIProgressEventSink
                         , public nsIInterfaceRequestor
+                        , public nsILoadContext
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIPARENTCHANNEL
   NS_DECL_NSIPARENTREDIRECTINGCHANNEL
   NS_DECL_NSIPROGRESSEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
+  NS_DECL_NSILOADCONTEXT
 
   HttpChannelParent(PBrowserParent* iframeEmbedding);
   virtual ~HttpChannelParent();
 
 protected:
   virtual bool RecvAsyncOpen(const IPC::URI&            uri,
                              const IPC::URI&            originalUri,
                              const IPC::URI&            docUri,
@@ -59,16 +61,18 @@ protected:
                              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 &               haveLoadContext,
+                             const bool &               isContent,
                              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);
@@ -102,14 +106,19 @@ private:
   // into one IPDL call to child.
   nsresult mStoredStatus;
   PRUint64 mStoredProgress;
   PRUint64 mStoredProgressMax;
 
   bool mSentRedirect1Begin : 1;
   bool mSentRedirect1BeginFailed : 1;
   bool mReceivedRedirect2Verify : 1;
+
+  // fields for impersonating nsILoadContext
+  bool mHaveLoadContext : 1;
+  bool mIsContent : 1;
+  bool mUsePrivateBrowsing : 1;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -45,16 +45,20 @@ parent:
             bool                allowPipelining,
             bool                forceAllowThirdPartyCookie,
             bool                resumeAt,
             PRUint64            startPos,
             nsCString           entityID,
             bool                chooseApplicationCache,
             nsCString           appCacheClientID,
             bool                allowSpdy,
+            // If child channel callbacks implement nsILoadContext, we implement
+            // it in HttpChannelParent too
+            bool                haveLoadContext,
+            bool                isContent,
             bool                usePrivateBrowsing);
 
   // Used to connect redirected-to channel on the parent with redirected-to
   // channel on the child.
   ConnectChannel(PRUint32 channelId);
 
   SetPriority(PRUint16 priority);
 
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -539,17 +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());
+    mConnectionInfo->SetPrivate(mPrivateBrowsing);
     gHttpHandler->SpeculativeConnect(mConnectionInfo,
                                      callbacks, NS_GetCurrentThread());
 }
 
 void
 nsHttpChannel::DoNotifyListenerCleanup()
 {
     // We don't need this info anymore
@@ -834,17 +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());
+    mConnectionInfo->SetPrivate(mPrivateBrowsing);
 
     if (mUpgradeProtocolCallback) {
         mRequestHead.SetHeader(nsHttp::Upgrade, mUpgradeProtocol, false);
         mRequestHead.SetHeader(nsHttp::Connection,
                                nsDependentCString(nsHttp::Upgrade.get()),
                                true);
         mCaps |=  NS_HTTP_STICKY_CONNECTION;
         mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
@@ -2442,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, UsingPrivateBrowsing(),
+                                nsICache::STORE_OFFLINE, mPrivateBrowsing,
                                 cacheKey, nsICache::ACCESS_READ,
                                 mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY,
                                 usingSSL, true);
 
             mOnCacheEntryAvailableCallback =
                 &nsHttpChannel::OnOfflineCacheEntryAvailable;
 
             rv = mCacheQuery->Dispatch();
@@ -2543,33 +2543,31 @@ nsHttpChannel::OnOfflineCacheEntryAvaila
 
 nsresult
 nsHttpChannel::OpenNormalCacheEntry(bool usingSSL)
 {
     NS_ASSERTION(!mCacheEntry, "We have already mCacheEntry");
 
     nsresult rv;
 
-    bool isPrivate = UsingPrivateBrowsing();
-    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy(isPrivate);
+    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
     nsDependentCString clientID(
-        GetCacheSessionNameForStoragePolicy(storagePolicy, isPrivate));
+        GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing));
 
     nsCAutoString cacheKey;
     GenerateCacheKey(mPostID, cacheKey);
 
     nsCacheAccessMode accessRequested;
     rv = DetermineCacheAccess(&accessRequested);
     if (NS_FAILED(rv))
         return rv;
  
     mCacheQuery = new HttpCacheQuery(
                                 this, clientID, storagePolicy,
-                                UsingPrivateBrowsing(), cacheKey,
-                                accessRequested,
+                                mPrivateBrowsing, cacheKey, accessRequested,
                                 mLoadFlags & LOAD_BYPASS_LOCAL_CACHE_IF_BUSY,
                                 usingSSL, false);
 
     mOnCacheEntryAvailableCallback =
         &nsHttpChannel::OnNormalCacheEntryAvailable;
 
     rv = mCacheQuery->Dispatch();
     if (NS_SUCCEEDED(rv))
@@ -5868,49 +5866,48 @@ 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
-    bool isPrivate = UsingPrivateBrowsing();
-    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy(isPrivate);
-    const char * clientID = GetCacheSessionNameForStoragePolicy(storagePolicy,
-                                                                isPrivate);
+    nsCacheStoragePolicy storagePolicy = DetermineStoragePolicy();
+    const char * clientID =
+        GetCacheSessionNameForStoragePolicy(storagePolicy, mPrivateBrowsing);
 
     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());
+        rv = session->SetIsPrivate(mPrivateBrowsing);
     }
     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(bool isPrivate)
+nsHttpChannel::DetermineStoragePolicy()
 {
     nsCacheStoragePolicy policy = nsICache::STORE_ANYWHERE;
-    if (isPrivate)
+    if (mPrivateBrowsing)
         policy = nsICache::STORE_IN_MEMORY;
     else if (mLoadFlags & INHIBIT_PERSISTENT_CACHING)
         policy = nsICache::STORE_IN_MEMORY;
 
     return policy;
 }
 
 nsresult
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -140,26 +140,16 @@ 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();
@@ -230,17 +220,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(bool isPrivate);
+    nsCacheStoragePolicy DetermineStoragePolicy();
     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/websocket/PWebSocket.ipdl
+++ b/netwerk/protocol/websocket/PWebSocket.ipdl
@@ -17,17 +17,23 @@ namespace mozilla {
 namespace net {
 
 async protocol PWebSocket
 {
   manager PNecko;
 
 parent:
   // Forwarded methods corresponding to methods on nsIWebSocketChannel
-  AsyncOpen(URI aURI, nsCString aOrigin, nsCString aProtocol, bool aSecure);
+  AsyncOpen(URI aURI,
+            nsCString aOrigin,
+            nsCString aProtocol,
+            bool aSecure,
+            bool haveLoadContext,
+            bool isContent,
+            bool usingPrivateBrowsing);
   Close(PRUint16 code, nsCString reason);
   SendMsg(nsCString aMsg);
   SendBinaryMsg(nsCString aMsg);
   SendBinaryStream(InputStream aStream, PRUint32 aLength);
 
   DeleteSelf();
 
 child:
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -4,16 +4,18 @@
  * 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 "WebSocketLog.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "WebSocketChannelChild.h"
 #include "nsITabChild.h"
+#include "nsILoadContext.h"
+#include "nsNetUtil.h"
 
 namespace mozilla {
 namespace net {
 
 NS_IMPL_ADDREF(WebSocketChannelChild)
 
 NS_IMETHODIMP_(nsrefcnt) WebSocketChannelChild::Release()
 {
@@ -321,21 +323,36 @@ WebSocketChannelChild::AsyncOpen(nsIURI 
   nsCOMPtr<nsITabChild> iTabChild;
   NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
                                 NS_GET_IID(nsITabChild),
                                 getter_AddRefs(iTabChild));
   if (iTabChild) {
     tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
   }
 
+  // Get info from nsILoadContext, if any
+  bool haveLoadContext = false;
+  bool isContent = false;
+  bool usePrivateBrowsing = false;
+  nsCOMPtr<nsILoadContext> loadContext;
+  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
+                                NS_GET_IID(nsILoadContext),
+                                getter_AddRefs(loadContext));
+  if (loadContext) {
+    haveLoadContext = true;
+    loadContext->GetIsContent(&isContent);
+    loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
+  }
+
   // Corresponding release in DeallocPWebSocket
   AddIPDLReference();
 
   gNeckoChild->SendPWebSocketConstructor(this, tabChild);
-  if (!SendAsyncOpen(aURI, nsCString(aOrigin), mProtocol, mEncrypted))
+  if (!SendAsyncOpen(aURI, nsCString(aOrigin), mProtocol, mEncrypted,
+                     haveLoadContext, isContent, usePrivateBrowsing))
     return NS_ERROR_UNEXPECTED;
 
   mOriginalURI = aURI;
   mURI = mOriginalURI;
   mListener = aListener;
   mContext = aContext;
   mOrigin = aOrigin;
 
--- a/netwerk/protocol/websocket/WebSocketChannelParent.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp
@@ -6,57 +6,72 @@
 
 #include "WebSocketLog.h"
 #include "WebSocketChannelParent.h"
 #include "nsIAuthPromptProvider.h"
 
 namespace mozilla {
 namespace net {
 
-NS_IMPL_THREADSAFE_ISUPPORTS2(WebSocketChannelParent,
+NS_IMPL_THREADSAFE_ISUPPORTS3(WebSocketChannelParent,
                               nsIWebSocketListener,
+                              nsILoadContext,
                               nsIInterfaceRequestor)
 
 WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider)
   : mAuthProvider(aAuthProvider)
   , mIPCOpen(true)
+  , mHaveLoadContext(false)
+  , mIsContent(false)
+  , mUsePrivateBrowsing(false)
 {
 #if defined(PR_LOGGING)
   if (!webSocketLog)
     webSocketLog = PR_NewLogModule("nsWebSocket");
 #endif
 }
 
+//-----------------------------------------------------------------------------
+// WebSocketChannelParent::PWebSocketChannelParent
+//-----------------------------------------------------------------------------
+
 bool
 WebSocketChannelParent::RecvDeleteSelf()
 {
   LOG(("WebSocketChannelParent::RecvDeleteSelf() %p\n", this));
   mChannel = nsnull;
   mAuthProvider = nsnull;
   return mIPCOpen ? Send__delete__(this) : true;
 }
 
 bool
 WebSocketChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
                                       const nsCString& aOrigin,
                                       const nsCString& aProtocol,
-                                      const bool& aSecure)
+                                      const bool& aSecure,
+                                      const bool& haveLoadContext,
+                                      const bool& isContent,
+                                      const bool& usePrivateBrowsing)
 {
   LOG(("WebSocketChannelParent::RecvAsyncOpen() %p\n", this));
   nsresult rv;
   if (aSecure) {
     mChannel =
       do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
   } else {
     mChannel =
       do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
   }
   if (NS_FAILED(rv))
     goto fail;
 
+  // fields needed to impersonate nsILoadContext
+  mHaveLoadContext = haveLoadContext;
+  mIsContent = isContent;
+  mUsePrivateBrowsing = usePrivateBrowsing;
   rv = mChannel->SetNotificationCallbacks(this);
   if (NS_FAILED(rv))
     goto fail;
 
   rv = mChannel->SetProtocol(aProtocol);
   if (NS_FAILED(rv))
     goto fail;
 
@@ -111,26 +126,19 @@ WebSocketChannelParent::RecvSendBinarySt
   LOG(("WebSocketChannelParent::RecvSendBinaryStream() %p\n", this));
   if (mChannel) {
     nsresult rv = mChannel->SendBinaryStream(aStream, aLength);
     NS_ENSURE_SUCCESS(rv, true);
   }
   return true;
 }
 
-NS_IMETHODIMP
-WebSocketChannelParent::GetInterface(const nsIID & iid, void **result NS_OUTPARAM)
-{
-  LOG(("WebSocketChannelParent::GetInterface() %p\n", this));
-  if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider)))
-    return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
-                                        iid, result);
-
-  return NS_ERROR_FAILURE;
-}
+//-----------------------------------------------------------------------------
+// WebSocketChannelParent::nsIRequestObserver
+//-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 WebSocketChannelParent::OnStart(nsISupports *aContext)
 {
   LOG(("WebSocketChannelParent::OnStart() %p\n", this));
   nsCAutoString protocol, extensions;
   if (mChannel) {
     mChannel->GetProtocol(protocol);
@@ -195,10 +203,81 @@ WebSocketChannelParent::OnServerClose(ns
 
 void
 WebSocketChannelParent::ActorDestroy(ActorDestroyReason why)
 {
   LOG(("WebSocketChannelParent::ActorDestroy() %p\n", this));
   mIPCOpen = false;
 }
 
+//-----------------------------------------------------------------------------
+// WebSocketChannelParent::nsIInterfaceRequestor
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WebSocketChannelParent::GetInterface(const nsIID & iid, void **result NS_OUTPARAM)
+{
+  LOG(("WebSocketChannelParent::GetInterface() %p\n", this));
+  if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider)))
+    return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
+                                        iid, result);
+
+  // Only support nsILoadContext if child channel's callbacks did too
+  if (iid.Equals(NS_GET_IID(nsILoadContext)) && !mHaveLoadContext) {
+    return NS_NOINTERFACE;
+  }
+
+  return QueryInterface(iid, result);
+}
+
+//-----------------------------------------------------------------------------
+// WebSocketChannelParent::nsILoadContext
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WebSocketChannelParent::GetAssociatedWindow(nsIDOMWindow**)
+{
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::GetTopWindow(nsIDOMWindow**)
+{
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::IsAppOfType(PRUint32, bool*)
+{
+  // don't expect we need this in parent (Thunderbird/SeaMonkey specific?)
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::GetIsContent(bool *aIsContent)
+{
+  NS_ENSURE_ARG_POINTER(aIsContent);
+
+  *aIsContent = mIsContent;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
+{
+  NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
+
+  *aUsePrivateBrowsing = mUsePrivateBrowsing;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WebSocketChannelParent::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
+{
+  // We shouldn't need this on parent...
+  return NS_ERROR_UNEXPECTED;
+}
+
+
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/websocket/WebSocketChannelParent.h
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.h
@@ -5,50 +5,61 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_net_WebSocketChannelParent_h
 #define mozilla_net_WebSocketChannelParent_h
 
 #include "mozilla/net/PWebSocketParent.h"
 #include "nsIWebSocketListener.h"
 #include "nsIWebSocketChannel.h"
+#include "nsILoadContext.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 
 class nsIAuthPromptProvider;
 
 namespace mozilla {
 namespace net {
 
 class WebSocketChannelParent : public PWebSocketParent,
                                public nsIWebSocketListener,
-                               public nsIInterfaceRequestor
+                               public nsIInterfaceRequestor,
+                               public nsILoadContext
 {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIWEBSOCKETLISTENER
   NS_DECL_NSIINTERFACEREQUESTOR
+  NS_DECL_NSILOADCONTEXT
 
   WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider);
 
  private:
   bool RecvAsyncOpen(const IPC::URI& aURI,
                      const nsCString& aOrigin,
                      const nsCString& aProtocol,
-                     const bool& aSecure);
+                     const bool& aSecure,
+                     const bool& haveLoadContext,
+                     const bool& isContent,
+                     const bool& usingPrivateBrowsing);
   bool RecvClose(const PRUint16 & code, const nsCString & reason);
   bool RecvSendMsg(const nsCString& aMsg);
   bool RecvSendBinaryMsg(const nsCString& aMsg);
   bool RecvSendBinaryStream(const InputStream& aStream,
                             const PRUint32& aLength);
   bool RecvDeleteSelf();
 
   void ActorDestroy(ActorDestroyReason why);
 
   nsCOMPtr<nsIAuthPromptProvider> mAuthProvider;
   nsCOMPtr<nsIWebSocketChannel> mChannel;
   bool mIPCOpen;
+
+  // fields for impersonating nsILoadContext
+  bool mHaveLoadContext : 1;
+  bool mIsContent : 1;
+  bool mUsePrivateBrowsing : 1;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_WebSocketChannelParent_h
--- a/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
+++ b/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
@@ -17,16 +17,18 @@ protocol PWyciwygChannel
   manager PNecko;
 
 parent:
   __delete__();
 
   Init(URI uri);
   AsyncOpen(URI      originalURI,
             PRUint32 loadFlags,
+            bool     haveLoadContext,
+            bool     isContent,
             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
@@ -8,29 +8,29 @@
 #include "WyciwygChannelChild.h"
 
 #include "nsCharsetSource.h"
 #include "nsStringStream.h"
 #include "nsMimeTypes.h"
 #include "nsNetUtil.h"
 #include "nsISerializable.h"
 #include "nsSerializationHelper.h"
+#include "nsILoadContext.h"
 
 namespace mozilla {
 namespace net {
 
 NS_IMPL_ISUPPORTS3(WyciwygChannelChild,
                    nsIRequest,
                    nsIChannel,
                    nsIWyciwygChannel);
 
 
 WyciwygChannelChild::WyciwygChannelChild()
-  : PrivateBrowsingConsumer(this)
-  , mStatus(NS_OK)
+  : mStatus(NS_OK)
   , mIsPending(false)
   , mCanceled(false)
   , mLoadFlags(LOAD_NORMAL)
   , mContentLength(-1)
   , mCharsetSource(kCharsetUninitialized)
   , mState(WCC_NEW)
   , mIPCOpen(false)
   , mEventQ(NS_ISUPPORTS_CAST(nsIWyciwygChannel*, this))
@@ -557,17 +557,32 @@ WyciwygChannelChild::AsyncOpen(nsIStream
 
   mListener = aListener;
   mListenerContext = aContext;
   mIsPending = true;
 
   if (mLoadGroup)
     mLoadGroup->AddRequest(this, nsnull);
 
-  SendAsyncOpen(IPC::URI(mOriginalURI), mLoadFlags, UsePrivateBrowsing());
+  // Get info from nsILoadContext, if any
+  bool haveLoadContext = false;
+  bool isContent = false;
+  bool usePrivateBrowsing = false;
+  nsCOMPtr<nsILoadContext> loadContext;
+  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
+                                NS_GET_IID(nsILoadContext),
+                                getter_AddRefs(loadContext));
+  if (loadContext) {
+    haveLoadContext = true;
+    loadContext->GetIsContent(&isContent);
+    loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
+  }
+
+  SendAsyncOpen(IPC::URI(mOriginalURI), mLoadFlags, haveLoadContext, isContent,
+                usePrivateBrowsing);
 
   mState = WCC_OPENED;
 
   return NS_OK;
 }
 
 
 //-----------------------------------------------------------------------------
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.h
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h
@@ -5,17 +5,16 @@
 #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,
@@ -30,17 +29,16 @@ 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
@@ -12,16 +12,19 @@
 #include "nsISerializable.h"
 #include "nsSerializationHelper.h"
 
 namespace mozilla {
 namespace net {
 
 WyciwygChannelParent::WyciwygChannelParent()
  : mIPCClosed(false)
+ , mHaveLoadContext(false)
+ , mIsContent(false)
+ , mUsePrivateBrowsing(false)
 {
 #if defined(PR_LOGGING)
   if (!gWyciwygLog)
     gWyciwygLog = PR_NewLogModule("nsWyciwygChannel");
 #endif
 }
 
 WyciwygChannelParent::~WyciwygChannelParent()
@@ -35,18 +38,20 @@ WyciwygChannelParent::ActorDestroy(Actor
   // yet, but we must not send any more msgs to child.
   mIPCClosed = true;
 }
 
 //-----------------------------------------------------------------------------
 // WyciwygChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS2(WyciwygChannelParent,
+NS_IMPL_ISUPPORTS4(WyciwygChannelParent,
                    nsIStreamListener,
+                   nsIInterfaceRequestor,
+                   nsILoadContext,
                    nsIRequestObserver);
 
 //-----------------------------------------------------------------------------
 // WyciwygChannelParent::PWyciwygChannelParent
 //-----------------------------------------------------------------------------
 
 bool
 WyciwygChannelParent::RecvInit(const IPC::URI& aURI)
@@ -74,17 +79,19 @@ WyciwygChannelParent::RecvInit(const IPC
     return SendCancelEarly(rv);
 
   return true;
 }
 
 bool
 WyciwygChannelParent::RecvAsyncOpen(const IPC::URI& aOriginal,
                                     const PRUint32& aLoadFlags,
-                                    const bool& aUsingPrivateBrowsing)
+                                    const bool& haveLoadContext,
+                                    const bool& isContent,
+                                    const bool& usePrivateBrowsing)
 {
   nsCOMPtr<nsIURI> original(aOriginal);
 
   LOG(("WyciwygChannelParent RecvAsyncOpen [this=%x]\n", this));
 
   if (!mChannel)
     return true;
 
@@ -93,18 +100,21 @@ 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);
+  // fields needed to impersonate nsILoadContext
+  mHaveLoadContext = haveLoadContext;
+  mIsContent = isContent;
+  mUsePrivateBrowsing = usePrivateBrowsing;
+  mChannel->SetNotificationCallbacks(this);
 
   rv = mChannel->AsyncOpen(this, nsnull);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   return true;
 }
 
@@ -236,9 +246,75 @@ WyciwygChannelParent::OnDataAvailable(ns
 
   if (mIPCClosed || !SendOnDataAvailable(data, aOffset)) {
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// WyciwygChannelParent::nsIInterfaceRequestor
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WyciwygChannelParent::GetInterface(const nsIID& uuid, void** result)
+{
+  // Only support nsILoadContext if child channel's callbacks did too
+  if (uuid.Equals(NS_GET_IID(nsILoadContext)) && !mHaveLoadContext) {
+    return NS_NOINTERFACE;
+  }
+
+  return QueryInterface(uuid, result);
+}
+
+//-----------------------------------------------------------------------------
+// WyciwygChannelParent::nsILoadContext
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WyciwygChannelParent::GetAssociatedWindow(nsIDOMWindow**)
+{
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelParent::GetTopWindow(nsIDOMWindow**)
+{
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelParent::IsAppOfType(PRUint32, bool*)
+{
+  // don't expect we need this in parent (Thunderbird/SeaMonkey specific?)
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelParent::GetIsContent(bool *aIsContent)
+{
+  NS_ENSURE_ARG_POINTER(aIsContent);
+
+  *aIsContent = mIsContent;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelParent::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
+{
+  NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
+
+  *aUsePrivateBrowsing = mUsePrivateBrowsing;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelParent::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
+{
+  // We shouldn't need this on parent...
+  return NS_ERROR_UNEXPECTED;
+}
+
+
 }} // mozilla::net
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
@@ -5,45 +5,58 @@
 #ifndef mozilla_net_WyciwygChannelParent_h
 #define mozilla_net_WyciwygChannelParent_h
 
 #include "mozilla/net/PWyciwygChannelParent.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "nsIStreamListener.h"
 
 #include "nsIWyciwygChannel.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsILoadContext.h"
 
 namespace mozilla {
 namespace net {
 
 class WyciwygChannelParent : public PWyciwygChannelParent
                            , public nsIStreamListener
+                           , public nsIInterfaceRequestor
+                           , public nsILoadContext
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
+  NS_DECL_NSIINTERFACEREQUESTOR
+  NS_DECL_NSILOADCONTEXT
 
   WyciwygChannelParent();
   virtual ~WyciwygChannelParent();
 
 protected:
   virtual bool RecvInit(const IPC::URI& uri);
   virtual bool RecvAsyncOpen(const IPC::URI& original,
                              const PRUint32& loadFlags,
+                             const bool& haveLoadContext,
+                             const bool& isContent,
                              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);
 
   nsCOMPtr<nsIWyciwygChannel> mChannel;
   bool mIPCClosed;
+
+  // fields for impersonating nsILoadContext
+  bool mHaveLoadContext : 1;
+  bool mIsContent : 1;
+  bool mUsePrivateBrowsing : 1;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_WyciwygChannelParent_h
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -74,22 +74,21 @@ public:
   }
 private:
   nsresult mReason;
 };
 
 
 // nsWyciwygChannel methods 
 nsWyciwygChannel::nsWyciwygChannel()
-  : PrivateBrowsingConsumer(this),
-    mStatus(NS_OK),
+  : mStatus(NS_OK),
     mIsPending(false),
     mCharsetAndSourceSet(false),
     mNeedToWriteCharset(false),
-    mPrivate(false),
+    mPrivateBrowsing(false),
     mCharsetSource(kCharsetUninitialized),
     mContentLength(-1),
     mLoadFlags(LOAD_NORMAL)
 {
 }
 
 nsWyciwygChannel::~nsWyciwygChannel() 
 {
@@ -267,16 +266,20 @@ nsWyciwygChannel::GetNotificationCallbac
 NS_IMETHODIMP
 nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
 {
   mCallbacks = aNotificationCallbacks;
   NS_QueryNotificationCallbacks(mCallbacks,
                                 mLoadGroup,
                                 NS_GET_IID(nsIProgressEventSink),
                                 getter_AddRefs(mProgressSink));
+
+  // Will never change unless SetNotificationCallbacks called again, so cache
+  mPrivateBrowsing = NS_UsePrivateBrowsing(this);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP 
 nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
 {
   NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
 
@@ -391,19 +394,16 @@ 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");
@@ -663,30 +663,30 @@ 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 (mPrivate || mLoadFlags & INHIBIT_PERSISTENT_CACHING)
+  if (mPrivateBrowsing || mLoadFlags & INHIBIT_PERSISTENT_CACHING)
     storagePolicy = nsICache::STORE_IN_MEMORY;
   else
     storagePolicy = nsICache::STORE_ANYWHERE;
 
   nsCOMPtr<nsICacheSession> cacheSession;
   // Open a stream based cache session.
-  const char* sessionName = mPrivate ? "wyciwyg-private" : "wyciwyg";
+  const char* sessionName = mPrivateBrowsing ? "wyciwyg-private" : "wyciwyg";
   rv = cacheService->CreateSession(sessionName, storagePolicy, true,
                                    getter_AddRefs(cacheSession));
   if (!cacheSession) 
     return NS_ERROR_FAILURE;
 
-  cacheSession->SetIsPrivate(mPrivate);
+  cacheSession->SetIsPrivate(mPrivateBrowsing);
 
   if (aAccessMode == nsICache::ACCESS_WRITE)
     rv = cacheSession->OpenCacheEntry(aCacheKey, aAccessMode, false,
                                       getter_AddRefs(mCacheEntry));
   else
     rv = cacheSession->AsyncOpenCacheEntry(aCacheKey, aAccessMode, this, false);
 
   return rv;
--- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
@@ -19,26 +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"
+#include "nsILoadContext.h"
+#include "nsNetUtil.h"
 
 extern PRLogModuleInfo * gWyciwygLog;
 
 //-----------------------------------------------------------------------------
 
 class nsWyciwygChannel: public nsIWyciwygChannel,
                         public nsIStreamListener,
-                        public nsICacheListener,
-                        public mozilla::net::PrivateBrowsingConsumer
+                        public nsICacheListener
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIREQUEST
     NS_DECL_NSICHANNEL
     NS_DECL_NSIWYCIWYGCHANNEL
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
@@ -67,17 +67,17 @@ protected:
 
     void NotifyListener();
     bool IsOnCacheIOThread();
 
     nsresult                            mStatus;
     bool                                mIsPending;
     bool                                mCharsetAndSourceSet;
     bool                                mNeedToWriteCharset;
-    bool                                mPrivate;
+    bool                                mPrivateBrowsing;
     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_cacheflags.js
+++ b/netwerk/test/unit/test_cacheflags.js
@@ -6,50 +6,80 @@ var httpserver = null;
 var suffix = Math.random();
 var httpBase = "http://localhost:4444";
 var httpsBase = "http://localhost:4445";
 var shortexpPath = "/shortexp" + suffix;
 var longexpPath = "/longexp" + suffix;
 var nocachePath = "/nocache" + suffix;
 var nostorePath = "/nostore" + suffix;
 
-function make_channel(url, flags) {
+// We attach this to channel when we want to test Private Browsing mode
+function LoadContext(usePrivateBrowsing) {
+  this.usePrivateBrowsing = usePrivateBrowsing;
+}
+
+LoadContext.prototype = {
+  usePrivateBrowsing: false,
+  // don't bother defining rest of nsILoadContext fields: don't need 'em
+
+  QueryInterface: function(iid) {
+    if (iid.equals(Ci.nsILoadContext))
+      return this;
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  },
+
+  getInterface: function(iid) {
+    if (iid.equals(Ci.nsILoadContext))
+      return this;
+    throw Cr.NS_ERROR_NO_INTERFACE;
+  }
+};
+
+PrivateBrowsingLoadContext = new LoadContext(true);
+
+function make_channel(url, flags, usePrivateBrowsing) {
   var ios = Cc["@mozilla.org/network/io-service;1"].
     getService(Ci.nsIIOService);
   var req = ios.newChannel(url, null, null);
   req.loadFlags = flags;
+  if (usePrivateBrowsing) {
+    req.notificationCallbacks = PrivateBrowsingLoadContext;    
+  }
   return req;
 }
 
-function Test(path, flags, expectSuccess, readFromCache, hitServer) {
+function Test(path, flags, expectSuccess, readFromCache, hitServer, 
+              usePrivateBrowsing /* defaults to false */) {
   this.path = path;
   this.flags = flags;
   this.expectSuccess = expectSuccess;
   this.readFromCache = readFromCache;
   this.hitServer = hitServer;
+  this.usePrivateBrowsing = usePrivateBrowsing;
 }
 
 Test.prototype = {
   flags: 0,
   expectSuccess: true,
   readFromCache: false,
   hitServer: true,
+  usePrivateBrowsing: false,
   _buffer: "",
   _isFromCache: false,
 
   QueryInterface: function(iid) {
     if (iid.equals(Components.interfaces.nsIStreamListener) ||
         iid.equals(Components.interfaces.nsIRequestObserver) ||
         iid.equals(Components.interfaces.nsISupports))
       return this;
     throw Components.results.NS_ERROR_NO_INTERFACE;
   },
 
   onStartRequest: function(request, context) {
-    var cachingChannel = request.QueryInterface(Ci.nsICachingChannel);
+    var cachingChannel = request.QueryInterface(Ci.nsICacheInfoChannel);
     this._isFromCache = request.isPending() && cachingChannel.isFromCache();
   },
 
   onDataAvailable: function(request, context, stream, offset, count) {
     this._buffer = this._buffer.concat(read_stream(stream, count));
   },
 
   onStopRequest: function(request, context, status) {
@@ -63,24 +93,30 @@ Test.prototype = {
   run: function() {
     dump("Running:" +
          "\n  " + this.path +
          "\n  " + this.flags +
          "\n  " + this.expectSuccess +
          "\n  " + this.readFromCache +
          "\n  " + this.hitServer + "\n");
     gHitServer = false;
-    var channel = make_channel(this.path, this.flags);
+    var channel = make_channel(this.path, this.flags, this.usePrivateBrowsing);
     channel.asyncOpen(this, null);
   }
 };
 
 var gHitServer = false;
 
 var gTests = [
+
+  new Test(httpBase + shortexpPath, 0,
+           true,   // expect success
+           false,  // read from cache
+           true,   // hit server
+           true),  // USE PRIVATE BROWSING, so not cached for later requests
   new Test(httpBase + shortexpPath, 0,
            true,   // expect success
            false,  // read from cache
            true),  // hit server
   new Test(httpBase + shortexpPath, 0,
            true,   // expect success
            true,   // read from cache
            true),  // hit server
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit_ipc/test_cacheflags_wrap.js
@@ -0,0 +1,7 @@
+//
+// Run test script in content process instead of chrome (xpcshell's default)
+//
+
+function run_test() {
+  run_test_in_child("../unit/test_cacheflags.js");
+}
--- a/netwerk/test/unit_ipc/xpcshell.ini
+++ b/netwerk/test/unit_ipc/xpcshell.ini
@@ -1,12 +1,13 @@
 [DEFAULT]
 head = head_channels_clone.js
 tail = 
 
+[test_cacheflags_wrap.js]
 [test_channel_close_wrap.js]
 [test_cookie_wrap.js]
 [test_duplicate_headers_wrap.js]
 [test_event_sink_wrap.js]
 [test_head_wrap.js]
 [test_headers_wrap.js]
 [test_httpcancel_wrap.js]
 [test_httpsuspend_wrap.js]
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -101,17 +101,16 @@
 #include "prmem.h"
 
 #include "ContentChild.h"
 #include "nsXULAppAPI.h"
 #include "nsPIDOMWindow.h"
 #include "nsIDocShellTreeOwner.h"
 #include "nsIDocShellTreeItem.h"
 #include "ExternalHelperAppChild.h"
-#include "nsIPrivateBrowsingConsumer.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #endif
 
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
@@ -2176,18 +2175,18 @@ nsresult nsExternalAppHandler::OpenWithA
 #if !defined(XP_MACOSX)
                            true);
 #else
                            false);
 #endif
 
     // See whether the channel has been opened in private browsing mode
     NS_ASSERTION(mRequest, "This should never be called with a null request");
-    nsCOMPtr<nsIPrivateBrowsingConsumer> pbConsumer = do_QueryInterface(mRequest);
-    bool inPrivateBrowsing = pbConsumer && pbConsumer->UsePrivateBrowsing();
+    nsCOMPtr<nsIChannel> channel = do_QueryInterface(mRequest);
+    bool inPrivateBrowsing = channel && NS_UsePrivateBrowsing(channel);
 
     // make the tmp file readonly so users won't edit it and lose the changes
     // only if we're going to delete the file
     if (deleteTempFileOnExit || inPrivateBrowsing)
       mFinalFileDestination->SetPermissions(0400);
 
     rv = mMimeInfo->LaunchWithFile(mFinalFileDestination);
     if (NS_FAILED(rv))