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 102870 418b5cbc7cd9f259d950526cb450881d4d6d4a1e
parent 102869 da866a8a19e384f197d62109d03fd5be32b3d9ef
child 102871 858ab0d138a068ef69faa34a1af80761a4dbb74d
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewerskhuey
bugs781256
milestone17.0a1
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();