Bug 776174 - e10s: cleanup IPC nsILoader code. r=smaug, r=jdm
authorJason Duell <jduell.mcbugs@gmail.com>
Mon, 06 Aug 2012 21:47:48 -0700
changeset 101632 5a6ac05db368df50b92e501801436c127733ff25
parent 101631 533e0681e6ff2d4909e5d7ea0f8a47d607c0b954
child 101633 a525ac9349eb4bf29d4c2c650517791dea282669
push id23245
push useremorley@mozilla.com
push dateTue, 07 Aug 2012 13:39:24 +0000
treeherdermozilla-central@2637d896de91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, jdm
bugs776174
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 776174 - e10s: cleanup IPC nsILoader code. r=smaug, r=jdm
docshell/base/LoadContext.cpp
docshell/base/LoadContext.h
docshell/base/Makefile.in
docshell/base/SerializedLoadContext.cpp
docshell/base/SerializedLoadContext.h
netwerk/base/public/nsNetUtil.h
netwerk/ipc/NeckoMessageUtils.h
netwerk/protocol/ftp/FTPChannelChild.cpp
netwerk/protocol/ftp/FTPChannelParent.cpp
netwerk/protocol/ftp/FTPChannelParent.h
netwerk/protocol/ftp/PFTPChannel.ipdl
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
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/WyciwygChannelParent.cpp
netwerk/protocol/wyciwyg/WyciwygChannelParent.h
new file mode 100644
--- /dev/null
+++ b/docshell/base/LoadContext.cpp
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/LoadContext.h"
+#include "nsIScriptSecurityManager.h"
+#include "nsServiceManagerUtils.h"
+#include "nsContentUtils.h"
+
+namespace mozilla {
+
+NS_IMPL_ISUPPORTS1(LoadContext, nsILoadContext);
+
+//-----------------------------------------------------------------------------
+// LoadContext::nsILoadContext
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+LoadContext::GetAssociatedWindow(nsIDOMWindow**)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+LoadContext::GetTopWindow(nsIDOMWindow**)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  // can't support this in the parent process
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+LoadContext::IsAppOfType(PRUint32, bool*)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  // don't expect we need this in parent (Thunderbird/SeaMonkey specific?)
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+LoadContext::GetIsContent(bool* aIsContent)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  NS_ENSURE_ARG_POINTER(aIsContent);
+
+  *aIsContent = mIsContent;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadContext::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
+
+  *aUsePrivateBrowsing = mUsePrivateBrowsing;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadContext::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  // We shouldn't need this on parent...
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+LoadContext::GetIsInBrowserElement(bool* aIsInBrowserElement)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
+
+  *aIsInBrowserElement = mIsInBrowserElement;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadContext::GetAppId(PRUint32* aAppId)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  NS_ENSURE_ARG_POINTER(aAppId);
+
+  *aAppId = mAppId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadContext::GetExtendedOrigin(nsIURI* aUri, nsACString& aResult)
+{
+  MOZ_ASSERT(mIsNotNull);
+
+  nsIScriptSecurityManager* ssmgr = nsContentUtils::GetSecurityManager();
+
+  return ssmgr->GetExtendedOrigin(aUri, mAppId, mIsInBrowserElement, aResult);
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/docshell/base/LoadContext.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef LoadContext_h
+#define LoadContext_h
+
+#include "SerializedLoadContext.h"
+
+namespace mozilla {
+
+/**
+ * Class that provides nsILoadContext info in Parent process.  Typically copied
+ * from Child via SerializedLoadContext.
+ *
+ * Note: this is not the "normal" or "original" nsILoadContext.  That is
+ * typically provided by nsDocShell.  This is only used when the original
+ * docshell is in a different process and we need to copy certain values from
+ * it.
+ */
+
+class LoadContext : public nsILoadContext
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSILOADCONTEXT
+
+  LoadContext(const IPC::SerializedLoadContext& toCopy)
+    : mIsNotNull(toCopy.mIsNotNull)
+    , mIsContent(toCopy.mIsContent)
+    , mUsePrivateBrowsing(toCopy.mUsePrivateBrowsing)
+    , mIsInBrowserElement(toCopy.mIsInBrowserElement)
+    , mAppId(toCopy.mAppId)
+  {}
+
+private:
+  bool          mIsNotNull;
+  bool          mIsContent;
+  bool          mUsePrivateBrowsing;
+  bool          mIsInBrowserElement;
+  PRUint32      mAppId;
+};
+
+} // namespace mozilla
+
+#endif // LoadContext_h
+
--- a/docshell/base/Makefile.in
+++ b/docshell/base/Makefile.in
@@ -51,35 +51,39 @@ XPIDLSRCS = \
   nsIDocumentLoaderFactory.idl \
   nsIPrivacyTransitionObserver.idl \
   $(NULL)
 
 EXPORTS = \
   nsDocShellLoadTypes.h \
   nsILinkHandler.h \
   nsIWebShellServices.h \
+  SerializedLoadContext.h \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla
 
 EXPORTS_mozilla = \
   IHistory.h \
+  LoadContext.h \
   $(NULL)
 
 CPPSRCS = \
   nsDocShell.cpp \
   nsDocShellLoadInfo.cpp \
   nsDocShellEditorData.cpp \
   nsDocShellTransferableHooks.cpp \
   nsDocShellEnumerator.cpp \
   nsDSURIContentListener.cpp \
   nsDefaultURIFixup.cpp \
   nsWebNavigationInfo.cpp \
   nsAboutRedirector.cpp \
   nsDownloadHistory.cpp \
+  SerializedLoadContext.cpp \
+  LoadContext.cpp \
   $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a
 # static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
new file mode 100644
--- /dev/null
+++ b/docshell/base/SerializedLoadContext.cpp
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "SerializedLoadContext.h"
+#include "nsNetUtil.h"
+#include "nsIChannel.h"
+#include "nsIWebSocketChannel.h"
+
+namespace IPC {
+
+SerializedLoadContext::SerializedLoadContext(nsILoadContext* aLoadContext)
+{
+  Init(aLoadContext);
+}
+
+SerializedLoadContext::SerializedLoadContext(nsIChannel* aChannel)
+{
+  nsCOMPtr<nsILoadContext> loadContext;
+  NS_QueryNotificationCallbacks(aChannel, loadContext);
+  Init(loadContext);
+}
+
+SerializedLoadContext::SerializedLoadContext(nsIWebSocketChannel* aChannel)
+{
+  nsCOMPtr<nsILoadContext> loadContext;
+  NS_QueryNotificationCallbacks(aChannel, loadContext);
+  Init(loadContext);
+}
+
+void
+SerializedLoadContext::Init(nsILoadContext* aLoadContext)
+{
+  if (aLoadContext) {
+    mIsNotNull = true;
+    aLoadContext->GetIsContent(&mIsContent);
+    aLoadContext->GetUsePrivateBrowsing(&mUsePrivateBrowsing);
+    aLoadContext->GetAppId(&mAppId);
+    aLoadContext->GetIsInBrowserElement(&mIsInBrowserElement);
+  } else {
+    mIsNotNull = false;
+    // none of below values really matter when mIsNotNull == false:
+    // we won't be GetInterfaced to nsILoadContext
+    mIsContent = true;
+    mUsePrivateBrowsing = false;
+    mAppId = 0;
+    mIsInBrowserElement = false;
+  }
+}
+
+} // namespace IPC
+
new file mode 100644
--- /dev/null
+++ b/docshell/base/SerializedLoadContext.h
@@ -0,0 +1,85 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef SerializedLoadContext_h
+#define SerializedLoadContext_h
+
+#include "base/basictypes.h"
+#include "IPC/IPCMessageUtils.h"
+#include "nsIIPCSerializable.h"
+#include "nsILoadContext.h"
+
+/*
+ *  This file contains the IPC::SerializedLoadContext class, which is used to
+ *  copy data across IPDL from Child process contexts so it is available in the
+ *  Parent.
+ */
+
+class nsIChannel;
+class nsIWebSocketChannel;
+
+namespace IPC {
+
+class SerializedLoadContext
+{
+public:
+  SerializedLoadContext()
+  {
+    Init(nsnull);
+  }
+
+  SerializedLoadContext(nsILoadContext* aLoadContext);
+  SerializedLoadContext(nsIChannel* aChannel);
+  SerializedLoadContext(nsIWebSocketChannel* aChannel);
+
+  void Init(nsILoadContext* aLoadContext);
+
+  bool IsNotNull() const 
+  {
+    return mIsNotNull;
+  }
+
+  // used to indicate if child-side LoadContext * was null.
+  bool          mIsNotNull;
+  bool          mIsContent;
+  bool          mUsePrivateBrowsing;
+  bool          mIsInBrowserElement;
+  PRUint32      mAppId;
+};
+
+// Function to serialize over IPDL
+template<>
+struct ParamTraits<SerializedLoadContext>
+{
+  typedef SerializedLoadContext paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mIsNotNull);
+    WriteParam(aMsg, aParam.mIsContent);
+    WriteParam(aMsg, aParam.mUsePrivateBrowsing);
+    WriteParam(aMsg, aParam.mAppId);
+    WriteParam(aMsg, aParam.mIsInBrowserElement);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    if (!ReadParam(aMsg, aIter, &aResult->mIsNotNull) ||
+        !ReadParam(aMsg, aIter, &aResult->mIsContent)  ||
+        !ReadParam(aMsg, aIter, &aResult->mUsePrivateBrowsing)  ||
+        !ReadParam(aMsg, aIter, &aResult->mAppId)  ||
+        !ReadParam(aMsg, aIter, &aResult->mIsInBrowserElement)) {
+      return false;
+    }
+
+    return true;
+  }
+};
+
+} // namespace IPC
+
+#endif // SerializedLoadContext_h
+
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -1248,19 +1248,22 @@ NS_LoadPersistentPropertiesFromURISpec(n
 }
 
 /**
  * NS_QueryNotificationCallbacks implements the canonical algorithm for
  * querying interfaces from a channel's notification callbacks.  It first
  * searches the channel's notificationCallbacks attribute, and if the interface
  * is not found there, then it inspects the notificationCallbacks attribute of
  * the channel's loadGroup.
+ *
+ * Note: templatized only because nsIWebSocketChannel is currently not an
+ * nsIChannel.
  */
-inline void
-NS_QueryNotificationCallbacks(nsIChannel   *channel,
+template <class T> inline void
+NS_QueryNotificationCallbacks(T            *channel,
                               const nsIID  &iid,
                               void        **result)
 {
     NS_PRECONDITION(channel, "null channel");
     *result = nullptr;
 
     nsCOMPtr<nsIInterfaceRequestor> cbs;
     channel->GetNotificationCallbacks(getter_AddRefs(cbs));
@@ -1273,19 +1276,22 @@ NS_QueryNotificationCallbacks(nsIChannel
         if (loadGroup) {
             loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs));
             if (cbs)
                 cbs->GetInterface(iid, result);
         }
     }
 }
 
-/* template helper */
-template <class T> inline void
-NS_QueryNotificationCallbacks(nsIChannel  *channel,
+// template helper:
+// Note: "class C" templatized only because nsIWebSocketChannel is currently not
+// an nsIChannel.
+
+template <class C, class T> inline void
+NS_QueryNotificationCallbacks(C           *channel,
                               nsCOMPtr<T> &result)
 {
     NS_QueryNotificationCallbacks(channel, NS_GET_TEMPLATE_IID(T),
                                   getter_AddRefs(result));
 }
 
 /**
  * Alternate form of NS_QueryNotificationCallbacks designed for use by
--- a/netwerk/ipc/NeckoMessageUtils.h
+++ b/netwerk/ipc/NeckoMessageUtils.h
@@ -11,16 +11,17 @@
 #include "nsIURI.h"
 #include "nsIIPCSerializable.h"
 #include "nsIClassInfo.h"
 #include "nsComponentManagerUtils.h"
 #include "nsNetUtil.h"
 #include "nsStringStream.h"
 #include "prio.h"
 #include "mozilla/Util.h" // for DebugOnly
+#include "SerializedLoadContext.h"
 
 namespace IPC {
 
 // Since IPDL doesn't have any knowledge of pointers, there's no easy way to
 // pass around nsIURI pointers.  This is a very thin wrapper that IPDL can
 // easily work with, allowing for conversion to and from an nsIURI pointer.
 
 class URI {
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -155,39 +155,18 @@ FTPChannelChild::AsyncOpen(::nsIStreamLi
   gNeckoChild->SendPFTPChannelConstructor(this);
   mListener = listener;
   mListenerContext = aContext;
 
   // add ourselves to the load group. 
   if (mLoadGroup)
     mLoadGroup->AddRequest(this, nullptr);
 
-  // Get info from nsILoadContext, if any
-  bool haveLoadContext = false;
-  bool isContent = false;
-  bool usePrivateBrowsing = false;
-  bool isInBrowserElement = false;
-  PRUint32 appId = 0;
-  nsCAutoString extendedOrigin;
-  nsCOMPtr<nsILoadContext> loadContext;
-  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
-                                NS_GET_IID(nsILoadContext),
-                                getter_AddRefs(loadContext));
-  if (loadContext) {
-    haveLoadContext = true;
-    loadContext->GetIsContent(&isContent);
-    loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
-    loadContext->GetIsInBrowserElement(&isInBrowserElement);
-    loadContext->GetAppId(&appId);
-    loadContext->GetExtendedOrigin(mURI, extendedOrigin);
-  }
-
   SendAsyncOpen(nsBaseChannel::URI(), mStartPos, mEntityID,
-                IPC::InputStream(mUploadStream), haveLoadContext, isContent,
-                usePrivateBrowsing, isInBrowserElement, appId, extendedOrigin);
+                IPC::InputStream(mUploadStream), IPC::SerializedLoadContext(this));
 
   // 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/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -6,30 +6,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/net/FTPChannelParent.h"
 #include "nsFTPChannel.h"
 #include "nsNetUtil.h"
 #include "nsISupportsPriority.h"
 #include "nsIRedirectChannelRegistrar.h"
 #include "nsFtpProtocolHandler.h"
+#include "mozilla/LoadContext.h"
 
 #undef LOG
 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
 
 namespace mozilla {
 namespace net {
 
 FTPChannelParent::FTPChannelParent()
   : mIPCClosed(false)
-  , mHaveLoadContext(false)
-  , mIsContent(false)
-  , mUsePrivateBrowsing(false)
-  , mIsInBrowserElement(false)
-  , mAppId(0)
 {
   nsIProtocolHandler* handler;
   CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &handler);
   NS_ASSERTION(handler, "no ftp handler");
 }
 
 FTPChannelParent::~FTPChannelParent()
 {
@@ -43,38 +39,32 @@ FTPChannelParent::ActorDestroy(ActorDest
   // yet, but we must not send any more msgs to child.
   mIPCClosed = true;
 }
 
 //-----------------------------------------------------------------------------
 // FTPChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS5(FTPChannelParent,
+NS_IMPL_ISUPPORTS4(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& haveLoadContext,
-                                const bool& isContent,
-                                const bool& usePrivateBrowsing,
-                                const bool& isInBrowserElement,
-                                const PRUint32& appId,
-                                const nsCString& extendedOrigin)
+                                const IPC::SerializedLoadContext& loadContext)
 {
   nsCOMPtr<nsIURI> uri(aURI);
 
 #ifdef DEBUG
   nsCString uriSpec;
   uri->GetSpec(uriSpec);
   LOG(("FTPChannelParent RecvAsyncOpen [this=%x uri=%s]\n",
        this, uriSpec.get()));
@@ -99,24 +89,18 @@ FTPChannelParent::RecvAsyncOpen(const IP
     if (NS_FAILED(rv))
       return SendFailedAsyncOpen(rv);
   }
 
   rv = mChannel->ResumeAt(aStartPos, aEntityID);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
 
-  // fields needed to impersonate nsILoadContext
-  mHaveLoadContext = haveLoadContext;
-  mIsContent = isContent;
-  mUsePrivateBrowsing = usePrivateBrowsing;
-  mIsInBrowserElement = isInBrowserElement;
-  mAppId = appId;
-  mExtendedOrigin = extendedOrigin;
-  mChannel->SetNotificationCallbacks(this);
+  if (loadContext.IsNotNull())
+    mLoadContext = new LoadContext(loadContext);
 
   rv = mChannel->AsyncOpen(this, nullptr);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
   
   return true;
 }
 
@@ -243,94 +227,21 @@ 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;
+  if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
+    NS_ADDREF(mLoadContext);
+    *result = static_cast<nsILoadContext*>(mLoadContext);
+    return NS_OK;
   }
 
   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;
-}
-
-NS_IMETHODIMP
-FTPChannelParent::GetIsInBrowserElement(bool* aIsInBrowserElement)
-{
-  NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
-
-  *aIsInBrowserElement = mIsInBrowserElement;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-FTPChannelParent::GetAppId(PRUint32* aAppId)
-{
-  NS_ENSURE_ARG_POINTER(aAppId);
-
-  *aAppId = mAppId;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-FTPChannelParent::GetExtendedOrigin(nsIURI *aUri, nsACString &aResult)
-{
-  aResult = mExtendedOrigin;
-  return NS_OK;
-}
-
-
+//---------------------
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/ftp/FTPChannelParent.h
+++ b/netwerk/protocol/ftp/FTPChannelParent.h
@@ -17,57 +17,43 @@
 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:
   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& usingPrivateBrowsing,
-                             const bool& isInBrowserElement,
-                             const PRUint32& appId,
-                             const nsCString& extendedOrigin) MOZ_OVERRIDE;
+                             const IPC::SerializedLoadContext& loadContext) MOZ_OVERRIDE;
   virtual bool RecvConnectChannel(const PRUint32& channelId) MOZ_OVERRIDE;
   virtual bool RecvCancel(const nsresult& status) MOZ_OVERRIDE;
   virtual bool RecvSuspend() MOZ_OVERRIDE;
   virtual bool RecvResume() MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   nsRefPtr<nsFtpChannel> mChannel;
 
   bool mIPCClosed;
 
-  // fields for impersonating nsILoadContext
-  bool mHaveLoadContext       : 1;
-  bool mIsContent             : 1;
-  bool mUsePrivateBrowsing    : 1;
-  bool mIsInBrowserElement    : 1;
-
-  PRUint32 mAppId;
-  nsCString mExtendedOrigin;
+  nsCOMPtr<nsILoadContext> mLoadContext;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_FTPChannelParent_h
--- a/netwerk/protocol/ftp/PFTPChannel.ipdl
+++ b/netwerk/protocol/ftp/PFTPChannel.ipdl
@@ -6,38 +6,35 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PNecko;
 
 include "mozilla/net/NeckoMessageUtils.h";
 
 using IPC::URI;
 using IPC::InputStream;
+using IPC::SerializedLoadContext;
 using PRTime;
 
 namespace mozilla {
 namespace net {
 
 async protocol PFTPChannel
 {
   manager PNecko;
 
 parent:
   __delete__();
 
   AsyncOpen(URI uri,
             PRUint64 startPos,
             nsCString entityID,
             InputStream uploadStream,
-            bool haveLoadContext,
-            bool isContent,
-            bool usePrivateBrowsing,
-            bool isInBrowserElement,
-            PRUint32 appID,
-            nsCString extendedOrigin);
+            SerializedLoadContext loadContext);
+
   ConnectChannel(PRUint32 channelId);
   Cancel(nsresult status);
   Suspend();
   Resume();
 
 child:
   OnStartRequest(PRInt32 aContentLength, nsCString aContentType,
                  PRTime aLastModified, nsCString aEntityID, URI aURI);
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -1010,34 +1010,16 @@ 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;
-  bool isInBrowserElement = false;
-  PRUint32 appId = 0;
-  nsCAutoString extendedOrigin;
-  nsCOMPtr<nsILoadContext> loadContext;
-  GetCallback(loadContext);
-  if (loadContext) {
-    haveLoadContext = true;
-    loadContext->GetIsContent(&isContent);
-    loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
-    loadContext->GetIsInBrowserElement(&isInBrowserElement);
-    loadContext->GetAppId(&appId);
-    loadContext->GetExtendedOrigin(mURI, extendedOrigin);
-  }
-
   //
   // Send request to the chrome process...
   //
 
   // FIXME: bug 558623: Combine constructor and SendAsyncOpen into one IPC msg
 
   mozilla::dom::TabChild* tabChild = nullptr;
   nsCOMPtr<nsITabChild> iTabChild;
@@ -1054,18 +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, haveLoadContext, isContent,
-                usePrivateBrowsing, isInBrowserElement, appId, extendedOrigin);
+                appCacheClientId, mAllowSpdy, IPC::SerializedLoadContext(this));
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIHttpChannel
 //-----------------------------------------------------------------------------
 
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -17,34 +17,30 @@
 #include "nsIBadCertListener2.h"
 #include "nsICacheEntryDescriptor.h"
 #include "nsSerializationHelper.h"
 #include "nsISerializable.h"
 #include "nsIAssociatedContentSecurity.h"
 #include "nsIApplicationCacheService.h"
 #include "nsIOfflineCacheUpdate.h"
 #include "nsIRedirectChannelRegistrar.h"
+#include "mozilla/LoadContext.h"
 #include "prinit.h"
 
 namespace mozilla {
 namespace net {
 
 HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding)
   : mIPCClosed(false)
   , mStoredStatus(NS_OK)
   , mStoredProgress(0)
   , mStoredProgressMax(0)
   , mSentRedirect1Begin(false)
   , mSentRedirect1BeginFailed(false)
   , mReceivedRedirect2Verify(false)
-  , mHaveLoadContext(false)
-  , mIsContent(false)
-  , mUsePrivateBrowsing(false)
-  , mIsInBrowserElement(false)
-  , mAppId(0)
 {
   // 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));
 }
@@ -62,18 +58,17 @@ HttpChannelParent::ActorDestroy(ActorDes
   // to child, or IPDL will kill chrome process, too.
   mIPCClosed = true;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS7(HttpChannelParent,
-                   nsILoadContext,
+NS_IMPL_ISUPPORTS6(HttpChannelParent,
                    nsIInterfaceRequestor,
                    nsIProgressEventSink,
                    nsIRequestObserver,
                    nsIStreamListener,
                    nsIParentChannel,
                    nsIParentRedirectingChannel)
 
 //-----------------------------------------------------------------------------
@@ -87,18 +82,20 @@ HttpChannelParent::GetInterface(const ns
       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;
+  if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
+    NS_ADDREF(mLoadContext);
+    *result = static_cast<nsILoadContext*>(mLoadContext);
+    return NS_OK;
   }
 
   return QueryInterface(aIID, result);
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::PHttpChannelParent
 //-----------------------------------------------------------------------------
@@ -118,22 +115,17 @@ 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&                haveLoadContext,
-                                 const bool&                isContent,
-                                 const bool&                usePrivateBrowsing,
-                                 const bool&                isInBrowserElement,
-                                 const PRUint32&            appId,
-                                 const nsCString&           extendedOrigin)
+                                 const IPC::SerializedLoadContext& loadContext)
 {
   nsCOMPtr<nsIURI> uri(aURI);
   nsCOMPtr<nsIURI> originalUri(aOriginalURI);
   nsCOMPtr<nsIURI> docUri(aDocURI);
   nsCOMPtr<nsIURI> referrerUri(aReferrerURI);
 
   nsCString uriSpec;
   uri->GetSpec(uriSpec);
@@ -145,23 +137,18 @@ 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, nullptr, nullptr, loadFlags);
   if (NS_FAILED(rv))
     return SendFailedAsyncOpen(rv);
 
-  // fields needed to impersonate nsILoadContext
-  mHaveLoadContext = haveLoadContext;
-  mIsContent = isContent;
-  mUsePrivateBrowsing = usePrivateBrowsing;
-  mIsInBrowserElement = isInBrowserElement;
-  mAppId = appId;
-  mExtendedOrigin = extendedOrigin;
+  if (loadContext.IsNotNull())
+    mLoadContext = new LoadContext(loadContext);
 
   nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
 
   if (doResumeAt)
     httpChan->ResumeAt(startPos, entityID);
 
   if (originalUri)
     httpChan->SetOriginalURI(originalUri);
@@ -603,84 +590,9 @@ HttpChannelParent::CompleteRedirect(bool
     // TODO: check return value: assume child dead if failed
     unused << SendRedirect3Complete();
   }
 
   mRedirectChannel = nullptr;
   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;
-}
-
-NS_IMETHODIMP
-HttpChannelParent::GetIsInBrowserElement(bool* aIsInBrowserElement)
-{
-  NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
-
-  *aIsInBrowserElement = mIsInBrowserElement;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelParent::GetAppId(PRUint32* aAppId)
-{
-  NS_ENSURE_ARG_POINTER(aAppId);
-
-  *aAppId = mAppId;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-HttpChannelParent::GetExtendedOrigin(nsIURI *aUri, nsACString &aResult)
-{
-  aResult = mExtendedOrigin;
-  return NS_OK;
-}
-
 }} // mozilla::net
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -26,27 +26,25 @@ 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,
@@ -61,22 +59,17 @@ 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,
-                             const bool&                isInBrowserElement,
-                             const PRUint32&            appId,
-                             const nsCString&           extendedOrigin);
+                             const IPC::SerializedLoadContext& loadContext) MOZ_OVERRIDE;
 
   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,
@@ -110,22 +103,15 @@ private:
   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;
-  bool mIsInBrowserElement          : 1;
-
-  PRUint32 mAppId;
-  nsCString mExtendedOrigin;
+  nsCOMPtr<nsILoadContext> mLoadContext;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -12,16 +12,17 @@ include "mozilla/net/NeckoMessageUtils.h
 include "prio.h";
 
 using RequestHeaderTuples;
 using nsHttpHeaderArray;
 using nsHttpResponseHead;
 using nsHttpAtom;
 using IPC::URI;
 using IPC::InputStream;
+using IPC::SerializedLoadContext;
 using PRNetAddr;
 
 namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
 protocol PHttpChannel
 {
@@ -45,23 +46,17 @@ parent:
             bool                allowPipelining,
             bool                forceAllowThirdPartyCookie,
             bool                resumeAt,
             PRUint64            startPos,
             nsCString           entityID,
             bool                chooseApplicationCache,
             nsCString           appCacheClientID,
             bool                allowSpdy,
-            // Fields for imitating a nsILoadContext
-            bool                haveLoadContext,
-            bool                isContent,
-            bool                usePrivateBrowsing,
-            bool                isInBrowserElement,
-            PRUint32            appID,
-            nsCString           extendedOrigin);
+            SerializedLoadContext loadContext);
 
   // 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/websocket/PWebSocket.ipdl
+++ b/netwerk/protocol/websocket/PWebSocket.ipdl
@@ -7,37 +7,32 @@
 
 include protocol PNecko;
 include protocol PBrowser;
 
 include "mozilla/net/NeckoMessageUtils.h";
 
 using IPC::URI;
 using IPC::InputStream;
+using IPC::SerializedLoadContext;
 
 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,
-            // Fields for imitating a nsILoadContext
-            bool haveLoadContext,
-            bool isContent,
-            bool usePrivateBrowsing,
-            bool isInBrowserElement,
-            PRUint32 appID,
-            nsCString extendedOrigin);
+            SerializedLoadContext loadContext);
   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
@@ -323,43 +323,22 @@ 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;
-  bool isInBrowserElement = false;
-  PRUint32 appId = 0;
-  nsCAutoString extendedOrigin;
-  nsCOMPtr<nsILoadContext> loadContext;
-  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
-                                NS_GET_IID(nsILoadContext),
-                                getter_AddRefs(loadContext));
-  if (loadContext) {
-    haveLoadContext = true;
-    loadContext->GetIsContent(&isContent);
-    loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
-    loadContext->GetIsInBrowserElement(&isInBrowserElement);
-    loadContext->GetAppId(&appId);
-    loadContext->GetExtendedOrigin(mURI, extendedOrigin);
-  }
-
   // Corresponding release in DeallocPWebSocket
   AddIPDLReference();
 
   gNeckoChild->SendPWebSocketConstructor(this, tabChild);
   if (!SendAsyncOpen(aURI, nsCString(aOrigin), mProtocol, mEncrypted,
-                     haveLoadContext, isContent, usePrivateBrowsing,
-                     isInBrowserElement, appId, extendedOrigin))
+                     IPC::SerializedLoadContext(this)))
     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
@@ -2,33 +2,28 @@
 /* vim: set sw=2 ts=8 et tw=80 : */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebSocketLog.h"
 #include "WebSocketChannelParent.h"
 #include "nsIAuthPromptProvider.h"
+#include "mozilla/LoadContext.h"
 
 namespace mozilla {
 namespace net {
 
-NS_IMPL_THREADSAFE_ISUPPORTS3(WebSocketChannelParent,
+NS_IMPL_THREADSAFE_ISUPPORTS2(WebSocketChannelParent,
                               nsIWebSocketListener,
-                              nsILoadContext,
                               nsIInterfaceRequestor)
 
 WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider)
   : mAuthProvider(aAuthProvider)
   , mIPCOpen(true)
-  , mHaveLoadContext(false)
-  , mIsContent(false)
-  , mUsePrivateBrowsing(false)
-  , mIsInBrowserElement(false)
-  , mAppId(0)
 {
 #if defined(PR_LOGGING)
   if (!webSocketLog)
     webSocketLog = PR_NewLogModule("nsWebSocket");
 #endif
 }
 
 //-----------------------------------------------------------------------------
@@ -44,42 +39,33 @@ WebSocketChannelParent::RecvDeleteSelf()
   return mIPCOpen ? Send__delete__(this) : true;
 }
 
 bool
 WebSocketChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
                                       const nsCString& aOrigin,
                                       const nsCString& aProtocol,
                                       const bool& aSecure,
-                                      const bool& haveLoadContext,
-                                      const bool& isContent,
-                                      const bool& usePrivateBrowsing,
-                                      const bool& isInBrowserElement,
-                                      const PRUint32& appId,
-                                      const nsCString& extendedOrigin)
+                                      const IPC::SerializedLoadContext& loadContext)
 {
   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;
-  mIsInBrowserElement = isInBrowserElement;
-  mAppId = appId;
-  mExtendedOrigin = extendedOrigin;
+  if (loadContext.IsNotNull())
+    mLoadContext = new LoadContext(loadContext);
+
   rv = mChannel->SetNotificationCallbacks(this);
   if (NS_FAILED(rv))
     goto fail;
 
   rv = mChannel->SetProtocol(aProtocol);
   if (NS_FAILED(rv))
     goto fail;
 
@@ -224,94 +210,20 @@ NS_IMETHODIMP
 WebSocketChannelParent::GetInterface(const nsIID & iid, void **result)
 {
   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;
+  if (iid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
+    NS_ADDREF(mLoadContext);
+    *result = static_cast<nsILoadContext*>(mLoadContext);
+    return NS_OK;
   }
 
   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;
-}
-
-NS_IMETHODIMP
-WebSocketChannelParent::GetIsInBrowserElement(bool* aIsInBrowserElement)
-{
-  NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
-
-  *aIsInBrowserElement = mIsInBrowserElement;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-WebSocketChannelParent::GetAppId(PRUint32* aAppId)
-{
-  NS_ENSURE_ARG_POINTER(aAppId);
-
-  *aAppId = mAppId;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-WebSocketChannelParent::GetExtendedOrigin(nsIURI *aUri,
-                                          nsACString &aResult)
-{
-  aResult = mExtendedOrigin;
-  return NS_OK;
-}
-
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/websocket/WebSocketChannelParent.h
+++ b/netwerk/protocol/websocket/WebSocketChannelParent.h
@@ -16,57 +16,43 @@
 
 class nsIAuthPromptProvider;
 
 namespace mozilla {
 namespace net {
 
 class WebSocketChannelParent : public PWebSocketParent,
                                public nsIWebSocketListener,
-                               public nsIInterfaceRequestor,
-                               public nsILoadContext
+                               public nsIInterfaceRequestor
 {
  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& haveLoadContext,
-                     const bool& isContent,
-                     const bool& usingPrivateBrowsing,
-                     const bool& isInBrowserElement,
-                     const PRUint32& appId,
-                     const nsCString& extendedOrigin);
+                     const IPC::SerializedLoadContext& loadContext);
   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;
+  nsCOMPtr<nsILoadContext> mLoadContext;
   bool mIPCOpen;
 
-  // fields for impersonating nsILoadContext
-  bool mHaveLoadContext             : 1;
-  bool mIsContent                   : 1;
-  bool mUsePrivateBrowsing          : 1;
-  bool mIsInBrowserElement          : 1;
-
-  PRUint32 mAppId;
-  nsCString mExtendedOrigin;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_WebSocketChannelParent_h
--- a/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
+++ b/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
@@ -2,38 +2,33 @@
  * 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 protocol PNecko;
 
 include "mozilla/net/NeckoMessageUtils.h";
 
 using IPC::URI;
+using IPC::SerializedLoadContext;
 
 namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
 protocol PWyciwygChannel
 {
   manager PNecko;
 
 parent:
   __delete__();
 
   Init(URI uri);
-  AsyncOpen(URI      originalURI,
-            PRUint32 loadFlags,
-            // Fields for imitating a nsILoadContext
-            bool     haveLoadContext,
-            bool     isContent,
-            bool     usePrivateBrowsing,
-            bool     isInBrowserElement,
-            PRUint32 appID,
-            nsCString extendedOrigin);
+  AsyncOpen(URI                   originalURI,
+            PRUint32              loadFlags,
+            SerializedLoadContext loadContext);
 
   // 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
@@ -557,38 +557,18 @@ WyciwygChannelChild::AsyncOpen(nsIStream
 
   mListener = aListener;
   mListenerContext = aContext;
   mIsPending = true;
 
   if (mLoadGroup)
     mLoadGroup->AddRequest(this, nullptr);
 
-  // Get info from nsILoadContext, if any
-  bool haveLoadContext = false;
-  bool isContent = false;
-  bool usePrivateBrowsing = false;
-  bool isInBrowserElement = false;
-  PRUint32 appId = 0;
-  nsCAutoString extendedOrigin;
-  nsCOMPtr<nsILoadContext> loadContext;
-  NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
-                                NS_GET_IID(nsILoadContext),
-                                getter_AddRefs(loadContext));
-  if (loadContext) {
-    haveLoadContext = true;
-    loadContext->GetIsContent(&isContent);
-    loadContext->GetUsePrivateBrowsing(&usePrivateBrowsing);
-    loadContext->GetIsInBrowserElement(&isInBrowserElement);
-    loadContext->GetAppId(&appId);
-    loadContext->GetExtendedOrigin(mURI, extendedOrigin);
-  }
-
-  SendAsyncOpen(IPC::URI(mOriginalURI), mLoadFlags, haveLoadContext, isContent,
-                usePrivateBrowsing, isInBrowserElement, appId, extendedOrigin);
+  SendAsyncOpen(IPC::URI(mOriginalURI), mLoadFlags,
+                IPC::SerializedLoadContext(this));
 
   mState = WCC_OPENED;
 
   return NS_OK;
 }
 
 
 //-----------------------------------------------------------------------------
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
@@ -6,27 +6,23 @@
 
 #include "mozilla/net/WyciwygChannelParent.h"
 #include "nsWyciwygChannel.h"
 #include "nsNetUtil.h"
 #include "nsISupportsPriority.h"
 #include "nsCharsetSource.h"
 #include "nsISerializable.h"
 #include "nsSerializationHelper.h"
+#include "mozilla/LoadContext.h"
 
 namespace mozilla {
 namespace net {
 
 WyciwygChannelParent::WyciwygChannelParent()
  : mIPCClosed(false)
- , mHaveLoadContext(false)
- , mIsContent(false)
- , mUsePrivateBrowsing(false)
- , mIsInBrowserElement(false)
- , mAppId(0)
 {
 #if defined(PR_LOGGING)
   if (!gWyciwygLog)
     gWyciwygLog = PR_NewLogModule("nsWyciwygChannel");
 #endif
 }
 
 WyciwygChannelParent::~WyciwygChannelParent()
@@ -40,20 +36,19 @@ WyciwygChannelParent::ActorDestroy(Actor
   // yet, but we must not send any more msgs to child.
   mIPCClosed = true;
 }
 
 //-----------------------------------------------------------------------------
 // WyciwygChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS4(WyciwygChannelParent,
+NS_IMPL_ISUPPORTS3(WyciwygChannelParent,
                    nsIStreamListener,
                    nsIInterfaceRequestor,
-                   nsILoadContext,
                    nsIRequestObserver);
 
 //-----------------------------------------------------------------------------
 // WyciwygChannelParent::PWyciwygChannelParent
 //-----------------------------------------------------------------------------
 
 bool
 WyciwygChannelParent::RecvInit(const IPC::URI& aURI)
@@ -81,22 +76,17 @@ WyciwygChannelParent::RecvInit(const IPC
     return SendCancelEarly(rv);
 
   return true;
 }
 
 bool
 WyciwygChannelParent::RecvAsyncOpen(const IPC::URI& aOriginal,
                                     const PRUint32& aLoadFlags,
-                                    const bool& haveLoadContext,
-                                    const bool& isContent,
-                                    const bool& usePrivateBrowsing,
-                                    const bool& isInBrowserElement,
-                                    const PRUint32& appId,
-                                    const nsCString& extendedOrigin)
+                                    const IPC::SerializedLoadContext& loadContext)
 {
   nsCOMPtr<nsIURI> original(aOriginal);
 
   LOG(("WyciwygChannelParent RecvAsyncOpen [this=%x]\n", this));
 
   if (!mChannel)
     return true;
 
@@ -105,24 +95,18 @@ 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);
 
-  // fields needed to impersonate nsILoadContext
-  mHaveLoadContext = haveLoadContext;
-  mIsContent = isContent;
-  mUsePrivateBrowsing = usePrivateBrowsing;
-  mIsInBrowserElement = isInBrowserElement;
-  mAppId = appId;
-  mExtendedOrigin = extendedOrigin;
-  mChannel->SetNotificationCallbacks(this);
+  if (loadContext.IsNotNull())
+    mLoadContext = new LoadContext(loadContext);
 
   rv = mChannel->AsyncOpen(this, nullptr);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   return true;
 }
 
@@ -262,93 +246,19 @@ WyciwygChannelParent::OnDataAvailable(ns
 //-----------------------------------------------------------------------------
 // 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;
+  if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
+    NS_ADDREF(mLoadContext);
+    *result = static_cast<nsILoadContext*>(mLoadContext);
+    return NS_OK;
   }
 
   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;
-}
-
-NS_IMETHODIMP
-WyciwygChannelParent::GetIsInBrowserElement(bool* aIsInBrowserElement)
-{
-  NS_ENSURE_ARG_POINTER(aIsInBrowserElement);
-
-  *aIsInBrowserElement = mIsInBrowserElement;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-WyciwygChannelParent::GetAppId(PRUint32* aAppId)
-{
-  NS_ENSURE_ARG_POINTER(aAppId);
-
-  *aAppId = mAppId;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-WyciwygChannelParent::GetExtendedOrigin(nsIURI *aUri,
-                                        nsACString &aResult)
-{
-  aResult = mExtendedOrigin;
-  return NS_OK;
-}
-
 
 }} // mozilla::net
--- a/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
@@ -14,56 +14,41 @@
 #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,
-                             const bool& isInBrowserElement,
-                             const PRUint32& appId,
-                             const nsCString& extendedOrigin);
+                             const IPC::SerializedLoadContext& loadContext);
   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;
-  bool mIsInBrowserElement          : 1;
-
-  PRUint32 mAppId;
-  nsCString mExtendedOrigin;
+  nsCOMPtr<nsILoadContext> mLoadContext;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_WyciwygChannelParent_h