Bug 781256 - 'Share FileDescriptors across processes in preparation for OS-level sandbox'. r=khuey+cjones.
authorBen Turner <bent.mozilla@gmail.com>
Thu, 16 Aug 2012 00:02:32 -0400
changeset 107975 418b5cbc7cd9f259d950526cb450881d4d6d4a1e
parent 107974 da866a8a19e384f197d62109d03fd5be32b3d9ef
child 107976 858ab0d138a068ef69faa34a1af80761a4dbb74d
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)
reviewerskhuey
bugs781256
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 781256 - 'Share FileDescriptors across processes in preparation for OS-level sandbox'. r=khuey+cjones.
content/base/src/nsDOMFile.cpp
docshell/base/SerializedLoadContext.h
dom/ipc/Blob.cpp
dom/ipc/Blob.h
dom/ipc/PBlobStream.ipdl
dom/plugins/ipc/PPluginModule.ipdl
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/PluginModuleParent.cpp
ipc/glue/FileDescriptor.cpp
ipc/glue/FileDescriptor.h
ipc/glue/IPCSerializableParams.ipdlh
ipc/glue/InputStreamUtils.cpp
ipc/glue/InputStreamUtils.h
ipc/glue/Makefile.in
ipc/glue/ProtocolUtils.h
ipc/glue/ipdl.mk
ipc/glue/nsIIPCSerializableInputStream.h
ipc/ipdl/Makefile.in
ipc/ipdl/ipdl/builtin.py
ipc/ipdl/ipdl/lower.py
ipc/ipdl/ipdl/type.py
netwerk/base/public/Makefile.in
netwerk/base/public/nsIIPCSerializable.idl
netwerk/base/public/nsIIPCSerializableObsolete.idl
netwerk/base/src/nsBufferedStreams.cpp
netwerk/base/src/nsBufferedStreams.h
netwerk/base/src/nsFileStreams.cpp
netwerk/base/src/nsFileStreams.h
netwerk/base/src/nsMIMEInputStream.cpp
netwerk/base/src/nsSimpleNestedURI.cpp
netwerk/base/src/nsSimpleNestedURI.h
netwerk/base/src/nsSimpleURI.cpp
netwerk/base/src/nsSimpleURI.h
netwerk/base/src/nsStandardURL.cpp
netwerk/base/src/nsStandardURL.h
netwerk/ipc/NeckoMessageUtils.h
netwerk/protocol/about/nsAboutProtocolHandler.cpp
netwerk/protocol/about/nsAboutProtocolHandler.h
netwerk/protocol/http/PHttpChannelParams.h
xpcom/io/nsMultiplexInputStream.cpp
xpcom/io/nsStringStream.cpp
--- a/content/base/src/nsDOMFile.cpp
+++ b/content/base/src/nsDOMFile.cpp
@@ -12,17 +12,18 @@
 #include "nsError.h"
 #include "nsICharsetDetector.h"
 #include "nsICharsetConverterManager.h"
 #include "nsIClassInfo.h"
 #include "nsIConverterInputStream.h"
 #include "nsIDocument.h"
 #include "nsIFileStreams.h"
 #include "nsIInputStream.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableInputStream.h"
+#include "nsIIPCSerializableObsolete.h"
 #include "nsIMIMEService.h"
 #include "nsIPlatformCharset.h"
 #include "nsISeekableStream.h"
 #include "nsIUnicharInputStream.h"
 #include "nsIUnicodeDecoder.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
 #include "nsIUUIDGenerator.h"
@@ -42,63 +43,70 @@ using namespace mozilla::dom;
 
 // XXXkhuey the input stream that we pass out of a DOMFile
 // can outlive the actual DOMFile object.  Thus, we must
 // ensure that the buffer underlying the stream we get
 // from NS_NewByteInputStream is held alive as long as the
 // stream is.  We do that by passing back this class instead.
 class DataOwnerAdapter MOZ_FINAL : public nsIInputStream,
                                    public nsISeekableStream,
-                                   public nsIIPCSerializable,
-                                   public nsIClassInfo
+                                   public nsIIPCSerializableObsolete,
+                                   public nsIClassInfo,
+                                   public nsIIPCSerializableInputStream
 {
   typedef nsDOMMemoryFile::DataOwner DataOwner;
 public:
   static nsresult Create(DataOwner* aDataOwner,
                          PRUint32 aStart,
                          PRUint32 aLength,
                          nsIInputStream** _retval);
 
   NS_DECL_ISUPPORTS
 
   // These are mandatory.
   NS_FORWARD_NSIINPUTSTREAM(mStream->)
   NS_FORWARD_NSISEEKABLESTREAM(mSeekableStream->)
 
   // These are optional. We use a conditional QI to keep them from being called
   // if the underlying stream doesn't QI to either interface.
-  NS_FORWARD_NSIIPCSERIALIZABLE(mSerializable->)
+  NS_FORWARD_NSIIPCSERIALIZABLEOBSOLETE(mSerializableObsolete->)
   NS_FORWARD_NSICLASSINFO(mClassInfo->)
+  NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->)
 
 private:
   DataOwnerAdapter(DataOwner* aDataOwner,
                    nsIInputStream* aStream)
     : mDataOwner(aDataOwner), mStream(aStream),
       mSeekableStream(do_QueryInterface(aStream)),
-      mSerializable(do_QueryInterface(aStream)),
-      mClassInfo(do_QueryInterface(aStream))
+      mSerializableObsolete(do_QueryInterface(aStream)),
+      mClassInfo(do_QueryInterface(aStream)),
+      mSerializableInputStream(do_QueryInterface(aStream))
   {
     NS_ASSERTION(mSeekableStream, "Somebody gave us the wrong stream!");
   }
 
   nsRefPtr<DataOwner> mDataOwner;
   nsCOMPtr<nsIInputStream> mStream;
   nsCOMPtr<nsISeekableStream> mSeekableStream;
-  nsCOMPtr<nsIIPCSerializable> mSerializable;
+  nsCOMPtr<nsIIPCSerializableObsolete> mSerializableObsolete;
   nsCOMPtr<nsIClassInfo> mClassInfo;
+  nsCOMPtr<nsIIPCSerializableInputStream> mSerializableInputStream;
 };
 
 NS_IMPL_THREADSAFE_ADDREF(DataOwnerAdapter)
 NS_IMPL_THREADSAFE_RELEASE(DataOwnerAdapter)
 
 NS_INTERFACE_MAP_BEGIN(DataOwnerAdapter)
   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
   NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializable, mSerializable)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableObsolete,
+                                     mSerializableObsolete)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIClassInfo, mClassInfo)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
+                                     mSerializableInputStream)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
 NS_INTERFACE_MAP_END
 
 nsresult DataOwnerAdapter::Create(DataOwner* aDataOwner,
                                   PRUint32 aStart,
                                   PRUint32 aLength,
                                   nsIInputStream** _retval)
 {
--- a/docshell/base/SerializedLoadContext.h
+++ b/docshell/base/SerializedLoadContext.h
@@ -4,17 +4,16 @@
  * 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.
  */
 
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -5,31 +5,33 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "Blob.h"
 
 #include "nsIDOMFile.h"
 #include "nsIInputStream.h"
+#include "nsIIPCSerializableInputStream.h"
 #include "nsIRemoteBlob.h"
 #include "nsISeekableStream.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/unused.h"
-#include "mozilla/net/NeckoMessageUtils.h"
+#include "mozilla/ipc/InputStreamUtils.h"
 #include "nsDOMFile.h"
 #include "nsThreadUtils.h"
 
 #include "ContentChild.h"
 #include "ContentParent.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
+using namespace mozilla::ipc;
 
 namespace {
 
 class RemoteInputStream : public nsIInputStream,
                           public nsISeekableStream
 {
   mozilla::Monitor mMonitor;
   nsCOMPtr<nsIDOMBlob> mSourceBlob;
@@ -222,20 +224,28 @@ private:
     else {
       ReallyBlockAndWaitForStream();
     }
 
     return !!mSeekableStream;
   }
 };
 
+NS_IMPL_THREADSAFE_ADDREF(RemoteInputStream)
+NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream)
+
+NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
+  NS_INTERFACE_MAP_ENTRY(nsIInputStream)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
+NS_INTERFACE_MAP_END
+
 template <ActorFlavorEnum ActorFlavor>
 class InputStreamActor : public BlobTraits<ActorFlavor>::StreamType
 {
-  typedef typename BlobTraits<ActorFlavor>::StreamType::InputStream InputStream;
   nsRefPtr<RemoteInputStream> mRemoteStream;
 
 public:
   InputStreamActor(RemoteInputStream* aRemoteStream)
   : mRemoteStream(aRemoteStream)
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aRemoteStream);
@@ -244,22 +254,27 @@ public:
   InputStreamActor()
   {
     MOZ_ASSERT(NS_IsMainThread());
   }
 
 private:
   // This method is only called by the IPDL message machinery.
   virtual bool
-  Recv__delete__(const InputStream& aStream) MOZ_OVERRIDE
+  Recv__delete__(const InputStreamParams& aParams) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(mRemoteStream);
 
-    mRemoteStream->SetStream(aStream);
+    nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams);
+    if (!stream) {
+      return false;
+    }
+
+    mRemoteStream->SetStream(stream);
     return true;
   }
 };
 
 template <ActorFlavorEnum ActorFlavor>
 inline
 already_AddRefed<nsIDOMBlob>
 GetBlobFromParams(const SlicedBlobConstructorParams& aParams)
@@ -600,24 +615,20 @@ public:
 
     nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
     return helper->GetStream(aStream);
   }
 
   virtual void*
   GetPBlob() MOZ_OVERRIDE
   {
-    return static_cast<typename ActorType::BaseType*>(mActor);
+    return static_cast<typename ActorType::ProtocolType*>(mActor);
   }
 };
 
-} // namespace ipc
-} // namespace dom
-} // namespace mozilla
-
 template <ActorFlavorEnum ActorFlavor>
 Blob<ActorFlavor>::Blob(nsIDOMBlob* aBlob)
 : mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true), mBlobIsFile(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
   aBlob->AddRef();
 
@@ -735,17 +746,17 @@ Blob<ActorFlavor>::SetMysteryBlobInfo(co
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(mRemoteBlob);
   MOZ_ASSERT(aLength);
 
   ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength);
 
   FileBlobConstructorParams params(aName, aContentType, aLength);
-  return BaseType::SendResolveMystery(params);
+  return ProtocolType::SendResolveMystery(params);
 }
 
 template <ActorFlavorEnum ActorFlavor>
 bool
 Blob<ActorFlavor>::SetMysteryBlobInfo(const nsString& aContentType,
                                       PRUint64 aLength)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -754,17 +765,17 @@ Blob<ActorFlavor>::SetMysteryBlobInfo(co
   MOZ_ASSERT(aLength);
 
   nsString voidString;
   voidString.SetIsVoid(true);
 
   ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength);
 
   NormalBlobConstructorParams params(aContentType, aLength);
-  return BaseType::SendResolveMystery(params);
+  return ProtocolType::SendResolveMystery(params);
 }
 
 template <ActorFlavorEnum ActorFlavor>
 void
 Blob<ActorFlavor>::SetRemoteBlob(nsRefPtr<RemoteBlobType>& aRemoteBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mBlob);
@@ -804,17 +815,17 @@ Blob<ActorFlavor>::NoteDyingRemoteBlob()
 
     return;
   }
 
   // Must do this before calling Send__delete__ or we'll crash there trying to
   // access a dangling pointer.
   mRemoteBlob = nullptr;
 
-  mozilla::unused << BaseType::Send__delete__(this);
+  mozilla::unused << ProtocolType::Send__delete__(this);
 }
 
 template <ActorFlavorEnum ActorFlavor>
 void
 Blob<ActorFlavor>::ActorDestroy(ActorDestroyReason aWhy)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
@@ -863,29 +874,77 @@ Blob<ActorFlavor>::RecvResolveMystery(co
 
     default:
       MOZ_NOT_REACHED("Unknown params!");
   }
 
   return true;
 }
 
-template <ActorFlavorEnum ActorFlavor>
+template <>
 bool
-Blob<ActorFlavor>::RecvPBlobStreamConstructor(StreamType* aActor)
+Blob<Parent>::RecvPBlobStreamConstructor(StreamType* aActor)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mBlob);
   MOZ_ASSERT(!mRemoteBlob);
 
   nsCOMPtr<nsIInputStream> stream;
   nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
   NS_ENSURE_SUCCESS(rv, false);
 
-  return aActor->Send__delete__(aActor, stream.get());
+  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
+    do_QueryInterface(stream);
+  if (!serializable) {
+    MOZ_ASSERT(false, "Must be serializable!");
+    return false;
+  }
+
+  nsCOMPtr<nsIEventTarget> target =
+    do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(target, false);
+
+  nsRefPtr<BaseType::OpenStreamRunnable> runnable =
+    new BaseType::OpenStreamRunnable(this, aActor, stream, serializable,
+                                      target);
+
+  rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsRevocableEventPtr<BaseType::OpenStreamRunnable>* arrayMember =
+    mOpenStreamRunnables.AppendElement();
+  *arrayMember = runnable;
+  return true;
+}
+
+template <>
+bool
+Blob<Child>::RecvPBlobStreamConstructor(StreamType* aActor)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(mBlob);
+  MOZ_ASSERT(!mRemoteBlob);
+
+  nsCOMPtr<nsIInputStream> stream;
+  nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
+    do_QueryInterface(stream);
+  if (!serializable) {
+    MOZ_ASSERT(false, "Must be serializable!");
+    return false;
+  }
+
+  InputStreamParams params;
+  serializable->Serialize(params);
+
+  MOZ_ASSERT(params.type() != InputStreamParams::T__None);
+
+  return aActor->Send__delete__(aActor, params);
 }
 
 template <ActorFlavorEnum ActorFlavor>
 typename Blob<ActorFlavor>::StreamType*
 Blob<ActorFlavor>::AllocPBlobStream()
 {
   MOZ_ASSERT(NS_IsMainThread());
   return new InputStreamActor<ActorFlavor>();
@@ -905,28 +964,137 @@ NS_IMPL_ADDREF_INHERITED(RemoteBlob<Acto
 
 template <ActorFlavorEnum ActorFlavor>
 NS_IMPL_RELEASE_INHERITED(RemoteBlob<ActorFlavor>, nsDOMFile)
 
 template <ActorFlavorEnum ActorFlavor>
 NS_IMPL_QUERY_INTERFACE_INHERITED1(RemoteBlob<ActorFlavor>, nsDOMFile,
                                                             nsIRemoteBlob)
 
-NS_IMPL_THREADSAFE_ADDREF(RemoteInputStream)
-NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream)
+void
+BlobTraits<Parent>::BaseType::NoteRunnableCompleted(
+                    BlobTraits<Parent>::BaseType::OpenStreamRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  for (PRUint32 index = 0; index < mOpenStreamRunnables.Length(); index++) {
+    nsRevocableEventPtr<BaseType::OpenStreamRunnable>& runnable =
+      mOpenStreamRunnables[index];
+
+    if (runnable.get() == aRunnable) {
+      runnable.Forget();
+      mOpenStreamRunnables.RemoveElementAt(index);
+      return;
+    }
+  }
+
+  MOZ_NOT_REACHED("Runnable not in our array!");
+}
+
+BlobTraits<Parent>::BaseType::
+OpenStreamRunnable::OpenStreamRunnable(
+                                   BlobTraits<Parent>::BaseType* aOwner,
+                                   BlobTraits<Parent>::StreamType* aActor,
+                                   nsIInputStream* aStream,
+                                   nsIIPCSerializableInputStream* aSerializable,
+                                   nsIEventTarget* aTarget)
+: mOwner(aOwner), mActor(aActor), mStream(aStream),
+  mSerializable(aSerializable), mTarget(aTarget), mRevoked(false),
+  mClosing(false)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aOwner);
+  MOZ_ASSERT(aActor);
+  MOZ_ASSERT(aStream);
+  MOZ_ASSERT(aSerializable);
+  MOZ_ASSERT(aTarget);
+}
+
+NS_IMETHODIMP
+BlobTraits<Parent>::BaseType::OpenStreamRunnable::Run()
+{
+  MOZ_ASSERT(mStream);
+
+  nsresult rv;
+
+  if (NS_IsMainThread()) {
+    MOZ_ASSERT(mTarget);
+    MOZ_ASSERT(!mClosing);
+
+    if (mRevoked) {
+      MOZ_ASSERT(!mOwner);
+      MOZ_ASSERT(!mActor);
+    }
+    else {
+      MOZ_ASSERT(mOwner);
+      MOZ_ASSERT(mActor);
+
+      nsCOMPtr<nsIIPCSerializableInputStream> serializable;
+      mSerializable.swap(serializable);
 
-NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
-  NS_INTERFACE_MAP_ENTRY(nsIInputStream)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
-  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
-NS_INTERFACE_MAP_END
+      InputStreamParams params;
+      serializable->Serialize(params);
+
+      MOZ_ASSERT(params.type() != InputStreamParams::T__None);
+
+      unused << mActor->Send__delete__(mActor, params);
+
+      mOwner->NoteRunnableCompleted(this);
+
+#ifdef DEBUG
+      mOwner = nullptr;
+      mActor = nullptr;
+#endif
+    }
+
+    mClosing = true;
+
+    nsCOMPtr<nsIEventTarget> target;
+    mTarget.swap(target);
+
+    rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
 
-namespace mozilla {
-namespace dom {
-namespace ipc {
+  if (!mClosing) {
+    // To force the stream open we call Available(). We don't actually care how
+    // much data is available.
+    PRUint64 available;
+    if (NS_FAILED(mStream->Available(&available))) {
+      NS_WARNING("Available failed on this stream!");
+    }
+
+    rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  // Going to always release here.
+  nsCOMPtr<nsIInputStream> stream;
+  mStream.swap(stream);
+
+  rv = stream->Close();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+#ifdef DEBUG
+void
+BlobTraits<Parent>::BaseType::OpenStreamRunnable::Revoke()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mOwner = nullptr;
+  mActor = nullptr;
+  mRevoked = true;
+}
+#endif
 
 // Explicit instantiation of both classes.
 template class Blob<Parent>;
 template class Blob<Child>;
 
 } // namespace ipc
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/Blob.h
+++ b/dom/ipc/Blob.h
@@ -7,22 +7,26 @@
 #ifndef mozilla_dom_ipc_Blob_h
 #define mozilla_dom_ipc_Blob_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/PBlobChild.h"
 #include "mozilla/dom/PBlobParent.h"
 #include "mozilla/dom/PBlobStreamChild.h"
 #include "mozilla/dom/PBlobStreamParent.h"
-#include "mozilla/dom/PContentChild.h"
-#include "mozilla/dom/PContentParent.h"
+#include "mozilla/dom/PContent.h"
+
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
+#include "nsTArray.h"
+#include "nsThreadUtils.h"
 
 class nsIDOMBlob;
+class nsIIPCSerializableInputStream;
+class nsIInputStream;
 
 namespace mozilla {
 namespace dom {
 namespace ipc {
 
 enum ActorFlavorEnum
 {
   Parent = 0,
@@ -31,41 +35,116 @@ enum ActorFlavorEnum
 
 template <ActorFlavorEnum>
 struct BlobTraits
 { };
 
 template <>
 struct BlobTraits<Parent>
 {
-  typedef mozilla::dom::PBlobParent BaseType;
+  typedef mozilla::dom::PBlobParent ProtocolType;
   typedef mozilla::dom::PBlobStreamParent StreamType;
-  typedef mozilla::dom::PContentParent ManagerType;
+
+  // BaseType on the parent side is a bit more complicated than for the child
+  // side. In the case of nsIInputStreams backed by files we need to ensure that
+  // the files are actually opened and closed on a background thread before we
+  // can send their file handles across to the child. The child process could
+  // crash during this process so we need to make sure we cancel the intended
+  // response in such a case. We do that by holding an array of
+  // nsRevocableEventPtr. If the child crashes then this actor will be destroyed
+  // and the nsRevocableEventPtr destructor will cancel any stream events that
+  // are currently in flight.
+  class BaseType : public ProtocolType
+  {
+  protected:
+    BaseType()
+    { }
+
+    virtual ~BaseType()
+    { }
+
+    // Each instance of this class will be dispatched to the network stream
+    // thread pool to run the first time where it will open the file input
+    // stream. It will then dispatch itself back to the main thread to send the
+    // child process its response (assuming that the child has not crashed). The
+    // runnable will then dispatch itself to the thread pool again in order to
+    // close the file input stream.
+    class OpenStreamRunnable : public nsRunnable
+    {
+      friend class nsRevocableEventPtr<OpenStreamRunnable>;
+    public:
+      NS_DECL_NSIRUNNABLE
+
+      OpenStreamRunnable(BaseType* aOwner, StreamType* aActor,
+                         nsIInputStream* aStream,
+                         nsIIPCSerializableInputStream* aSerializable,
+                         nsIEventTarget* aTarget);
+
+    private:
+#ifdef DEBUG
+      void
+      Revoke();
+#else
+      void
+      Revoke()
+      {
+        mRevoked = true;
+      }
+#endif
+
+      // Only safe to access these two pointers if mRevoked is false!
+      BaseType* mOwner;
+      StreamType* mActor;
+
+      nsCOMPtr<nsIInputStream> mStream;
+      nsCOMPtr<nsIIPCSerializableInputStream> mSerializable;
+      nsCOMPtr<nsIEventTarget> mTarget;
+
+      bool mRevoked;
+      bool mClosing;
+    };
+
+    friend class OpenStreamRunnable;
+
+    void
+    NoteRunnableCompleted(OpenStreamRunnable* aRunnable);
+
+    nsTArray<nsRevocableEventPtr<OpenStreamRunnable> > mOpenStreamRunnables;
+  };
 };
 
 template <>
 struct BlobTraits<Child>
 {
-  typedef mozilla::dom::PBlobChild BaseType;
+  typedef mozilla::dom::PBlobChild ProtocolType;
   typedef mozilla::dom::PBlobStreamChild StreamType;
-  typedef mozilla::dom::PContentChild ManagerType;
+
+  class BaseType : public ProtocolType
+  {
+  protected:
+    BaseType()
+    { }
+
+    virtual ~BaseType()
+    { }
+  };
 };
 
 template <ActorFlavorEnum>
 class RemoteBlob;
 
 template <ActorFlavorEnum ActorFlavor>
 class Blob : public BlobTraits<ActorFlavor>::BaseType
 {
   friend class RemoteBlob<ActorFlavor>;
 
 public:
-  typedef typename BlobTraits<ActorFlavor>::BaseType BaseType;
+  typedef typename BlobTraits<ActorFlavor>::ProtocolType ProtocolType;
   typedef typename BlobTraits<ActorFlavor>::StreamType StreamType;
-  typedef typename BlobTraits<ActorFlavor>::ManagerType ManagerType;
+  typedef typename BlobTraits<ActorFlavor>::BaseType BaseType;
   typedef RemoteBlob<ActorFlavor> RemoteBlobType;
   typedef mozilla::ipc::IProtocolManager<
                       mozilla::ipc::RPCChannel::RPCListener>::ActorDestroyReason
           ActorDestroyReason;
   typedef mozilla::dom::BlobConstructorParams BlobConstructorParams;
 
 protected:
   nsIDOMBlob* mBlob;
--- a/dom/ipc/PBlobStream.ipdl
+++ b/dom/ipc/PBlobStream.ipdl
@@ -1,23 +1,20 @@
 /* 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 protocol PBlob;
-
-include "mozilla/net/NeckoMessageUtils.h";
-
-using IPC::InputStream;
+include IPCSerializableParams;
 
 namespace mozilla {
 namespace dom {
 
 protocol PBlobStream
 {
   manager PBlob;
 
 both:
-  __delete__(InputStream stream);
+  __delete__(InputStreamParams params);
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -9,17 +9,16 @@ include protocol PPluginScriptableObject
 include protocol PCrashReporter;
 
 include "npapi.h";
 include "mozilla/plugins/PluginMessageUtils.h";
 include "mozilla/dom/TabMessageUtils.h";
 
 using NPError;
 using NPNVariable;
-using base::FileDescriptor;
 using mozilla::dom::NativeThreadId;
 using mac_plugin_interposing::NSCursorInfo;
 using nsID;
 
 namespace mozilla {
 namespace plugins {
 
 rpc protocol PPluginModule
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -1845,20 +1845,20 @@ PluginModuleChild::AnswerNP_Initialize(c
 
     mAsyncDrawingAllowed = aFlags & kAllowAsyncDrawing;
 
 #ifdef OS_WIN
     SetEventHooks();
 #endif
 
 #ifdef MOZ_X11
-    // Send the parent a dup of our X socket, to act as a proxy
-    // reference for our X resources
+    // Send the parent our X socket to act as a proxy reference for our X
+    // resources.
     int xSocketFd = ConnectionNumber(DefaultXDisplay());
-    SendBackUpXResources(FileDescriptor(xSocketFd, false/*don't close*/));
+    SendBackUpXResources(FileDescriptor(xSocketFd));
 #endif
 
 #if defined(OS_LINUX)
     *_retval = mInitializeFunc(&sBrowserFuncs, &mFunctions);
     return true;
 #elif defined(OS_WIN) || defined(OS_MACOSX)
     *_retval = mInitializeFunc(&sBrowserFuncs);
     return true;
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -684,19 +684,18 @@ PluginModuleParent::NPP_SetValue(NPP ins
 bool
 PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd)
 {
 #ifndef MOZ_X11
     NS_RUNTIMEABORT("This message only makes sense on X11 platforms");
 #else
     NS_ABORT_IF_FALSE(0 > mPluginXSocketFdDup.get(),
                       "Already backed up X resources??");
-    int fd = aXSocketFd.fd; // Copy to discard |const| qualifier
     mPluginXSocketFdDup.forget();
-    mPluginXSocketFdDup.reset(fd);
+    mPluginXSocketFdDup.reset(aXSocketFd.PlatformHandle());
 #endif
     return true;
 }
 
 void
 PluginModuleParent::NPP_URLRedirectNotify(NPP instance, const char* url,
                                           int32_t status, void* notifyData)
 {
new file mode 100644
--- /dev/null
+++ b/ipc/glue/FileDescriptor.cpp
@@ -0,0 +1,65 @@
+/* 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 "FileDescriptor.h"
+
+#include "mozilla/Assertions.h"
+#include "nsDebug.h"
+
+#ifdef XP_WIN
+#include <windows.h>
+#define INVALID_HANDLE INVALID_HANDLE_VALUE
+#else
+#include <unistd.h>
+#define INVALID_HANDLE -1
+#endif
+
+using mozilla::ipc::FileDescriptor;
+
+FileDescriptor::FileDescriptor()
+: mHandle(INVALID_HANDLE)
+{ }
+
+FileDescriptor::PickleType
+FileDescriptor::ShareTo(const FileDescriptor::IPDLPrivate&,
+                        FileDescriptor::ProcessHandle aOtherProcess) const
+{
+#ifdef XP_WIN
+  if (mHandle == INVALID_HANDLE) {
+    return INVALID_HANDLE;
+  }
+
+  PlatformHandleType newHandle;
+  if (!DuplicateHandle(GetCurrentProcess(), mHandle, aOtherProcess, &newHandle,
+                       0, FALSE, DUPLICATE_SAME_ACCESS)) {
+    NS_WARNING("Failed to duplicate file handle!");
+    return INVALID_HANDLE;
+  }
+
+  return newHandle;
+#else // XP_WIN
+  if (mHandle == INVALID_HANDLE) {
+    return base::FileDescriptor();
+  }
+
+  PlatformHandleType newHandle = dup(mHandle);
+  if (newHandle < 0) {
+    NS_WARNING("Failed to duplicate file descriptor!");
+    return base::FileDescriptor();
+  }
+
+  // This file descriptor must be closed once the caller is done using it, so
+  // pass true here for the 'auto_close' argument.
+  return base::FileDescriptor(newHandle, true);
+#endif
+
+  MOZ_NOT_REACHED("Must not get here!");
+  return PickleType();
+}
+
+bool
+FileDescriptor::IsValid() const
+{
+  return mHandle != INVALID_HANDLE;
+}
new file mode 100644
--- /dev/null
+++ b/ipc/glue/FileDescriptor.h
@@ -0,0 +1,95 @@
+/* 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_ipc_FileDescriptor_h
+#define mozilla_ipc_FileDescriptor_h
+
+#include "base/basictypes.h"
+#include "base/process.h"
+#include "nscore.h"
+
+#ifdef XP_WIN
+// Need the HANDLE typedef.
+#include <winnt.h>
+#else
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace mozilla {
+namespace ipc {
+
+// This class is used by IPDL to share file descriptors across processes. When
+// sending a FileDescriptor IPDL will first duplicate a platform-specific file
+// handle type ('PlatformHandleType') into a handle that is valid in the other
+// process. Then IPDL will convert the duplicated handle into a type suitable
+// for pickling ('PickleType') and then send that through the IPC pipe. In the
+// receiving process the pickled data is converted into a platform-specific file
+// handle and then returned to the receiver.
+//
+// To use this class add 'FileDescriptor' as an argument in the IPDL protocol
+// and then pass a file descriptor from C++ to the Call/Send method. The
+// Answer/Recv method will receive a FileDescriptor& on which PlatformHandle()
+// can be called to return the platform file handle.
+class FileDescriptor
+{
+public:
+  typedef base::ProcessHandle ProcessHandle;
+
+#ifdef XP_WIN
+  typedef HANDLE PlatformHandleType;
+  typedef HANDLE PickleType;
+#else
+  typedef int PlatformHandleType;
+  typedef base::FileDescriptor PickleType;
+#endif
+
+  // This should only ever be created by IPDL.
+  struct IPDLPrivate
+  {};
+
+  FileDescriptor();
+
+  FileDescriptor(PlatformHandleType aHandle)
+  : mHandle(aHandle)
+  { }
+
+  FileDescriptor(const IPDLPrivate&, const PickleType& aPickle)
+#ifdef XP_WIN
+  : mHandle(aPickle)
+#else
+  : mHandle(aPickle.fd)
+#endif
+  { }
+
+  // Performs platform-specific actions to duplicate mHandle in the other
+  // process (e.g. dup() on POSIX, DuplicateHandle() on Windows). Returns a
+  // pickled value that can be passed to the other process via IPC.
+  PickleType
+  ShareTo(const IPDLPrivate&, ProcessHandle aOtherProcess) const;
+
+  // Tests mHandle against a well-known invalid platform-specific file handle
+  // (e.g. -1 on POSIX, INVALID_HANDLE_VALUE on Windows).
+  bool
+  IsValid() const;
+
+  PlatformHandleType
+  PlatformHandle() const
+  {
+    return mHandle;
+  }
+
+  bool
+  operator==(const FileDescriptor& aOther) const
+  {
+    return mHandle == aOther.mHandle;
+  }
+
+private:
+  PlatformHandleType mHandle;
+};
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif // mozilla_ipc_FileDescriptor_h
new file mode 100644
--- /dev/null
+++ b/ipc/glue/IPCSerializableParams.ipdlh
@@ -0,0 +1,44 @@
+/* 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/. */
+
+namespace mozilla {
+namespace ipc {
+
+struct StringInputStreamParams
+{
+  nsCString data;
+};
+
+struct FileInputStreamParams
+{
+  FileDescriptor file;
+  int32_t behaviorFlags;
+  int32_t ioFlags;
+};
+
+struct PartialFileInputStreamParams
+{
+  FileInputStreamParams fileStreamParams;
+  uint64_t begin;
+  uint64_t length;
+};
+
+struct MultiplexInputStreamParams
+{
+  InputStreamParams[] streams;
+  uint32_t currentStream;
+  nsresult status;
+  bool startedReadingCurrent;
+};
+
+union InputStreamParams
+{
+  StringInputStreamParams;
+  FileInputStreamParams;
+  PartialFileInputStreamParams;
+  MultiplexInputStreamParams;
+};
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -0,0 +1,79 @@
+/* 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 "InputStreamUtils.h"
+
+#include "nsIIPCSerializableInputStream.h"
+
+#include "mozilla/Assertions.h"
+#include "nsComponentManagerUtils.h"
+#include "nsDebug.h"
+#include "nsID.h"
+#include "nsMultiplexInputStream.h"
+#include "nsNetCID.h"
+#include "nsStringStream.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla::ipc;
+
+namespace {
+
+NS_DEFINE_CID(kStringInputStreamCID, NS_STRINGINPUTSTREAM_CID);
+NS_DEFINE_CID(kFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID);
+NS_DEFINE_CID(kPartialFileInputStreamCID, NS_PARTIALLOCALFILEINPUTSTREAM_CID);
+NS_DEFINE_CID(kMultiplexInputStreamCID, NS_MULTIPLEXINPUTSTREAM_CID);
+
+} // anonymous namespace
+
+namespace mozilla {
+namespace ipc {
+
+already_AddRefed<nsIInputStream>
+DeserializeInputStream(const InputStreamParams& aParams)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIIPCSerializableInputStream> serializable;
+
+  switch (aParams.type()) {
+    case InputStreamParams::T__None:
+      NS_WARNING("This union has no type!");
+      return nullptr;
+
+    case InputStreamParams::TStringInputStreamParams:
+      serializable = do_CreateInstance(kStringInputStreamCID);
+      break;
+
+    case InputStreamParams::TFileInputStreamParams:
+      serializable = do_CreateInstance(kFileInputStreamCID);
+      break;
+
+    case InputStreamParams::TPartialFileInputStreamParams:
+      serializable = do_CreateInstance(kPartialFileInputStreamCID);
+      break;
+
+    case InputStreamParams::TMultiplexInputStreamParams:
+      serializable = do_CreateInstance(kMultiplexInputStreamCID);
+      break;
+
+    default:
+      NS_WARNING("Unknown params!");
+      return nullptr;
+  }
+
+  MOZ_ASSERT(serializable);
+
+  if (!serializable->Deserialize(aParams)) {
+    NS_WARNING("Deserialize failed!");
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIInputStream> stream = do_QueryInterface(serializable);
+  MOZ_ASSERT(stream);
+
+  return stream.forget();
+}
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/glue/InputStreamUtils.h
@@ -0,0 +1,21 @@
+/* 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_ipc_InputStreamUtils_h
+#define mozilla_ipc_InputStreamUtils_h
+
+#include "mozilla/ipc/IPCSerializableParams.h"
+#include "nsCOMPtr.h"
+#include "nsIInputStream.h"
+
+namespace mozilla {
+namespace ipc {
+
+already_AddRefed<nsIInputStream>
+DeserializeInputStream(const InputStreamParams& aParams);
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif // mozilla_ipc_InputStreamUtils_h
--- a/ipc/glue/Makefile.in
+++ b/ipc/glue/Makefile.in
@@ -20,31 +20,35 @@ EXPORT_LIBRARY = 1
 EXPORTS_NAMESPACES = IPC mozilla/ipc
 
 EXPORTS_IPC = IPCMessageUtils.h
 
 EXPORTS_mozilla/ipc = \
   AsyncChannel.h \
   BrowserProcessSubThread.h \
   CrossProcessMutex.h \
+  FileDescriptor.h \
   GeckoChildProcessHost.h \
+  InputStreamUtils.h \
   IOThreadChild.h \
   ProcessChild.h \
   ProtocolUtils.h \
   RPCChannel.h \
   SharedMemory.h \
   SharedMemoryBasic.h \
   SharedMemoryBasic_chromium.h \
   SharedMemorySysV.h \
   Shmem.h \
   SyncChannel.h \
   ScopedXREEmbed.h \
   Transport.h \
   $(NULL)
 
+EXPORTS = nsIIPCSerializableInputStream.h
+
 ifeq ($(OS_ARCH),WINNT) #{
 EXPORTS_mozilla/ipc += \
   Transport_win.h \
   $(NULL)
 else
 # POSIX
 EXPORTS_mozilla/ipc += \
   Transport_posix.h \
@@ -58,17 +62,19 @@ ifeq ($(OS_TARGET),Android)
 EXPORTS_mozilla/ipc += SharedMemoryBasic_android.h
 else
 EXPORTS_mozilla/ipc += SharedMemoryBasic_chromium.h
 endif #}
 
 CPPSRCS += \
   AsyncChannel.cpp \
   BrowserProcessSubThread.cpp \
+  FileDescriptor.cpp \
   GeckoChildProcessHost.cpp \
+  InputStreamUtils.cpp \
   MessagePump.cpp \
   ProcessChild.cpp \
   ProtocolUtils.cpp \
   RPCChannel.cpp \
   ScopedXREEmbed.cpp \
   SharedMemory.cpp \
   Shmem.cpp \
   StringUtil.cpp \
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -10,16 +10,17 @@
 
 #include "base/process.h"
 #include "base/process_util.h"
 #include "chrome/common/ipc_message_utils.h"
 
 #include "prenv.h"
 
 #include "IPCMessageStart.h"
+#include "mozilla/ipc/FileDescriptor.h"
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/Transport.h"
 
 // WARNING: this takes into account the private, special-message-type
 // enum in ipc_channel.h.  They need to be kept in sync.
 namespace {
 // XXX the max message ID is actually kuint32max now ... when this
 // changed, the assumptions of the special message IDs changed in that
new file mode 100644
--- /dev/null
+++ b/ipc/glue/ipdl.mk
@@ -0,0 +1,5 @@
+# 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/.
+
+IPDLSRCS = IPCSerializableParams.ipdlh
new file mode 100644
--- /dev/null
+++ b/ipc/glue/nsIIPCSerializableInputStream.h
@@ -0,0 +1,57 @@
+/* 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_ipc_nsIIPCSerializableInputStream_h
+#define mozilla_ipc_nsIIPCSerializableInputStream_h
+
+#include "nsISupports.h"
+#include "mozilla/Attributes.h"
+
+namespace mozilla {
+namespace ipc {
+class InputStreamParams;
+}
+}
+
+#define NS_IIPCSERIALIZABLEINPUTSTREAM_IID \
+  {0x1f56a3f8, 0xc413, 0x4274, {0x88, 0xe6, 0x68, 0x50, 0x9d, 0xf8, 0x85, 0x2d}}
+
+class NS_NO_VTABLE nsIIPCSerializableInputStream : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(NS_IIPCSERIALIZABLEINPUTSTREAM_IID)
+
+  virtual void
+  Serialize(mozilla::ipc::InputStreamParams& aParams) = 0;
+
+  virtual bool
+  Deserialize(const mozilla::ipc::InputStreamParams& aParams) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
+                              NS_IIPCSERIALIZABLEINPUTSTREAM_IID)
+
+#define NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM \
+  virtual void \
+  Serialize(mozilla::ipc::InputStreamParams&) MOZ_OVERRIDE; \
+  virtual bool \
+  Deserialize(const mozilla::ipc::InputStreamParams&) MOZ_OVERRIDE;
+
+#define NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \
+  virtual void \
+  Serialize(mozilla::ipc::InputStreamParams& aParams) MOZ_OVERRIDE \
+  { _to Serialize(aParams); } \
+  virtual bool \
+  Deserialize(const mozilla::ipc::InputStreamParams& aParams) MOZ_OVERRIDE \
+  { return _to Deserialize(aParams); }
+
+#define NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \
+  virtual void \
+  Serialize(mozilla::ipc::InputStreamParams& aParams) MOZ_OVERRIDE \
+  { if (_to) { _to->Serialize(aParams); } } \
+  virtual bool \
+  Deserialize(const mozilla::ipc::InputStreamParams& aParams) MOZ_OVERRIDE \
+  { if (_to) { return _to->Deserialize(aParams); } return false; }
+
+#endif // mozilla_ipc_nsIIPCSerializableInputStream_h
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -27,16 +27,17 @@ IPDLDIRS =  \
   dom/indexedDB/ipc \
   dom/bluetooth/ipc \
   dom/plugins/ipc  \
   dom/ipc \
   dom/sms/src/ipc \
   dom/src/storage \
   gfx/layers/ipc \
   hal/sandbox \
+  ipc/glue  \
   ipc/testshell  \
   js/ipc  \
   layout/ipc \
   netwerk/ipc  \
   netwerk/protocol/ftp \
   netwerk/protocol/http  \
   netwerk/protocol/wyciwyg \
   netwerk/protocol/websocket \
--- a/ipc/ipdl/ipdl/builtin.py
+++ b/ipc/ipdl/ipdl/builtin.py
@@ -43,16 +43,17 @@ Types = (
     'PRUint64',
     'PRSize',
 
     # Mozilla types: "less" standard things we know how serialize/deserialize
     'nsresult',
     'nsString',
     'nsCString',
     'mozilla::ipc::Shmem',
+    'mozilla::ipc::FileDescriptor',
 
     # quasi-stdint types used by "public" Gecko headers
     'int8',
     'uint8',
     'int16',
     'uint16',
     'int32',
     'uint32',
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -228,17 +228,16 @@ def _shmemForget(shmemexpr):
 
 def _shmemRevokeRights(shmemexpr):
     return ExprCall(ExprSelect(shmemexpr, '.', 'RevokeRights'),
                     args=[ _shmemBackstagePass() ])
 
 def _lookupShmem(idexpr):
     return ExprCall(ExprVar('LookupSharedMemory'), args=[ idexpr ])
 
-
 def _makeForwardDeclForQClass(clsname, quals):
     fd = ForwardDecl(clsname, cls=1)
     if 0 == len(quals):
         return fd
 
     outerns = Namespace(quals[0])
     innerns = outerns
     for ns in quals[1:]:
@@ -487,16 +486,19 @@ class _ConvertToCxxType(TypeVisitor):
 
     def visitArrayType(self, a):
         basecxxtype = a.basetype.accept(self)
         return _cxxArrayType(basecxxtype)
 
     def visitShmemType(self, s):
         return Type(self.typename(s))
 
+    def visitFDType(self, s):
+        return Type(self.typename(s))
+
     def visitProtocolType(self, p): assert 0
     def visitMessageType(self, m): assert 0
     def visitVoidType(self, v): assert 0
     def visitStateType(self, st): assert 0
 
 def _cxxBareType(ipdltype, side, fq=0):
     return ipdltype.accept(_ConvertToCxxType(side, fq))
 
@@ -663,16 +665,18 @@ class _StructField(_CompoundTypeComponen
             ref = ExprDeref(ref)
         return ref
 
     def constRefExpr(self, thisexpr=None):
         # sigh, gross hack
         refexpr = self.refExpr(thisexpr)
         if 'Shmem' == self.ipdltype.name():
             refexpr = ExprCast(refexpr, Type('Shmem', ref=1), const=1)
+        if 'FileDescriptor' == self.ipdltype.name():
+            refexpr = ExprCast(refexpr, Type('FileDescriptor', ref=1), const=1)
         return refexpr
 
     def argVar(self):
         return ExprVar('_'+ self.name)
 
     def memberVar(self):
         return ExprVar(self.name + '_')
 
@@ -821,16 +825,18 @@ IPDL union type."""
         # XXX sneaky here, maybe need ExprCtor()?
         return ExprCall(self.bareType())
 
     def getConstValue(self):
         v = ExprDeref(self.callGetConstPtr())
         # sigh
         if 'Shmem' == self.ipdltype.name():
             v = ExprCast(v, Type('Shmem', ref=1), const=1)
+        if 'FileDescriptor' == self.ipdltype.name():
+            v = ExprCast(v, Type('FileDescriptor', ref=1), const=1)
         return v
 
 ##--------------------------------------------------
 
 class MessageDecl(ipdl.ast.MessageDecl):
     def baseName(self):
         return self.name
     
@@ -985,17 +991,16 @@ def _subtreeUsesShmem(p):
 
     ptype = p.decl.type
     for mgd in ptype.manages:
         if ptype is not mgd:
             if _subtreeUsesShmem(mgd._ast):
                 return True
     return False
 
-
 class Protocol(ipdl.ast.Protocol):
     def cxxTypedefs(self):
         return self.decl.cxxtypedefs
 
     def sendSems(self):
         return self.decl.type.toplevel().sendSemantics
 
     def channelName(self):
@@ -1862,16 +1867,21 @@ stmt.  Some types generate both kinds.''
     def visitArrayType(self, t):
         return TypeVisitor.visitArrayType(self, t)
 
     def visitShmemType(self, s):
         if s in self.visited: return
         self.visited.add(s)
         self.maybeTypedef('mozilla::ipc::Shmem', 'Shmem')
 
+    def visitFDType(self, s):
+        if s in self.visited: return
+        self.visited.add(s)
+        self.maybeTypedef('mozilla::ipc::FileDescriptor', 'FileDescriptor')
+
     def visitVoidType(self, v): assert 0
     def visitMessageType(self, v): assert 0
     def visitProtocolType(self, v): assert 0
     def visitStateType(self, v): assert 0
 
 
 def _generateCxxStruct(sd):
     ''' '''
@@ -3374,21 +3384,21 @@ class _GenerateProtocolActorCode(ipdl.as
                 StmtDecl(Decl(
                     p.managedVarType(managed, self.side),
                     p.managedVar(managed, self.side).name)) ])
 
     def implementManagerIface(self):
         p = self.protocol
         routedvar = ExprVar('aRouted')
         idvar = ExprVar('aId')
-        shmemvar = ExprVar('aShmem')
+        shmemvar = ExprVar('shmem')
         rawvar = ExprVar('segment')
         sizevar = ExprVar('aSize')
-        typevar = ExprVar('type')
-        unsafevar = ExprVar('unsafe')
+        typevar = ExprVar('aType')
+        unsafevar = ExprVar('aUnsafe')
         listenertype = Type('ChannelListener', ptr=1)
 
         register = MethodDefn(MethodDecl(
             p.registerMethod().name,
             params=[ Decl(listenertype, routedvar.name) ],
             ret=_actorIdType(), virtual=1))
         registerid = MethodDefn(MethodDecl(
             p.registerIDMethod().name,
@@ -3973,18 +3983,19 @@ class _GenerateProtocolActorCode(ipdl.as
     ##
     def implementPickling(self):
         # pickling of "normal", non-IPDL types
         self.implementGenericPickling()
 
         # pickling for IPDL types
         specialtypes = set()
         class findSpecialTypes(TypeVisitor):
-            def visitActorType(self, a):  specialtypes.add(a)
-            def visitShmemType(self, s):  specialtypes.add(s)
+            def visitActorType(self, a): specialtypes.add(a)
+            def visitShmemType(self, s): specialtypes.add(s)
+            def visitFDType(self, s): specialtypes.add(s)
             def visitStructType(self, s):
                 specialtypes.add(s)
                 return TypeVisitor.visitStructType(self, s)
             def visitUnionType(self, u):
                 specialtypes.add(u)
                 return TypeVisitor.visitUnionType(self, u)
             def visitArrayType(self, a):
                 if a.basetype.isIPDL():
@@ -4001,16 +4012,17 @@ class _GenerateProtocolActorCode(ipdl.as
                 param.ipdltype.accept(findSpecialTypes())
             for ret in md.returns:
                 ret.ipdltype.accept(findSpecialTypes())
 
         for t in specialtypes:
             if t.isActor():    self.implementActorPickling(t)
             elif t.isArray():  self.implementSpecialArrayPickling(t)
             elif t.isShmem():  self.implementShmemPickling(t)
+            elif t.isFD():     self.implementFDPickling(t)
             elif t.isStruct(): self.implementStructPickling(t)
             elif t.isUnion():  self.implementUnionPickling(t)
             else:
                 assert 0 and 'unknown special type'
 
     def implementGenericPickling(self):
         var = self.var
         msgvar = self.msgvar
@@ -4220,16 +4232,67 @@ class _GenerateProtocolActorCode(ipdl.as
             StmtDecl(Decl(_rawShmemType(ptr=1), rawvar.name),
                      init=_lookupShmem(idvar)),
             iffound,
             StmtReturn.FALSE
         ])
 
         self.cls.addstmts([ write, Whitespace.NL, read, Whitespace.NL ])
 
+    def implementFDPickling(self, fdtype):
+        msgvar = self.msgvar
+        itervar = self.itervar
+        var = self.var
+        tmpvar = ExprVar('fd')
+        picklevar = ExprVar('pfd')
+        intype = _cxxConstRefType(fdtype, self.side)
+        outtype = _cxxPtrToType(fdtype, self.side)
+
+        def _fdType():
+            return Type('FileDescriptor')
+
+        def _fdPickleType():
+            return Type('FileDescriptor::PickleType')
+
+        def _fdBackstagePass():
+            return ExprCall(ExprVar('FileDescriptor::IPDLPrivate'))
+
+        write = MethodDefn(self.writeMethodDecl(intype, var))
+        write.addstmts([
+            StmtDecl(Decl(_fdPickleType(), picklevar.name),
+                     init=ExprCall(ExprSelect(var, '.', 'ShareTo'),
+                                   args=[ _fdBackstagePass(),
+                                          self.protocol.callOtherProcess() ])),
+            StmtExpr(ExprCall(ExprVar('IPC::WriteParam'),
+                              args=[ msgvar, picklevar ])),
+        ])
+
+        read = MethodDefn(self.readMethodDecl(outtype, var))
+        ifread = StmtIf(ExprNot(ExprCall(ExprVar('IPC::ReadParam'),
+                                         args=[ msgvar, itervar,
+                                                ExprAddrOf(picklevar) ])))
+        ifread.addifstmt(StmtReturn.FALSE)
+
+        ifnvalid = StmtIf(ExprNot(ExprCall(ExprSelect(tmpvar, '.', 'IsValid'))))
+        ifnvalid.addifstmt(StmtReturn.FALSE)
+
+        read.addstmts([
+            StmtDecl(Decl(_fdPickleType(), picklevar.name)),
+            ifread,
+            Whitespace.NL,
+            StmtDecl(Decl(_fdType(), tmpvar.name),
+                     init=ExprCall(ExprVar('FileDescriptor'),
+                                   args=[ _fdBackstagePass(), picklevar ])),
+            ifnvalid,
+            Whitespace.NL,
+            StmtExpr(ExprAssn(ExprDeref(var), tmpvar)),
+            StmtReturn.TRUE
+        ])
+
+        self.cls.addstmts([ write, Whitespace.NL, read, Whitespace.NL ])
 
     def implementStructPickling(self, structtype):
         msgvar = self.msgvar
         itervar = self.itervar
         var = self.var
         intype = _cxxConstRefType(structtype, self.side)
         outtype = _cxxPtrToType(structtype, self.side)
         sd = structtype._ast
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -84,16 +84,19 @@ class TypeVisitor:
         a.basetype.accept(self, *args)
 
     def visitShmemType(self, s, *args):
         pass
 
     def visitShmemChmodType(self, c, *args):
         c.shmem.accept(self)
 
+    def visitFDType(self, s, *args):
+        pass
+
 
 class Type:
     def __cmp__(self, o):
         return cmp(self.fullname(), o.fullname())
     def __eq__(self, o):
         return (self.__class__ == o.__class__
                 and self.fullname() == o.fullname())
     def __hash__(self):
@@ -191,16 +194,17 @@ class IPDLType(Type):
     def isActor(self): return False
     def isStruct(self): return False
     def isUnion(self): return False
     def isArray(self): return False
     def isAtom(self):  return True
     def isCompound(self): return False
     def isShmem(self): return False
     def isChmod(self): return False
+    def isFD(self): return False
 
     def isAsync(self): return self.sendSemantics is ASYNC
     def isSync(self): return self.sendSemantics is SYNC
     def isRpc(self): return self.sendSemantics is RPC
 
     def talksAsync(self): return True
     def talksSync(self): return self.isSync() or self.isRpc()
     def talksRpc(self): return self.isRpc()
@@ -412,16 +416,26 @@ class ShmemType(IPDLType):
         self.qname = qname
     def isShmem(self): return True
 
     def name(self):
         return self.qname.baseid
     def fullname(self):
         return str(self.qname)
 
+class FDType(IPDLType):
+    def __init__(self, qname):
+        self.qname = qname
+    def isFD(self): return True
+
+    def name(self):
+        return self.qname.baseid
+    def fullname(self):
+        return str(self.qname)
+
 def iteractortypes(t, visited=None):
     """Iterate over any actor(s) buried in |type|."""
     if visited is None:
         visited = set()
 
     # XXX |yield| semantics makes it hard to use TypeVisitor
     if not t.isIPDL():
         return
@@ -447,16 +461,27 @@ def hasshmem(type):
     class findShmem(TypeVisitor):
         def visitShmemType(self, s):  raise found()
     try:
         type.accept(findShmem())
     except found:
         return True
     return False
 
+def hasfd(type):
+    """Return true iff |type| is fd or has it buried within."""
+    class found: pass
+    class findFD(TypeVisitor):
+        def visitFDType(self, s):  raise found()
+    try:
+        type.accept(findFD())
+    except found:
+        return True
+    return False
+
 ##--------------------
 _builtinloc = Loc('<builtin>', 0)
 def makeBuiltinUsing(tname):
     quals = tname.split('::')
     base = quals.pop()
     quals = quals[0:]
     return UsingStmt(_builtinloc,
                      TypeSpec(_builtinloc,
@@ -770,16 +795,18 @@ class GatherDecls(TcheckVisitor):
             utype.components.append(self._canonicalType(cdecl.type, c))
 
     def visitUsingStmt(self, using):
         fullname = str(using.type)
         if using.type.basename() == fullname:
             fullname = None
         if fullname == 'mozilla::ipc::Shmem':
             ipdltype = ShmemType(using.type.spec)
+        elif fullname == 'mozilla::ipc::FileDescriptor':
+            ipdltype = FDType(using.type.spec)
         else:
             ipdltype = ImportedCxxType(using.type.spec)
         using.decl = self.declare(
             loc=using.loc,
             type=ipdltype,
             shortname=using.type.basename(),
             fullname=fullname)
 
--- a/netwerk/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -47,17 +47,17 @@ XPIDLSRCS	= \
 		nsICryptoHMAC.idl \
 		nsIDownloader.idl \
 		nsIEncodedChannel.idl \
 		nsIFileStreams.idl \
 		nsIIncrementalDownload.idl \
 		nsIInputStreamPump.idl \
 		nsIInputStreamChannel.idl \
                 nsIIOService2.idl \
-                nsIIPCSerializable.idl \
+                nsIIPCSerializableObsolete.idl \
 		nsIMIMEInputStream.idl \
 		nsINetAddr.idl \
                 nsINetworkLinkService.idl \
 		nsIPermission.idl \
 		nsIPermissionManager.idl \
 		nsIPrivateBrowsingService.idl \
 		nsIProgressEventSink.idl \
 		nsIPrompt.idl \
rename from netwerk/base/public/nsIIPCSerializable.idl
rename to netwerk/base/public/nsIIPCSerializableObsolete.idl
--- a/netwerk/base/public/nsIIPCSerializable.idl
+++ b/netwerk/base/public/nsIIPCSerializableObsolete.idl
@@ -12,13 +12,13 @@ class Message;
 }
 %}
 
 [ptr] native ConstMessage(const IPC::Message);
 [ptr] native Message(IPC::Message);
 [ptr] native Iterator(void*);
 
 [noscript, uuid(1f605ac7-666b-471f-9864-1a21a95f11c4)]
-interface nsIIPCSerializable : nsISupports
+interface nsIIPCSerializableObsolete : nsISupports
 {
   [notxpcom] boolean read(in ConstMessage msg, in Iterator iter);
   [notxpcom] void write(in Message msg);
 };
--- a/netwerk/base/src/nsBufferedStreams.cpp
+++ b/netwerk/base/src/nsBufferedStreams.cpp
@@ -247,26 +247,26 @@ NS_IMPL_RELEASE_INHERITED(nsBufferedInpu
 
 NS_IMPL_CLASSINFO(nsBufferedInputStream, NULL, nsIClassInfo::THREADSAFE,
                   NS_BUFFEREDINPUTSTREAM_CID)
 
 NS_INTERFACE_MAP_BEGIN(nsBufferedInputStream)
     NS_INTERFACE_MAP_ENTRY(nsIInputStream)
     NS_INTERFACE_MAP_ENTRY(nsIBufferedInputStream)
     NS_INTERFACE_MAP_ENTRY(nsIStreamBufferAccess)
-    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableObsolete)
     NS_IMPL_QUERY_CLASSINFO(nsBufferedInputStream)
 NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)
 
 NS_IMPL_CI_INTERFACE_GETTER5(nsBufferedInputStream,
                              nsIInputStream,
                              nsIBufferedInputStream,
                              nsISeekableStream,
                              nsIStreamBufferAccess,
-                             nsIIPCSerializable)
+                             nsIIPCSerializableObsolete)
 
 nsresult
 nsBufferedInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
 {
     NS_ENSURE_NO_AGGREGATION(aOuter);
 
     nsBufferedInputStream* stream = new nsBufferedInputStream();
     if (stream == nullptr)
--- a/netwerk/base/src/nsBufferedStreams.h
+++ b/netwerk/base/src/nsBufferedStreams.h
@@ -8,17 +8,17 @@
 
 #include "nsIBufferedStreams.h"
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
 #include "nsISeekableStream.h"
 #include "nsIStreamBufferAccess.h"
 #include "nsCOMPtr.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableObsolete.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsBufferedStream : public nsISeekableStream
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSISEEKABLESTREAM
@@ -55,24 +55,24 @@ protected:
     PRUint8                     mGetBufferCount;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsBufferedInputStream : public nsBufferedStream,
                               public nsIBufferedInputStream,
                               public nsIStreamBufferAccess,
-                              public nsIIPCSerializable
+                              public nsIIPCSerializableObsolete
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSIBUFFEREDINPUTSTREAM
     NS_DECL_NSISTREAMBUFFERACCESS
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
 
     nsBufferedInputStream() : nsBufferedStream() {}
     virtual ~nsBufferedInputStream() {}
 
     static nsresult
     Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
     nsIInputStream* Source() { 
--- a/netwerk/base/src/nsFileStreams.cpp
+++ b/netwerk/base/src/nsFileStreams.cpp
@@ -23,19 +23,24 @@
 #include "prerror.h"
 #include "nsCRT.h"
 #include "nsIFile.h"
 #include "nsDirectoryIndexStream.h"
 #include "nsMimeTypes.h"
 #include "nsReadLine.h"
 #include "nsNetUtil.h"
 #include "nsIClassInfoImpl.h"
+#include "mozilla/ipc/IPCSerializableParams.h"
 
 #define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067
 
+typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType;
+
+using namespace mozilla::ipc;
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsFileStreamBase
 
 nsFileStreamBase::nsFileStreamBase()
     : mFD(nullptr)
     , mBehaviorFlags(0)
     , mDeferredOpen(false)
 {
@@ -281,22 +286,26 @@ nsFileStreamBase::CleanUpOpen()
 {
     mOpenParams.localFile = nullptr;
     mDeferredOpen = false;
 }
 
 nsresult
 nsFileStreamBase::DoOpen()
 {
-    NS_PRECONDITION(mOpenParams.localFile, "Must have a file to open");
+    NS_ASSERTION(!mFD, "Already have a file descriptor!");
+    NS_ASSERTION(mOpenParams.localFile, "Must have a file to open");
 
     PRFileDesc* fd;
-    nsresult rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags, mOpenParams.perm, &fd);
+    nsresult rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags,
+                                                          mOpenParams.perm,
+                                                          &fd);
     CleanUpOpen();
-    if (NS_FAILED(rv)) return rv;
+    if (NS_FAILED(rv))
+        return rv;
     mFD = fd;
 
     return NS_OK;
 }
 
 nsresult
 nsFileStreamBase::DoPendingOpen()
 {
@@ -315,26 +324,26 @@ NS_IMPL_RELEASE_INHERITED(nsFileInputStr
 
 NS_IMPL_CLASSINFO(nsFileInputStream, NULL, nsIClassInfo::THREADSAFE,
                   NS_LOCALFILEINPUTSTREAM_CID)
 
 NS_INTERFACE_MAP_BEGIN(nsFileInputStream)
     NS_INTERFACE_MAP_ENTRY(nsIInputStream)
     NS_INTERFACE_MAP_ENTRY(nsIFileInputStream)
     NS_INTERFACE_MAP_ENTRY(nsILineInputStream)
-    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableObsolete)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
     NS_IMPL_QUERY_CLASSINFO(nsFileInputStream)
 NS_INTERFACE_MAP_END_INHERITING(nsFileStreamBase)
 
-NS_IMPL_CI_INTERFACE_GETTER5(nsFileInputStream,
+NS_IMPL_CI_INTERFACE_GETTER4(nsFileInputStream,
                              nsIInputStream,
                              nsIFileInputStream,
                              nsISeekableStream,
-                             nsILineInputStream,
-                             nsIIPCSerializable)
+                             nsILineInputStream)
 
 nsresult
 nsFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
 {
     NS_ENSURE_NO_AGGREGATION(aOuter);
 
     nsFileInputStream* stream = new nsFileInputStream();
     if (stream == nullptr)
@@ -500,41 +509,111 @@ nsFileInputStream::Write(IPC::Message *a
     mFile->GetNativePath(path);
     WriteParam(aMsg, path);
     bool followLinks;
     mFile->GetFollowLinks(&followLinks);
     WriteParam(aMsg, followLinks);
     WriteParam(aMsg, mBehaviorFlags);
 }
 
+void
+nsFileInputStream::Serialize(InputStreamParams& aParams)
+{
+    FileInputStreamParams params;
+
+    if (mFD) {
+        FileHandleType fd = FileHandleType(PR_FileDesc2NativeHandle(mFD));
+        NS_ASSERTION(fd, "This should never be null!");
+
+        params.file() = FileDescriptor(fd);
+        NS_ASSERTION(params.file().IsValid(),
+                     "Sending an invalid file descriptor!");
+    } else {
+        NS_WARNING("This file has not been opened (or could not be opened). "
+                   "Sending an invalid file descriptor to the other process!");
+    }
+
+    PRInt32 behaviorFlags = mBehaviorFlags;
+
+    // The other process shouldn't close when it reads the end because it will
+    // not be able to reopen the file later.
+    behaviorFlags &= ~nsIFileInputStream::CLOSE_ON_EOF;
+
+    // The other process will not be able to reopen the file so transferring
+    // this flag is meaningless.
+    behaviorFlags &= ~nsIFileInputStream::REOPEN_ON_REWIND;
+
+    // The other process is going to have an open file descriptor automatically
+    // so transferring this flag is meaningless.
+    behaviorFlags &= ~nsIFileInputStream::DEFER_OPEN;
+
+    params.behaviorFlags() = behaviorFlags;
+    params.ioFlags() = mIOFlags;
+
+    aParams = params;
+}
+
+bool
+nsFileInputStream::Deserialize(const InputStreamParams& aParams)
+{
+    NS_ASSERTION(!mFD, "Already have a file descriptor?!");
+    NS_ASSERTION(!mDeferredOpen, "Deferring open?!");
+    NS_ASSERTION(!mFile, "Should never have a file here!");
+    NS_ASSERTION(!mPerm, "This should always be 0!");
+
+    if (aParams.type() != InputStreamParams::TFileInputStreamParams) {
+        NS_WARNING("Received unknown parameters from the other process!");
+        return false;
+    }
+
+    const FileInputStreamParams& params = aParams.get_FileInputStreamParams();
+
+    const FileDescriptor& fd = params.file();
+    NS_WARN_IF_FALSE(fd.IsValid(), "Received an invalid file descriptor!");
+
+    if (fd.IsValid()) {
+        PRFileDesc* fileDesc = PR_ImportFile(PROsfd(fd.PlatformHandle()));
+        if (!fileDesc) {
+            NS_WARNING("Failed to import file handle!");
+            return false;
+        }
+        mFD = fileDesc;
+    }
+
+    mBehaviorFlags = params.behaviorFlags();
+    mIOFlags = params.ioFlags();
+
+    return true;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsPartialFileInputStream
 
 NS_IMPL_ADDREF_INHERITED(nsPartialFileInputStream, nsFileStreamBase)
 NS_IMPL_RELEASE_INHERITED(nsPartialFileInputStream, nsFileStreamBase)
 
 NS_IMPL_CLASSINFO(nsPartialFileInputStream, NULL, nsIClassInfo::THREADSAFE,
                   NS_PARTIALLOCALFILEINPUTSTREAM_CID)
 
 // Don't forward to nsFileInputStream as we don't want to QI to
 // nsIFileInputStream
 NS_INTERFACE_MAP_BEGIN(nsPartialFileInputStream)
     NS_INTERFACE_MAP_ENTRY(nsIInputStream)
     NS_INTERFACE_MAP_ENTRY(nsIPartialFileInputStream)
     NS_INTERFACE_MAP_ENTRY(nsILineInputStream)
-    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableObsolete)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
     NS_IMPL_QUERY_CLASSINFO(nsPartialFileInputStream)
 NS_INTERFACE_MAP_END_INHERITING(nsFileStreamBase)
 
-NS_IMPL_CI_INTERFACE_GETTER5(nsPartialFileInputStream,
+NS_IMPL_CI_INTERFACE_GETTER4(nsPartialFileInputStream,
                              nsIInputStream,
                              nsIPartialFileInputStream,
                              nsISeekableStream,
-                             nsILineInputStream,
-                             nsIIPCSerializable)
+                             nsILineInputStream)
 
 nsresult
 nsPartialFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID,
                                  void **aResult)
 {
     NS_ENSURE_NO_AGGREGATION(aOuter);
 
     nsPartialFileInputStream* stream = new nsPartialFileInputStream();
@@ -675,16 +754,74 @@ nsPartialFileInputStream::Write(IPC::Mes
     if (mPosition) {
       NS_WARNING("No support for sending a partially-consumed input stream!");
     }
 
     // Now run base class serialization.
     nsFileInputStream::Write(aMsg);
 }
 
+void
+nsPartialFileInputStream::Serialize(InputStreamParams& aParams)
+{
+    // Serialize the base class first.
+    InputStreamParams fileParams;
+    nsFileInputStream::Serialize(fileParams);
+
+    if (fileParams.type() != InputStreamParams::TFileInputStreamParams) {
+        NS_ERROR("Base class serialize failed!");
+        return;
+    }
+
+    PartialFileInputStreamParams params;
+
+    params.fileStreamParams() = fileParams.get_FileInputStreamParams();
+    params.begin() = mStart;
+    params.length() = mLength;
+
+    aParams = params;
+}
+
+bool
+nsPartialFileInputStream::Deserialize(const InputStreamParams& aParams)
+{
+    NS_ASSERTION(!mFD, "Already have a file descriptor?!");
+    NS_ASSERTION(!mStart, "Already have a start?!");
+    NS_ASSERTION(!mLength, "Already have a length?!");
+    NS_ASSERTION(!mPosition, "Already have a position?!");
+
+    if (aParams.type() != InputStreamParams::TPartialFileInputStreamParams) {
+        NS_ERROR("Received unknown parameters from the other process!");
+        return false;
+    }
+
+    const PartialFileInputStreamParams& params =
+        aParams.get_PartialFileInputStreamParams();
+
+    // Deserialize the base class first.
+    InputStreamParams fileParams(params.fileStreamParams());
+    if (!nsFileInputStream::Deserialize(fileParams)) {
+        NS_ERROR("Base class deserialize failed!");
+        return false;
+    }
+
+    NS_ASSERTION(mFD, "Must have a file descriptor now!");
+
+    mStart = params.begin();
+    mLength = params.length();
+    mPosition = 0;
+
+    if (!mStart) {
+      return true;
+    }
+
+    // XXX This is so broken. Main thread IO alert.
+    return NS_SUCCEEDED(nsFileInputStream::Seek(NS_SEEK_SET, mStart));
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsFileOutputStream
 
 NS_IMPL_ISUPPORTS_INHERITED2(nsFileOutputStream,
                              nsFileStreamBase,
                              nsIOutputStream,
                              nsIFileOutputStream)
  
--- a/netwerk/base/src/nsFileStreams.h
+++ b/netwerk/base/src/nsFileStreams.h
@@ -12,17 +12,18 @@
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
 #include "nsISeekableStream.h"
 #include "nsILineInputStream.h"
 #include "nsCOMPtr.h"
 #include "prlog.h"
 #include "prio.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableInputStream.h"
+#include "nsIIPCSerializableObsolete.h"
 
 template<class CharType> class nsLineBuffer;
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsFileStreamBase : public nsISeekableStream
 {
 public:
@@ -97,23 +98,25 @@ protected:
     inline nsresult DoPendingOpen();
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsFileInputStream : public nsFileStreamBase,
                           public nsIFileInputStream,
                           public nsILineInputStream,
-                          public nsIIPCSerializable
+                          public nsIIPCSerializableObsolete,
+                          public nsIIPCSerializableInputStream
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIFILEINPUTSTREAM
     NS_DECL_NSILINEINPUTSTREAM
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
+    NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
 
     NS_IMETHOD Close();
     NS_IMETHOD Available(PRUint64* _retval)
     {
         return nsFileStreamBase::Available(_retval);
     }
     NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32* _retval);
     NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
@@ -126,19 +129,21 @@ public:
     {
         return nsFileStreamBase::IsNonBlocking(_retval);
     } 
     
     // Overrided from nsFileStreamBase
     NS_IMETHOD Seek(PRInt32 aWhence, PRInt64 aOffset);
 
     nsFileInputStream()
+      : mIOFlags(0), mPerm(0)
     {
         mLineBuffer = nullptr;
     }
+
     virtual ~nsFileInputStream() 
     {
         Close();
     }
 
     static nsresult
     Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
@@ -174,17 +179,22 @@ protected:
 
 class nsPartialFileInputStream : public nsFileInputStream,
                                  public nsIPartialFileInputStream
 {
 public:
     using nsFileInputStream::Init;
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIPARTIALFILEINPUTSTREAM
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
+    NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
+
+    nsPartialFileInputStream()
+      : mStart(0), mLength(0), mPosition(0)
+    { }
 
     NS_IMETHOD Tell(PRInt64 *aResult);
     NS_IMETHOD Available(PRUint64 *aResult);
     NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32* aResult);
     NS_IMETHOD Seek(PRInt32 aWhence, PRInt64 aOffset);
 
     static nsresult
     Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
--- a/netwerk/base/src/nsMIMEInputStream.cpp
+++ b/netwerk/base/src/nsMIMEInputStream.cpp
@@ -14,32 +14,32 @@
 #include "nsCOMPtr.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsIMIMEInputStream.h"
 #include "nsISeekableStream.h"
 #include "nsIStringStream.h"
 #include "nsString.h"
 #include "nsMIMEInputStream.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableObsolete.h"
 #include "nsIClassInfoImpl.h"
 
 class nsMIMEInputStream : public nsIMIMEInputStream,
                           public nsISeekableStream,
-                          public nsIIPCSerializable
+                          public nsIIPCSerializableObsolete
 {
 public:
     nsMIMEInputStream();
     virtual ~nsMIMEInputStream();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSIMIMEINPUTSTREAM
     NS_DECL_NSISEEKABLESTREAM
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
     
     NS_METHOD Init();
 
 private:
 
     void InitStreams();
 
     struct ReadSegmentsState {
@@ -68,22 +68,22 @@ NS_IMPL_THREADSAFE_RELEASE(nsMIMEInputSt
 
 NS_IMPL_CLASSINFO(nsMIMEInputStream, NULL, nsIClassInfo::THREADSAFE,
                   NS_MIMEINPUTSTREAM_CID)
 
 NS_IMPL_QUERY_INTERFACE4_CI(nsMIMEInputStream,
                             nsIMIMEInputStream,
                             nsIInputStream,
                             nsISeekableStream,
-                            nsIIPCSerializable)
+                            nsIIPCSerializableObsolete)
 NS_IMPL_CI_INTERFACE_GETTER4(nsMIMEInputStream,
                              nsIMIMEInputStream,
                              nsIInputStream,
                              nsISeekableStream,
-                             nsIIPCSerializable)
+                             nsIIPCSerializableObsolete)
 
 nsMIMEInputStream::nsMIMEInputStream() : mAddContentLength(false),
                                          mStartedReading(false)
 {
 }
 
 nsMIMEInputStream::~nsMIMEInputStream()
 {
--- a/netwerk/base/src/nsSimpleNestedURI.cpp
+++ b/netwerk/base/src/nsSimpleNestedURI.cpp
@@ -50,17 +50,17 @@ nsSimpleNestedURI::Write(nsIObjectOutput
     nsresult rv = nsSimpleURI::Write(aStream);
     if (NS_FAILED(rv)) return rv;
 
     rv = aStream->WriteCompoundObject(mInnerURI, NS_GET_IID(nsIURI),
                                       true);
     return rv;
 }
 
-// nsIIPCSerializable
+// nsIIPCSerializableObsolete
 
 bool
 nsSimpleNestedURI::Read(const IPC::Message *aMsg, void **aIter)
 {
     if (!nsSimpleURI::Read(aMsg, aIter))
         return false;
 
     IPC::URI uri;
--- a/netwerk/base/src/nsSimpleNestedURI.h
+++ b/netwerk/base/src/nsSimpleNestedURI.h
@@ -31,17 +31,17 @@ public:
     }
 
     // Constructor that should generally be used when constructing an object of
     // this class with |operator new|.
     nsSimpleNestedURI(nsIURI* innerURI);
 
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSINESTEDURI
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
 
     // Overrides for various methods nsSimpleURI implements follow.
   
     // nsSimpleURI overrides
     virtual nsresult EqualsInternal(nsIURI* other,
                                     RefHandlingEnum refHandlingMode,
                                     bool* result);
     virtual nsSimpleURI* StartClone(RefHandlingEnum refHandlingMode);
--- a/netwerk/base/src/nsSimpleURI.cpp
+++ b/netwerk/base/src/nsSimpleURI.cpp
@@ -36,17 +36,18 @@ nsSimpleURI::nsSimpleURI()
 
 nsSimpleURI::~nsSimpleURI()
 {
 }
 
 NS_IMPL_ADDREF(nsSimpleURI)
 NS_IMPL_RELEASE(nsSimpleURI)
 NS_INTERFACE_TABLE_HEAD(nsSimpleURI)
-NS_INTERFACE_TABLE5(nsSimpleURI, nsIURI, nsISerializable, nsIIPCSerializable, nsIClassInfo, nsIMutable)
+NS_INTERFACE_TABLE5(nsSimpleURI, nsIURI, nsISerializable,
+                    nsIIPCSerializableObsolete, nsIClassInfo, nsIMutable)
 NS_INTERFACE_TABLE_TO_MAP_SEGUE
   if (aIID.Equals(kThisSimpleURIImplementationCID))
     foundInterface = static_cast<nsIURI*>(this);
   else
   NS_INTERFACE_MAP_ENTRY(nsISizeOf)
 NS_INTERFACE_MAP_END
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -112,17 +113,17 @@ nsSimpleURI::Write(nsIObjectOutputStream
         rv = aStream->WriteStringZ(mRef.get());
         if (NS_FAILED(rv)) return rv;
     }
 
     return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// nsIIPCSerializable methods:
+// nsIIPCSerializableObsolete methods:
 
 bool
 nsSimpleURI::Read(const IPC::Message *aMsg, void **aIter)
 {
     bool isMutable, isRefValid;
     if (!ReadParam(aMsg, aIter, &isMutable) ||
         !ReadParam(aMsg, aIter, &mScheme) ||
         !ReadParam(aMsg, aIter, &mPath) ||
--- a/netwerk/base/src/nsSimpleURI.h
+++ b/netwerk/base/src/nsSimpleURI.h
@@ -4,42 +4,42 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsSimpleURI_h__
 #define nsSimpleURI_h__
 
 #include "nsIURL.h"
 #include "nsAgg.h"
 #include "nsISerializable.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableObsolete.h"
 #include "nsString.h"
 #include "nsIClassInfo.h"
 #include "nsIMutable.h"
 #include "nsISizeOf.h"
 
 #define NS_THIS_SIMPLEURI_IMPLEMENTATION_CID         \
 { /* 0b9bb0c2-fee6-470b-b9b9-9fd9462b5e19 */         \
     0x0b9bb0c2,                                      \
     0xfee6,                                          \
     0x470b,                                          \
     {0xb9, 0xb9, 0x9f, 0xd9, 0x46, 0x2b, 0x5e, 0x19} \
 }
 
 class nsSimpleURI : public nsIURI,
                     public nsISerializable,
-                    public nsIIPCSerializable,
+                    public nsIIPCSerializableObsolete,
                     public nsIClassInfo,
                     public nsIMutable,
                     public nsISizeOf
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIURI
     NS_DECL_NSISERIALIZABLE
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
     NS_DECL_NSICLASSINFO
     NS_DECL_NSIMUTABLE
 
     // nsSimpleURI methods:
 
     nsSimpleURI();
     virtual ~nsSimpleURI();
 
--- a/netwerk/base/src/nsStandardURL.cpp
+++ b/netwerk/base/src/nsStandardURL.cpp
@@ -932,17 +932,17 @@ NS_IMPL_RELEASE(nsStandardURL)
 
 NS_INTERFACE_MAP_BEGIN(nsStandardURL)
     NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStandardURL)
     NS_INTERFACE_MAP_ENTRY(nsIURI)
     NS_INTERFACE_MAP_ENTRY(nsIURL)
     NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileURL, mSupportsFileURL)
     NS_INTERFACE_MAP_ENTRY(nsIStandardURL)
     NS_INTERFACE_MAP_ENTRY(nsISerializable)
-    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableObsolete)
     NS_INTERFACE_MAP_ENTRY(nsIClassInfo)
     NS_INTERFACE_MAP_ENTRY(nsIMutable)
     // see nsStandardURL::Equals
     if (aIID.Equals(kThisImplCID))
         foundInterface = static_cast<nsIURI *>(this);
     else
     NS_INTERFACE_MAP_ENTRY(nsISizeOf)
 NS_INTERFACE_MAP_END
@@ -2871,17 +2871,17 @@ nsStandardURL::Write(nsIObjectOutputStre
     if (NS_FAILED(rv)) return rv;
 
     // mSpecEncoding and mHostA are just caches that can be recovered as needed.
 
     return NS_OK;
 }
 
 //---------------------------------------------------------------------------
-// nsStandardURL::nsIIPCSerializable
+// nsStandardURL::nsIIPCSerializableObsolete
 //---------------------------------------------------------------------------
 
 bool
 nsStandardURL::Read(const IPC::Message *aMsg, void **aIter)
 {
     using IPC::ReadParam;
     
     NS_PRECONDITION(!mHostA, "Shouldn't have cached ASCII host");
--- a/netwerk/base/src/nsStandardURL.h
+++ b/netwerk/base/src/nsStandardURL.h
@@ -5,17 +5,17 @@
 
 #ifndef nsStandardURL_h__
 #define nsStandardURL_h__
 
 #include "nsString.h"
 #include "nsDependentString.h"
 #include "nsDependentSubstring.h"
 #include "nsISerializable.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableObsolete.h"
 #include "nsIFileURL.h"
 #include "nsIStandardURL.h"
 #include "nsIFile.h"
 #include "nsIURLParser.h"
 #include "nsIUnicodeEncoder.h"
 #include "nsIObserver.h"
 #include "nsIIOService.h"
 #include "nsCOMPtr.h"
@@ -37,28 +37,28 @@ class nsIPrefBranch;
 
 //-----------------------------------------------------------------------------
 // standard URL implementation
 //-----------------------------------------------------------------------------
 
 class nsStandardURL : public nsIFileURL
                     , public nsIStandardURL
                     , public nsISerializable
-                    , public nsIIPCSerializable
+                    , public nsIIPCSerializableObsolete
                     , public nsIClassInfo
                     , public nsISizeOf
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIURI
     NS_DECL_NSIURL
     NS_DECL_NSIFILEURL
     NS_DECL_NSISTANDARDURL
     NS_DECL_NSISERIALIZABLE
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
     NS_DECL_NSICLASSINFO
     NS_DECL_NSIMUTABLE
 
     // nsISizeOf
     virtual size_t SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
     virtual size_t SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const;
 
     nsStandardURL(bool aSupportsFileURL = false);
--- a/netwerk/ipc/NeckoMessageUtils.h
+++ b/netwerk/ipc/NeckoMessageUtils.h
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_net_NeckoMessageUtils_h
 #define mozilla_net_NeckoMessageUtils_h
 
 #include "IPC/IPCMessageUtils.h"
 #include "nsStringGlue.h"
 #include "nsIURI.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableObsolete.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"
 
@@ -46,17 +46,18 @@ struct ParamTraits<URI>
   
   static void Write(Message* aMsg, const paramType& aParam)
   {
     bool isNull = !aParam.mURI;
     WriteParam(aMsg, isNull);
     if (isNull)
       return;
     
-    nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(aParam.mURI);
+    nsCOMPtr<nsIIPCSerializableObsolete> serializable =
+      do_QueryInterface(aParam.mURI);
     if (!serializable) {
       nsCString scheme;
       aParam.mURI->GetScheme(scheme);
       if (!scheme.EqualsASCII("about:") &&
           !scheme.EqualsASCII("javascript:") &&
           !scheme.EqualsASCII("javascript"))
         NS_WARNING("All IPDL URIs must be serializable or an allowed scheme");
     }
@@ -115,17 +116,17 @@ struct ParamTraits<URI>
     nsCID cid;
     if (!ReadParam(aMsg, aIter, &cidStr) ||
         !cid.Parse(cidStr.get()))
       return false;
 
     nsCOMPtr<nsIURI> uri = do_CreateInstance(cid);
     if (!uri)
       return false;
-    nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(uri);
+    nsCOMPtr<nsIIPCSerializableObsolete> serializable = do_QueryInterface(uri);
     if (!serializable || !serializable->Read(aMsg, aIter))
       return false;
 
     uri.swap(aResult->mURI);
     return true;
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
@@ -165,22 +166,24 @@ struct ParamTraits<InputStream>
   static void Write(Message* aMsg, const paramType& aParam)
   {
     bool isNull = !aParam.mStream;
     aMsg->WriteBool(isNull);
 
     if (isNull)
       return;
 
-    nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(aParam.mStream);
+    nsCOMPtr<nsIIPCSerializableObsolete> serializable =
+      do_QueryInterface(aParam.mStream);
     bool isSerializable = !!serializable;
     WriteParam(aMsg, isSerializable);
 
     if (!serializable) {
-      NS_WARNING("nsIInputStream implementation doesn't support nsIIPCSerializable; falling back to copying data");
+      NS_WARNING("nsIInputStream implementation doesn't support "
+                 "nsIIPCSerializableObsolete; falling back to copying data");
 
       nsCString streamString;
       PRUint64 bytes;
 
       nsresult rv = aParam.mStream->Available(&bytes);
       if (NS_SUCCEEDED(rv) && bytes > 0) {
         // Also, on 64-bit system, for an interoperability for 32-bit process
         // and 64-bit process, we shouldn't handle over 4GB message.
@@ -236,17 +239,18 @@ struct ParamTraits<InputStream>
       nsCID cid;
       if (!ReadParam(aMsg, aIter, &cidStr) ||
           !cid.Parse(cidStr.get()))
         return false;
 
       stream = do_CreateInstance(cid);
       if (!stream)
         return false;
-      nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(stream);
+      nsCOMPtr<nsIIPCSerializableObsolete> serializable =
+        do_QueryInterface(stream);
       if (!serializable || !serializable->Read(aMsg, aIter))
         return false;
     }
 
     stream.swap(aResult->mStream);
     return true;
   }
 };
--- a/netwerk/protocol/about/nsAboutProtocolHandler.cpp
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.cpp
@@ -287,17 +287,17 @@ nsNestedAboutURI::Write(nsIObjectOutputS
         rv = aStream->WriteCompoundObject(mBaseURI, NS_GET_IID(nsISupports),
                                           true);
         if (NS_FAILED(rv)) return rv;
     }
 
     return NS_OK;
 }
 
-// nsIIPCSerializable
+// nsIIPCSerializableObsolete
 bool
 nsNestedAboutURI::Read(const IPC::Message *aMsg, void **aIter)
 {
     if (!nsSimpleNestedURI::Read(aMsg, aIter))
         return false;
 
     IPC::URI uri;
     if (!ReadParam(aMsg, aIter, &uri))
--- a/netwerk/protocol/about/nsAboutProtocolHandler.h
+++ b/netwerk/protocol/about/nsAboutProtocolHandler.h
@@ -40,17 +40,17 @@ public:
 private:
     ~nsSafeAboutProtocolHandler() {}
 };
 
 
 // Class to allow us to propagate the base URI to about:blank correctly
 class nsNestedAboutURI : public nsSimpleNestedURI {
 public:
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
 
     nsNestedAboutURI(nsIURI* aInnerURI, nsIURI* aBaseURI)
         : nsSimpleNestedURI(aInnerURI)
         , mBaseURI(aBaseURI)
     {}
 
     // For use only from deserialization
     nsNestedAboutURI() : nsSimpleNestedURI() {}
--- a/netwerk/protocol/http/PHttpChannelParams.h
+++ b/netwerk/protocol/http/PHttpChannelParams.h
@@ -10,17 +10,16 @@
 #define ALLOW_LATE_NSHTTP_H_INCLUDE 1
 #include "base/basictypes.h"
 
 #include "IPC/IPCMessageUtils.h"
 #include "nsHttp.h"
 #include "nsHttpHeaderArray.h"
 #include "nsHttpResponseHead.h"
 
-#include "nsIIPCSerializable.h"
 #include "nsIClassInfo.h"
 #include "nsNetUtil.h"
 
 namespace mozilla {
 namespace net {
 
 struct RequestHeaderTuple {
   nsCString mHeader;
--- a/xpcom/io/nsMultiplexInputStream.cpp
+++ b/xpcom/io/nsMultiplexInputStream.cpp
@@ -12,31 +12,38 @@
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "mozilla/Attributes.h"
 
 #include "nsMultiplexInputStream.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsISeekableStream.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableObsolete.h"
 #include "nsIClassInfoImpl.h"
+#include "nsIIPCSerializableInputStream.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+#include "mozilla/ipc/IPCSerializableParams.h"
+
+using namespace mozilla::ipc;
 
 class nsMultiplexInputStream MOZ_FINAL : public nsIMultiplexInputStream,
                                          public nsISeekableStream,
-                                         public nsIIPCSerializable
+                                         public nsIIPCSerializableObsolete,
+                                         public nsIIPCSerializableInputStream
 {
 public:
     nsMultiplexInputStream();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSIMULTIPLEXINPUTSTREAM
     NS_DECL_NSISEEKABLESTREAM
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
+    NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
 
 private:
     ~nsMultiplexInputStream() {}
 
     struct ReadSegmentsState {
         nsIInputStream* mThisStream;
         PRUint32 mOffset;
         nsWriteSegmentFun mWriter;
@@ -55,26 +62,26 @@ private:
 };
 
 NS_IMPL_THREADSAFE_ADDREF(nsMultiplexInputStream)
 NS_IMPL_THREADSAFE_RELEASE(nsMultiplexInputStream)
 
 NS_IMPL_CLASSINFO(nsMultiplexInputStream, NULL, nsIClassInfo::THREADSAFE,
                   NS_MULTIPLEXINPUTSTREAM_CID)
 
-NS_IMPL_QUERY_INTERFACE4_CI(nsMultiplexInputStream,
+NS_IMPL_QUERY_INTERFACE5_CI(nsMultiplexInputStream,
                             nsIMultiplexInputStream,
                             nsIInputStream,
                             nsISeekableStream,
-                            nsIIPCSerializable)
-NS_IMPL_CI_INTERFACE_GETTER4(nsMultiplexInputStream,
+                            nsIIPCSerializableObsolete,
+                            nsIIPCSerializableInputStream)
+NS_IMPL_CI_INTERFACE_GETTER3(nsMultiplexInputStream,
                              nsIMultiplexInputStream,
                              nsIInputStream,
-                             nsISeekableStream,
-                             nsIIPCSerializable)
+                             nsISeekableStream)
 
 nsMultiplexInputStream::nsMultiplexInputStream()
     : mCurrentStream(0),
       mStartedReadingCurrent(false),
       mStatus(NS_OK)
 {
 }
 
@@ -442,8 +449,80 @@ nsMultiplexInputStream::Write(IPC::Messa
         IPC::InputStream inputStream(mStreams.ObjectAt(i));
         WriteParam(aMsg, inputStream);
     }
 
     WriteParam(aMsg, mCurrentStream);
     WriteParam(aMsg, mStartedReadingCurrent);
     WriteParam(aMsg, mStatus);
 }
+
+void
+nsMultiplexInputStream::Serialize(InputStreamParams& aParams)
+{
+    MultiplexInputStreamParams params;
+
+    PRUint32 streamCount = mStreams.Count();
+
+    if (streamCount) {
+        InfallibleTArray<InputStreamParams>& streams = params.streams();
+
+        streams.SetCapacity(streamCount);
+        for (PRUint32 index = 0; index < streamCount; index++) {
+            nsCOMPtr<nsIIPCSerializableInputStream> serializable =
+                do_QueryInterface(mStreams.ObjectAt(index));
+            NS_ASSERTION(serializable, "Child stream isn't serializable!");
+
+            if (serializable) {
+                InputStreamParams childStreamParams;
+                serializable->Serialize(childStreamParams);
+
+                NS_ASSERTION(childStreamParams.type() !=
+                                 InputStreamParams::T__None,
+                             "Serialize failed!");
+
+                streams.AppendElement(childStreamParams);
+            }
+        }
+    }
+
+    params.currentStream() = mCurrentStream;
+    params.status() = mStatus;
+    params.startedReadingCurrent() = mStartedReadingCurrent;
+
+    aParams = params;
+}
+
+bool
+nsMultiplexInputStream::Deserialize(const InputStreamParams& aParams)
+{
+    if (aParams.type() !=
+            InputStreamParams::TMultiplexInputStreamParams) {
+        NS_ERROR("Received unknown parameters from the other process!");
+        return false;
+    }
+
+    const MultiplexInputStreamParams& params =
+        aParams.get_MultiplexInputStreamParams();
+
+    const InfallibleTArray<InputStreamParams>& streams = params.streams();
+
+    PRUint32 streamCount = streams.Length();
+    for (PRUint32 index = 0; index < streamCount; index++) {
+        nsCOMPtr<nsIInputStream> stream =
+            DeserializeInputStream(streams[index]);
+        if (!stream) {
+            NS_WARNING("Deserialize failed!");
+            return false;
+        }
+
+        if (NS_FAILED(AppendStream(stream))) {
+            NS_WARNING("AppendStream failed!");
+            return false;
+        }
+    }
+
+    mCurrentStream = params.currentStream();
+    mStatus = params.status();
+    mStartedReadingCurrent = params.startedReadingCurrent();
+
+    return true;
+}
--- a/xpcom/io/nsStringStream.cpp
+++ b/xpcom/io/nsStringStream.cpp
@@ -14,36 +14,42 @@
 #include "nsStreamUtils.h"
 #include "nsReadableUtils.h"
 #include "nsISeekableStream.h"
 #include "nsISupportsPrimitives.h"
 #include "nsCRT.h"
 #include "prerror.h"
 #include "plstr.h"
 #include "nsIClassInfoImpl.h"
-#include "nsIIPCSerializable.h"
+#include "nsIIPCSerializableObsolete.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/ipc/IPCSerializableParams.h"
+#include "nsIIPCSerializableInputStream.h"
+
+using namespace mozilla::ipc;
 
 //-----------------------------------------------------------------------------
 // nsIStringInputStream implementation
 //-----------------------------------------------------------------------------
 
 class nsStringInputStream MOZ_FINAL : public nsIStringInputStream
                                     , public nsISeekableStream
                                     , public nsISupportsCString
-                                    , public nsIIPCSerializable
+                                    , public nsIIPCSerializableObsolete
+                                    , public nsIIPCSerializableInputStream
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSISTRINGINPUTSTREAM
     NS_DECL_NSISEEKABLESTREAM
     NS_DECL_NSISUPPORTSPRIMITIVE
     NS_DECL_NSISUPPORTSCSTRING
-    NS_DECL_NSIIPCSERIALIZABLE
+    NS_DECL_NSIIPCSERIALIZABLEOBSOLETE
+    NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
 
     nsStringInputStream()
     {
         Clear();
     }
 
 private:
     ~nsStringInputStream()
@@ -75,28 +81,28 @@ private:
 
 // This class needs to support threadsafe refcounting since people often
 // allocate a string stream, and then read it from a background thread.
 NS_IMPL_THREADSAFE_ADDREF(nsStringInputStream)
 NS_IMPL_THREADSAFE_RELEASE(nsStringInputStream)
 
 NS_IMPL_CLASSINFO(nsStringInputStream, NULL, nsIClassInfo::THREADSAFE,
                   NS_STRINGINPUTSTREAM_CID)
-NS_IMPL_QUERY_INTERFACE5_CI(nsStringInputStream,
+NS_IMPL_QUERY_INTERFACE6_CI(nsStringInputStream,
                             nsIStringInputStream,
                             nsIInputStream,
                             nsISupportsCString,
                             nsISeekableStream,
-                            nsIIPCSerializable)
-NS_IMPL_CI_INTERFACE_GETTER5(nsStringInputStream,
+                            nsIIPCSerializableObsolete,
+                            nsIIPCSerializableInputStream)
+NS_IMPL_CI_INTERFACE_GETTER4(nsStringInputStream,
                              nsIStringInputStream,
                              nsIInputStream,
                              nsISupportsCString,
-                             nsISeekableStream,
-                             nsIIPCSerializable)
+                             nsISeekableStream)
 
 /////////
 // nsISupportsCString implementation
 /////////
 
 NS_IMETHODIMP
 nsStringInputStream::GetType(PRUint16 *type)
 {
@@ -283,17 +289,17 @@ nsStringInputStream::SetEOF()
     if (Closed())
         return NS_BASE_STREAM_CLOSED;
 
     mOffset = Length();
     return NS_OK;
 }
 
 /////////
-// nsIIPCSerializable implementation
+// nsIIPCSerializableObsolete implementation
 /////////
 
 bool
 nsStringInputStream::Read(const IPC::Message *aMsg, void **aIter)
 {
     using IPC::ReadParam;
 
     nsCString value;
@@ -311,16 +317,43 @@ nsStringInputStream::Read(const IPC::Mes
 void
 nsStringInputStream::Write(IPC::Message *aMsg)
 {
     using IPC::WriteParam;
 
     WriteParam(aMsg, static_cast<const nsCString&>(PromiseFlatCString(mData)));
 }
 
+void
+nsStringInputStream::Serialize(InputStreamParams& aParams)
+{
+    StringInputStreamParams params;
+    params.data() = PromiseFlatCString(mData);
+    aParams = params;
+}
+
+bool
+nsStringInputStream::Deserialize(const InputStreamParams& aParams)
+{
+    if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
+        NS_ERROR("Received unknown parameters from the other process!");
+        return false;
+    }
+
+    const StringInputStreamParams& params =
+        aParams.get_StringInputStreamParams();
+
+    if (NS_FAILED(SetData(params.data()))) {
+        NS_WARNING("SetData failed!");
+        return false;
+    }
+
+    return true;
+}
+
 nsresult
 NS_NewByteInputStream(nsIInputStream** aStreamResult,
                       const char* aStringToRead, PRInt32 aLength,
                       nsAssignmentType aAssignment)
 {
     NS_PRECONDITION(aStreamResult, "null out ptr");
 
     nsStringInputStream* stream = new nsStringInputStream();