Bug 1274343 - Add parent-to-child pipe streaming to IPCStream - part 2 - PParentToChild, r=smuag
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 14 Mar 2017 12:29:43 +0100
changeset 347587 cce5031e6ac46ae4a9b91a2a7667a7a0ad922c3b
parent 347586 9a43ac75dfca73751f1da1272fb797f771c9c300
child 347588 51bffdbb6a3066eab6b8502fef84c018038d9533
push id31500
push userkwierso@gmail.com
push dateWed, 15 Mar 2017 00:19:11 +0000
treeherdermozilla-central@8dd496fd015a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmuag
bugs1274343
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1274343 - Add parent-to-child pipe streaming to IPCStream - part 2 - PParentToChild, r=smuag
dom/cache/CacheOpParent.cpp
dom/cache/CacheStreamControlParent.cpp
dom/cache/PCache.ipdl
dom/cache/PCacheOp.ipdl
dom/cache/PCacheStorage.ipdl
dom/cache/TypeUtils.cpp
dom/cache/TypeUtils.h
dom/fetch/InternalResponse.cpp
dom/file/ipc/PBlob.ipdl
dom/flyweb/PFlyWebPublishedServer.ipdl
dom/ipc/ContentBridgeChild.cpp
dom/ipc/ContentBridgeChild.h
dom/ipc/ContentBridgeParent.cpp
dom/ipc/ContentBridgeParent.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/DOMTypes.ipdlh
dom/ipc/PContent.ipdl
dom/ipc/PContentBridge.ipdl
dom/ipc/nsIContentChild.cpp
dom/ipc/nsIContentChild.h
dom/ipc/nsIContentParent.cpp
dom/ipc/nsIContentParent.h
dom/network/PUDPSocket.ipdl
dom/webbrowserpersist/PWebBrowserPersistDocument.ipdl
ipc/glue/BackgroundChildImpl.cpp
ipc/glue/BackgroundChildImpl.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/IPCStream.ipdlh
ipc/glue/IPCStreamAlloc.h
ipc/glue/IPCStreamChild.cpp
ipc/glue/IPCStreamDestination.cpp
ipc/glue/IPCStreamDestination.h
ipc/glue/IPCStreamParent.cpp
ipc/glue/IPCStreamSource.cpp
ipc/glue/IPCStreamSource.h
ipc/glue/IPCStreamUtils.cpp
ipc/glue/IPCStreamUtils.h
ipc/glue/MessageLink.cpp
ipc/glue/PBackground.ipdl
ipc/glue/PChildToParentStream.ipdl
ipc/glue/PParentToChildStream.ipdl
ipc/glue/SendStream.h
ipc/glue/SendStreamAlloc.h
ipc/glue/SendStreamChild.cpp
ipc/glue/SendStreamParent.cpp
ipc/glue/moz.build
netwerk/ipc/PNecko.ipdl
netwerk/protocol/websocket/PWebSocket.ipdl
--- a/dom/cache/CacheOpParent.cpp
+++ b/dom/cache/CacheOpParent.cpp
@@ -7,25 +7,23 @@
 #include "mozilla/dom/cache/CacheOpParent.h"
 
 #include "mozilla/Unused.h"
 #include "mozilla/dom/cache/AutoUtils.h"
 #include "mozilla/dom/cache/ReadStream.h"
 #include "mozilla/dom/cache/SavedTypes.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/ipc/SendStream.h"
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 using mozilla::ipc::FileDescriptorSetParent;
 using mozilla::ipc::PBackgroundParent;
-using mozilla::ipc::SendStreamParent;
 
 CacheOpParent::CacheOpParent(PBackgroundParent* aIpcManager, CacheId aCacheId,
                              const CacheOpArgs& aOpArgs)
   : mIpcManager(aIpcManager)
   , mCacheId(aCacheId)
   , mNamespace(INVALID_NAMESPACE)
   , mOpArgs(aOpArgs)
 {
--- a/dom/cache/CacheStreamControlParent.cpp
+++ b/dom/cache/CacheStreamControlParent.cpp
@@ -55,18 +55,21 @@ CacheStreamControlParent::SerializeContr
 void
 CacheStreamControlParent::SerializeStream(CacheReadStream* aReadStreamOut,
                                           nsIInputStream* aStream,
                                           nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
   MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
   MOZ_DIAGNOSTIC_ASSERT(aStream);
+
   UniquePtr<AutoIPCStream> autoStream(new AutoIPCStream(aReadStreamOut->stream()));
-  autoStream->Serialize(aStream, Manager());
+  bool ok = autoStream->Serialize(aStream, Manager());
+  MOZ_DIAGNOSTIC_ASSERT(ok);
+
   aStreamCleanupList.AppendElement(Move(autoStream));
 }
 
 void
 CacheStreamControlParent::NoteClosedAfterForget(const nsID& aId)
 {
   NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
   RecvNoteClosed(aId);
--- a/dom/cache/PCache.ipdl
+++ b/dom/cache/PCache.ipdl
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBackground;
 include protocol PBlob; // FIXME: bug 792908
 include protocol PCacheOp;
 include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
 include protocol PChildToParentStream;
+include protocol PParentToChildStream;
 
 include CacheTypes;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 protocol PCache
--- a/dom/cache/PCacheOp.ipdl
+++ b/dom/cache/PCacheOp.ipdl
@@ -2,16 +2,17 @@
  * 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 PCache;
 include protocol PCacheStorage;
 include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
 include protocol PChildToParentStream;
+include protocol PParentToChildStream;
 
 include CacheTypes;
 
 using mozilla::ErrorResult from "ipc/ErrorIPCUtils.h";
 
 namespace mozilla {
 namespace dom {
 namespace cache {
--- a/dom/cache/PCacheStorage.ipdl
+++ b/dom/cache/PCacheStorage.ipdl
@@ -4,16 +4,17 @@
 
 include protocol PBackground;
 include protocol PBlob; // FIXME: bug 792908
 include protocol PCache;
 include protocol PCacheOp;
 include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
 include protocol PChildToParentStream;
+include protocol PParentToChildStream;
 
 include CacheTypes;
 
 namespace mozilla {
 namespace dom {
 namespace cache {
 
 protocol PCacheStorage
--- a/dom/cache/TypeUtils.cpp
+++ b/dom/cache/TypeUtils.cpp
@@ -12,17 +12,16 @@
 #include "mozilla/dom/Request.h"
 #include "mozilla/dom/Response.h"
 #include "mozilla/dom/cache/CacheTypes.h"
 #include "mozilla/dom/cache/ReadStream.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PFileDescriptorSetChild.h"
 #include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/ipc/SendStream.h"
 #include "nsCOMPtr.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIIPCSerializableInputStream.h"
 #include "nsQueryObject.h"
 #include "nsPromiseFlatString.h"
 #include "nsStreamUtils.h"
 #include "nsString.h"
--- a/dom/cache/TypeUtils.h
+++ b/dom/cache/TypeUtils.h
@@ -15,17 +15,16 @@
 class nsIGlobalObject;
 class nsIAsyncInputStream;
 class nsIInputStream;
 
 namespace mozilla {
 
 namespace ipc {
 class PBackgroundChild;
-class SendStreamChild;
 class AutoIPCStream;
 }
 
 namespace dom {
 
 struct CacheQueryOptions;
 class InternalRequest;
 class InternalResponse;
--- a/dom/fetch/InternalResponse.cpp
+++ b/dom/fetch/InternalResponse.cpp
@@ -75,19 +75,19 @@ InternalResponse::FromIPC(const IPCInter
   return response.forget();
 }
 
 InternalResponse::~InternalResponse()
 {
 }
 
 template void
-InternalResponse::ToIPC<PContentParent>
+InternalResponse::ToIPC<nsIContentParent>
   (IPCInternalResponse* aIPCResponse,
-   PContentParent* aManager,
+   nsIContentParent* aManager,
    UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
 template void
 InternalResponse::ToIPC<nsIContentChild>
   (IPCInternalResponse* aIPCResponse,
    nsIContentChild* aManager,
    UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
 template void
 InternalResponse::ToIPC<mozilla::ipc::PBackgroundParent>
@@ -122,17 +122,18 @@ InternalResponse::ToIPC(IPCInternalRespo
   }
 
   nsCOMPtr<nsIInputStream> body;
   int64_t bodySize;
   GetUnfilteredBody(getter_AddRefs(body), &bodySize);
 
   if (body) {
     aAutoStream.reset(new mozilla::ipc::AutoIPCStream(aIPCResponse->body()));
-    aAutoStream->Serialize(body, aManager);
+    bool ok = aAutoStream->Serialize(body, aManager);
+    MOZ_DIAGNOSTIC_ASSERT(ok);
   } else {
     aIPCResponse->body() = void_t();
   }
 
   aIPCResponse->bodySize() = bodySize;
 }
 
 already_AddRefed<InternalResponse>
--- a/dom/file/ipc/PBlob.ipdl
+++ b/dom/file/ipc/PBlob.ipdl
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBackground;
 include protocol PBlobStream;
 include protocol PContent;
 include protocol PContentBridge;
 include protocol PFileDescriptorSet;
 include protocol PChildToParentStream;
+include protocol PParentToChildStream;
 
 include BlobTypes;
 include DOMTypes;
 include InputStreamParams;
 
 namespace mozilla {
 namespace dom {
 
--- a/dom/flyweb/PFlyWebPublishedServer.ipdl
+++ b/dom/flyweb/PFlyWebPublishedServer.ipdl
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set sw=2 ts=8 et ft=cpp : */
 /* 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 PContent;
 include protocol PChildToParentStream;
+include protocol PParentToChildStream;
 include protocol PFileDescriptorSet;
 include protocol PTransportProvider;
 include FetchTypes;
 include ChannelInfo;
 include PBackgroundSharedTypes;
 
 namespace mozilla {
 namespace dom {
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -175,16 +175,28 @@ ContentBridgeChild::AllocPChildToParentS
 }
 
 bool
 ContentBridgeChild::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
 {
   return nsIContentChild::DeallocPChildToParentStreamChild(aActor);
 }
 
+PParentToChildStreamChild*
+ContentBridgeChild::AllocPParentToChildStreamChild()
+{
+  return nsIContentChild::AllocPParentToChildStreamChild();
+}
+
+bool
+ContentBridgeChild::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
+{
+  return nsIContentChild::DeallocPParentToChildStreamChild(aActor);
+}
+
 PFileDescriptorSetChild*
 ContentBridgeChild::AllocPFileDescriptorSetChild(const FileDescriptor& aFD)
 {
   return nsIContentChild::AllocPFileDescriptorSetChild(aFD);
 }
 
 bool
 ContentBridgeChild::DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor)
--- a/dom/ipc/ContentBridgeChild.h
+++ b/dom/ipc/ContentBridgeChild.h
@@ -76,16 +76,21 @@ protected:
   virtual bool DeallocPBlobChild(PBlobChild*) override;
 
   virtual mozilla::ipc::PChildToParentStreamChild*
   AllocPChildToParentStreamChild() override;
 
   virtual bool
   DeallocPChildToParentStreamChild(mozilla::ipc::PChildToParentStreamChild* aActor) override;
 
+  virtual PParentToChildStreamChild* AllocPParentToChildStreamChild() override;
+
+  virtual bool
+  DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor) override;
+
   virtual PFileDescriptorSetChild*
   AllocPFileDescriptorSetChild(const mozilla::ipc::FileDescriptor& aFD) override;
 
   virtual bool
   DeallocPFileDescriptorSetChild(mozilla::ipc::PFileDescriptorSetChild* aActor) override;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentBridgeChild);
 
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -105,16 +105,22 @@ ContentBridgeParent::SendPBrowserConstru
   return PContentBridgeParent::SendPBrowserConstructor(aActor,
                                                        aTabId,
                                                        aContext,
                                                        aChromeFlags,
                                                        aCpID,
                                                        aIsForBrowser);
 }
 
+PParentToChildStreamParent*
+ContentBridgeParent::SendPParentToChildStreamConstructor(PParentToChildStreamParent* aActor)
+{
+  return PContentBridgeParent::SendPParentToChildStreamConstructor(aActor);
+}
+
 PBlobParent*
 ContentBridgeParent::AllocPBlobParent(const BlobConstructorParams& aParams)
 {
   return nsIContentParent::AllocPBlobParent(aParams);
 }
 
 bool
 ContentBridgeParent::DeallocPBlobParent(PBlobParent* aActor)
@@ -182,16 +188,22 @@ ContentBridgeParent::Observe(nsISupports
 {
   if (!strcmp(aTopic, "content-child-shutdown")) {
     Close();
   }
   return NS_OK;
 }
 
 PFileDescriptorSetParent*
+ContentBridgeParent::SendPFileDescriptorSetConstructor(const FileDescriptor& aFD)
+{
+  return PContentBridgeParent::SendPFileDescriptorSetConstructor(aFD);
+}
+
+PFileDescriptorSetParent*
 ContentBridgeParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD)
 {
   return nsIContentParent::AllocPFileDescriptorSetParent(aFD);
 }
 
 bool
 ContentBridgeParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor)
 {
@@ -205,10 +217,22 @@ ContentBridgeParent::AllocPChildToParent
 }
 
 bool
 ContentBridgeParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
 {
   return nsIContentParent::DeallocPChildToParentStreamParent(aActor);
 }
 
+PParentToChildStreamParent*
+ContentBridgeParent::AllocPParentToChildStreamParent()
+{
+  return nsIContentParent::AllocPParentToChildStreamParent();
+}
+
+bool
+ContentBridgeParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor)
+{
+  return nsIContentParent::DeallocPParentToChildStreamParent(aActor);
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/ContentBridgeParent.h
+++ b/dom/ipc/ContentBridgeParent.h
@@ -40,16 +40,19 @@ public:
   virtual PBrowserParent*
   SendPBrowserConstructor(PBrowserParent* aActor,
                           const TabId& aTabId,
                           const IPCTabContext& aContext,
                           const uint32_t& aChromeFlags,
                           const ContentParentId& aCpID,
                           const bool& aIsForBrowser) override;
 
+  virtual PFileDescriptorSetParent*
+  SendPFileDescriptorSetConstructor(const FileDescriptor&) override;
+
   FORWARD_SHMEM_ALLOCATOR_TO(PContentBridgeParent)
 
   jsipc::CPOWManager* GetCPOWManager() override;
 
   virtual ContentParentId ChildID() const override
   {
     return mChildID;
   }
@@ -58,16 +61,19 @@ public:
     return mIsForBrowser;
   }
   virtual int32_t Pid() const override
   {
     // XXX: do we need this for ContentBridgeParent?
     return -1;
   }
 
+  virtual mozilla::ipc::PParentToChildStreamParent*
+  SendPParentToChildStreamConstructor(mozilla::ipc::PParentToChildStreamParent*) override;
+
 protected:
   virtual ~ContentBridgeParent();
 
   void SetChildID(ContentParentId aId)
   {
     mChildID = aId;
   }
 
@@ -114,16 +120,22 @@ protected:
 
   virtual bool DeallocPBlobParent(PBlobParent*) override;
 
   virtual PChildToParentStreamParent* AllocPChildToParentStreamParent() override;
 
   virtual bool
   DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) override;
 
+  virtual mozilla::ipc::PParentToChildStreamParent*
+  AllocPParentToChildStreamParent() override;
+
+  virtual bool
+  DeallocPParentToChildStreamParent(mozilla::ipc::PParentToChildStreamParent* aActor) override;
+
   virtual PFileDescriptorSetParent*
   AllocPFileDescriptorSetParent(const mozilla::ipc::FileDescriptor&) override;
 
   virtual bool
   DeallocPFileDescriptorSetParent(PFileDescriptorSetParent*) override;
 
   DISALLOW_EVIL_CONSTRUCTORS(ContentBridgeParent);
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1725,16 +1725,28 @@ ContentChild::AllocPChildToParentStreamC
 }
 
 bool
 ContentChild::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
 {
   return nsIContentChild::DeallocPChildToParentStreamChild(aActor);
 }
 
+PParentToChildStreamChild*
+ContentChild::AllocPParentToChildStreamChild()
+{
+  return nsIContentChild::AllocPParentToChildStreamChild();
+}
+
+bool
+ContentChild::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
+{
+  return nsIContentChild::DeallocPParentToChildStreamChild(aActor);
+}
+
 PScreenManagerChild*
 ContentChild::AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
                                        float* aSystemDefaultScale,
                                        bool* aSuccess)
 {
   // The ContentParent should never attempt to allocate the
   // nsScreenManagerProxy. Instead, the nsScreenManagerProxy
   // service is requested and instantiated via XPCOM, and the
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -234,16 +234,19 @@ public:
   virtual bool DeallocPPrintingChild(PPrintingChild*) override;
 
   virtual PChildToParentStreamChild*
   SendPChildToParentStreamConstructor(PChildToParentStreamChild*) override;
 
   virtual PChildToParentStreamChild* AllocPChildToParentStreamChild() override;
   virtual bool DeallocPChildToParentStreamChild(PChildToParentStreamChild*) override;
 
+  virtual PParentToChildStreamChild* AllocPParentToChildStreamChild() override;
+  virtual bool DeallocPParentToChildStreamChild(PParentToChildStreamChild*) override;
+
   virtual PScreenManagerChild*
   AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
                            float* aSystemDefaultScale,
                            bool* aSuccess) override;
 
   virtual bool DeallocPScreenManagerChild(PScreenManagerChild*) override;
 
   virtual PPSMContentDownloaderChild*
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3183,16 +3183,34 @@ ContentParent::AllocPChildToParentStream
 }
 
 bool
 ContentParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
 {
   return nsIContentParent::DeallocPChildToParentStreamParent(aActor);
 }
 
+PParentToChildStreamParent*
+ContentParent::SendPParentToChildStreamConstructor(PParentToChildStreamParent* aActor)
+{
+  return PContentParent::SendPParentToChildStreamConstructor(aActor);
+}
+
+PParentToChildStreamParent*
+ContentParent::AllocPParentToChildStreamParent()
+{
+  return nsIContentParent::AllocPParentToChildStreamParent();
+}
+
+bool
+ContentParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor)
+{
+  return nsIContentParent::DeallocPParentToChildStreamParent(aActor);
+}
+
 PScreenManagerParent*
 ContentParent::AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
                                          float* aSystemDefaultScale,
                                          bool* aSuccess)
 {
   return new ScreenManagerParent(aNumberOfScreens, aSystemDefaultScale, aSuccess);
 }
 
@@ -3916,17 +3934,20 @@ ContentParent::RecvKeywordToURI(const ns
 
   if (NS_FAILED(fixup->KeywordToURI(aKeyword, getter_AddRefs(postData),
                                     getter_AddRefs(info)))) {
     return IPC_OK();
   }
   info->GetKeywordProviderName(*aProviderName);
 
   AutoIPCStream autoStream;
-  autoStream.Serialize(postData, this);
+  if (NS_WARN_IF(!autoStream.Serialize(postData, this))) {
+    NS_ENSURE_SUCCESS(NS_ERROR_FAILURE, IPC_FAIL_NO_REASON(this));
+  }
+
   *aPostData = autoStream.TakeOptionalValue();
 
   nsCOMPtr<nsIURI> uri;
   info->GetPreferredURI(getter_AddRefs(uri));
   SerializeURI(uri, *aURI);
   return IPC_OK();
 }
 
@@ -4106,16 +4127,22 @@ ContentParent::RecvKeygenProvideContent(
   }
 
   formProcessor->ProvideContent(NS_LITERAL_STRING("SELECT"), *aContent,
                                 *aAttribute);
   return IPC_OK();
 }
 
 PFileDescriptorSetParent*
+ContentParent::SendPFileDescriptorSetConstructor(const FileDescriptor& aFD)
+{
+  return PContentParent::SendPFileDescriptorSetConstructor(aFD);
+}
+
+PFileDescriptorSetParent*
 ContentParent::AllocPFileDescriptorSetParent(const FileDescriptor& aFD)
 {
   return nsIContentParent::AllocPFileDescriptorSetParent(aFD);
 }
 
 bool
 ContentParent::DeallocPFileDescriptorSetParent(PFileDescriptorSetParent* aActor)
 {
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -424,16 +424,26 @@ public:
    */
   already_AddRefed<embedding::PrintingParent> GetPrintingParent();
 #endif
 
   virtual PChildToParentStreamParent* AllocPChildToParentStreamParent() override;
   virtual bool
   DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) override;
 
+  virtual PParentToChildStreamParent*
+  SendPParentToChildStreamConstructor(PParentToChildStreamParent*) override;
+
+  virtual PFileDescriptorSetParent*
+  SendPFileDescriptorSetConstructor(const FileDescriptor&) override;
+
+  virtual PParentToChildStreamParent* AllocPParentToChildStreamParent() override;
+  virtual bool
+  DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor) override;
+
   virtual PScreenManagerParent*
   AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
                             float* aSystemDefaultScale,
                             bool* aSuccess) override;
 
   virtual bool
   DeallocPScreenManagerParent(PScreenManagerParent* aActor) override;
 
--- a/dom/ipc/DOMTypes.ipdlh
+++ b/dom/ipc/DOMTypes.ipdlh
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
 /* 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 protocol PChildToParentStream;
+include protocol PParentToChildStream;
 include IPCStream;
 include ProtocolTypes;
 
 using struct mozilla::void_t
   from "ipc/IPCMessageUtils.h";
 
 using struct mozilla::SerializedStructuredCloneBuffer
   from "ipc/IPCMessageUtils.h";
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -22,16 +22,17 @@ include protocol PImageBridge;
 include protocol PMedia;
 include protocol PNecko;
 include protocol PGMPContent;
 include protocol PGMPService;
 include protocol PPluginModule;
 include protocol PGMP;
 include protocol PPrinting;
 include protocol PChildToParentStream;
+include protocol PParentToChildStream;
 include protocol POfflineCacheUpdate;
 include protocol PRenderFrame;
 include protocol PScreenManager;
 include protocol PSpeechSynthesis;
 include protocol PStorage;
 include protocol PTestShell;
 include protocol PJavaScript;
 include protocol PRemoteSpellcheckEngine;
@@ -282,16 +283,17 @@ nested(upto inside_cpow) sync protocol P
     manages PHal;
     manages PHandlerService;
     manages PHeapSnapshotTempFileHelper;
     manages PMedia;
     manages PNecko;
     manages POfflineCacheUpdate;
     manages PPrinting;
     manages PChildToParentStream;
+    manages PParentToChildStream;
     manages PScreenManager;
     manages PSpeechSynthesis;
     manages PStorage;
     manages PTestShell;
     manages PJavaScript;
     manages PRemoteSpellcheckEngine;
     manages PWebBrowserPersistDocument;
     manages PWebrtcGlobal;
@@ -582,16 +584,18 @@ child:
      * Sending an activate message moves focus to the child.
      */
     async Activate(PBrowser aTab);
 
     async Deactivate(PBrowser aTab);
 
     async ParentActivated(PBrowser aTab, bool aActivated);
 
+    async PParentToChildStream();
+
 parent:
     async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
 
     sync CreateChildProcess(IPCTabContext context,
                             ProcessPriority priority,
                             TabId openerTabId)
         returns (ContentParentId cpId, bool isForBrowser, TabId tabId);
     sync BridgeToChildProcess(ContentParentId cpId)
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBlob;
 include protocol PBrowser;
 include protocol PContent;
 include protocol PJavaScript;
 include protocol PFileDescriptorSet;
 include protocol PChildToParentStream;
+include protocol PParentToChildStream;
 
 include DOMTypes;
 include JavaScriptTypes;
 include PTabContext;
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using mozilla::dom::TabId from "mozilla/dom/ipc/IdType.h";
 using mozilla::dom::ContentParentId from "mozilla/dom/ipc/IdType.h";
@@ -34,16 +35,20 @@ namespace dom {
  */
 nested(upto inside_cpow) sync protocol PContentBridge
 {
     manages PBlob;
     manages PBrowser;
     manages PFileDescriptorSet;
     manages PJavaScript;
     manages PChildToParentStream;
+    manages PParentToChildStream;
+
+child:
+    async PParentToChildStream();
 
 parent:
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
     async PJavaScript();
 
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -10,17 +10,21 @@
 #include "mozilla/dom/DOMTypes.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/TabChild.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/InputStreamUtils.h"
-#include "mozilla/ipc/SendStream.h"
+#include "mozilla/ipc/IPCStreamAlloc.h"
+#include "mozilla/ipc/IPCStreamDestination.h"
+#include "mozilla/ipc/IPCStreamSource.h"
+#include "mozilla/ipc/PChildToParentStreamChild.h"
+#include "mozilla/ipc/PParentToChildStreamChild.h"
 
 #include "nsPrintfCString.h"
 #include "xpcpublic.h"
 
 using namespace mozilla::ipc;
 using namespace mozilla::jsipc;
 
 namespace mozilla {
@@ -143,16 +147,29 @@ nsIContentChild::AllocPChildToParentStre
 
 bool
 nsIContentChild::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
 {
   delete aActor;
   return true;
 }
 
+PParentToChildStreamChild*
+nsIContentChild::AllocPParentToChildStreamChild()
+{
+  return mozilla::ipc::AllocPParentToChildStreamChild();
+}
+
+bool
+nsIContentChild::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
 PFileDescriptorSetChild*
 nsIContentChild::AllocPFileDescriptorSetChild(const FileDescriptor& aFD)
 {
   return new FileDescriptorSetChild(aFD);
 }
 
 bool
 nsIContentChild::DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor)
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -25,16 +25,17 @@ namespace IPC {
 class Principal;
 } // namespace IPC
 
 namespace mozilla {
 namespace ipc {
 class FileDescriptor;
 class PFileDescriptorSetChild;
 class PChildToParentStreamChild;
+class PParentToChildStreamChild;
 class Shmem;
 } // namespace ipc
 
 namespace jsipc {
 class PJavaScriptChild;
 class CpowEntry;
 } // namespace jsipc
 
@@ -99,16 +100,21 @@ protected:
 
   virtual bool DeallocPBlobChild(PBlobChild* aActor);
 
   virtual mozilla::ipc::PChildToParentStreamChild* AllocPChildToParentStreamChild();
 
   virtual bool
   DeallocPChildToParentStreamChild(mozilla::ipc::PChildToParentStreamChild* aActor);
 
+  virtual mozilla::ipc::PParentToChildStreamChild* AllocPParentToChildStreamChild();
+
+  virtual bool
+  DeallocPParentToChildStreamChild(mozilla::ipc::PParentToChildStreamChild* aActor);
+
   virtual mozilla::ipc::PFileDescriptorSetChild*
   AllocPFileDescriptorSetChild(const mozilla::ipc::FileDescriptor& aFD);
 
   virtual bool
   DeallocPFileDescriptorSetChild(mozilla::ipc::PFileDescriptorSetChild* aActor);
 
   virtual mozilla::ipc::IPCResult RecvAsyncMessage(const nsString& aMsg,
                                                    InfallibleTArray<jsipc::CpowEntry>&& aCpows,
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -13,17 +13,19 @@
 #include "mozilla/dom/PTabContext.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/PFileDescriptorSetParent.h"
-#include "mozilla/ipc/SendStreamAlloc.h"
+#include "mozilla/ipc/IPCStreamAlloc.h"
+#include "mozilla/ipc/IPCStreamDestination.h"
+#include "mozilla/ipc/IPCStreamSource.h"
 #include "mozilla/Unused.h"
 
 #include "nsFrameMessageManager.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsPrintfCString.h"
 #include "xpcpublic.h"
 
 using namespace mozilla::jsipc;
@@ -268,16 +270,29 @@ nsIContentParent::AllocPChildToParentStr
 
 bool
 nsIContentParent::DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+PParentToChildStreamParent*
+nsIContentParent::AllocPParentToChildStreamParent()
+{
+  MOZ_CRASH("PParentToChildStreamChild actors should be manually constructed!");
+}
+
+bool
+nsIContentParent::DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
 mozilla::ipc::IPCResult
 nsIContentParent::RecvAsyncMessage(const nsString& aMsg,
                                    InfallibleTArray<CpowEntry>&& aCpows,
                                    const IPC::Principal& aPrincipal,
                                    const ClonedMessageData& aData)
 {
   CrossProcessCpowHolder cpows(this, aCpows);
   RefPtr<nsFrameMessageManager> ppm = mMessageManager;
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -5,16 +5,18 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_nsIContentParent_h
 #define mozilla_dom_nsIContentParent_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/ipc/IdType.h"
 #include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/ipc/PChildToParentStreamParent.h"
+#include "mozilla/ipc/PParentToChildStreamParent.h"
 
 #include "nsFrameMessageManager.h"
 #include "nsISupports.h"
 #include "mozilla/dom/CPOWManagerGetter.h"
 
 #define NS_ICONTENTPARENT_IID                                   \
   { 0xeeec9ebf, 0x8ecf, 0x4e38,                                 \
     { 0x81, 0xda, 0xb7, 0x34, 0x13, 0x7e, 0xac, 0xf3 } }
@@ -28,16 +30,17 @@ namespace mozilla {
 namespace jsipc {
 class PJavaScriptParent;
 class CpowEntry;
 } // namespace jsipc
 
 namespace ipc {
 class PFileDescriptorSetParent;
 class PChildToParentStreamParent;
+class PParentToChildStreamParent;
 }
 
 namespace dom {
 
 class Blob;
 class BlobConstructorParams;
 class BlobImpl;
 class BlobParent;
@@ -70,28 +73,34 @@ public:
   MOZ_MUST_USE virtual PBrowserParent*
   SendPBrowserConstructor(PBrowserParent* actor,
                           const TabId& aTabId,
                           const IPCTabContext& context,
                           const uint32_t& chromeFlags,
                           const ContentParentId& aCpId,
                           const bool& aIsForBrowser) = 0;
 
+  virtual mozilla::ipc::PFileDescriptorSetParent*
+  SendPFileDescriptorSetConstructor(const mozilla::ipc::FileDescriptor&) = 0;
+
   virtual bool IsContentParent() const { return false; }
 
   ContentParent* AsContentParent();
 
   virtual bool IsContentBridgeParent() const { return false; }
 
   ContentBridgeParent* AsContentBridgeParent();
 
   nsFrameMessageManager* GetMessageManager() const { return mMessageManager; }
 
   virtual int32_t Pid() const = 0;
 
+  virtual mozilla::ipc::PParentToChildStreamParent*
+  SendPParentToChildStreamConstructor(mozilla::ipc::PParentToChildStreamParent*) = 0;
+
 protected: // methods
   bool CanOpenBrowser(const IPCTabContext& aContext);
 
 protected: // IPDL methods
   virtual mozilla::jsipc::PJavaScriptParent* AllocPJavaScriptParent();
   virtual bool DeallocPJavaScriptParent(mozilla::jsipc::PJavaScriptParent*);
 
   virtual PBrowserParent* AllocPBrowserParent(const TabId& aTabId,
@@ -111,16 +120,21 @@ protected: // IPDL methods
   virtual bool
   DeallocPFileDescriptorSetParent(mozilla::ipc::PFileDescriptorSetParent* aActor);
 
   virtual mozilla::ipc::PChildToParentStreamParent* AllocPChildToParentStreamParent();
 
   virtual bool
   DeallocPChildToParentStreamParent(mozilla::ipc::PChildToParentStreamParent* aActor);
 
+  virtual mozilla::ipc::PParentToChildStreamParent* AllocPParentToChildStreamParent();
+
+  virtual bool
+  DeallocPParentToChildStreamParent(mozilla::ipc::PParentToChildStreamParent* aActor);
+
   virtual mozilla::ipc::IPCResult RecvSyncMessage(const nsString& aMsg,
                                                   const ClonedMessageData& aData,
                                                   InfallibleTArray<jsipc::CpowEntry>&& aCpows,
                                                   const IPC::Principal& aPrincipal,
                                                   nsTArray<ipc::StructuredCloneData>* aRetvals);
   virtual mozilla::ipc::IPCResult RecvRpcMessage(const nsString& aMsg,
                                                  const ClonedMessageData& aData,
                                                  InfallibleTArray<jsipc::CpowEntry>&& aCpows,
--- a/dom/network/PUDPSocket.ipdl
+++ b/dom/network/PUDPSocket.ipdl
@@ -5,16 +5,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PNecko;
 include protocol PBackground;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet; // FIXME: bug #792908
 include protocol PChildToParentStream; //FIXME: bug #792908
+include protocol PParentToChildStream; //FIXME: bug #792908
 
 include IPCStream;
 
 include "mozilla/net/NeckoMessageUtils.h";
 include "mozilla/net/DNS.h";
 include "prio.h";
 
 using mozilla::net::NetAddr from "mozilla/net/DNS.h";
--- a/dom/webbrowserpersist/PWebBrowserPersistDocument.ipdl
+++ b/dom/webbrowserpersist/PWebBrowserPersistDocument.ipdl
@@ -3,16 +3,17 @@
  * 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 PContent;
 include protocol PWebBrowserPersistResources;
 include protocol PWebBrowserPersistSerialize;
 include protocol PFileDescriptorSet;
 include protocol PChildToParentStream; //FIXME: bug #792908
+include protocol PParentToChildStream; //FIXME: bug #792908
 
 include IPCStream;
 
 namespace mozilla {
 
 // nsIWebBrowserPersistDocument has attributes which can be read
 // synchronously.  To avoid using sync IPC for them, the actor sends
 // this structure from the child to the parent before the parent actor
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -22,18 +22,20 @@
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h"
 #include "mozilla/dom/indexedDB/PBackgroundIndexedDBUtilsChild.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/quota/PQuotaChild.h"
 #include "mozilla/dom/GamepadEventChannelChild.h"
 #include "mozilla/dom/GamepadTestChannelChild.h"
 #include "mozilla/dom/MessagePortChild.h"
+#include "mozilla/ipc/IPCStreamAlloc.h"
 #include "mozilla/ipc/PBackgroundTestChild.h"
 #include "mozilla/ipc/PChildToParentStreamChild.h"
+#include "mozilla/ipc/PParentToChildStreamChild.h"
 #include "mozilla/layout/VsyncChild.h"
 #include "mozilla/net/PUDPSocketChild.h"
 #include "mozilla/dom/network/UDPSocketChild.h"
 #include "nsID.h"
 #include "nsTraceRefcnt.h"
 
 namespace {
 
@@ -411,16 +413,29 @@ BackgroundChildImpl::AllocPChildToParent
 
 bool
 BackgroundChildImpl::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
 {
   delete aActor;
   return true;
 }
 
+PParentToChildStreamChild*
+BackgroundChildImpl::AllocPParentToChildStreamChild()
+{
+  return mozilla::ipc::AllocPParentToChildStreamChild();
+}
+
+bool
+BackgroundChildImpl::DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
 PAsmJSCacheEntryChild*
 BackgroundChildImpl::AllocPAsmJSCacheEntryChild(
                                const dom::asmjscache::OpenMode& aOpenMode,
                                const dom::asmjscache::WriteParams& aWriteParams,
                                const PrincipalInfo& aPrincipalInfo)
 {
   MOZ_CRASH("PAsmJSCacheEntryChild actors should be manually constructed!");
 }
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -141,16 +141,22 @@ protected:
   DeallocPMessagePortChild(PMessagePortChild* aActor) override;
 
   virtual PChildToParentStreamChild*
   AllocPChildToParentStreamChild() override;
 
   virtual bool
   DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor) override;
 
+  virtual PParentToChildStreamChild*
+  AllocPParentToChildStreamChild() override;
+
+  virtual bool
+  DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor) override;
+
   virtual PAsmJSCacheEntryChild*
   AllocPAsmJSCacheEntryChild(const dom::asmjscache::OpenMode& aOpenMode,
                              const dom::asmjscache::WriteParams& aWriteParams,
                              const PrincipalInfo& aPrincipalInfo) override;
 
   virtual bool
   DeallocPAsmJSCacheEntryChild(PAsmJSCacheEntryChild* aActor) override;
 
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -26,20 +26,21 @@
 #include "mozilla/dom/ServiceWorkerRegistrar.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/cache/ActorUtils.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/quota/ActorsParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
+#include "mozilla/ipc/IPCStreamAlloc.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "mozilla/ipc/PBackgroundTestParent.h"
 #include "mozilla/ipc/PChildToParentStreamParent.h"
-#include "mozilla/ipc/SendStreamAlloc.h"
+#include "mozilla/ipc/PParentToChildStreamParent.h"
 #include "mozilla/layout/VsyncParent.h"
 #include "mozilla/dom/network/UDPSocketParent.h"
 #include "mozilla/Preferences.h"
 #include "nsNetUtil.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsProxyRelease.h"
 #include "mozilla/RefPtr.h"
 #include "nsThreadUtils.h"
@@ -311,16 +312,30 @@ BackgroundParentImpl::AllocPChildToParen
 bool
 BackgroundParentImpl::DeallocPChildToParentStreamParent(
                                              PChildToParentStreamParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+PParentToChildStreamParent*
+BackgroundParentImpl::AllocPParentToChildStreamParent()
+{
+  MOZ_CRASH("PParentToChildStreamParent actors should be manually constructed!");
+}
+
+bool
+BackgroundParentImpl::DeallocPParentToChildStreamParent(
+                                             PParentToChildStreamParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
 BackgroundParentImpl::PVsyncParent*
 BackgroundParentImpl::AllocPVsyncParent()
 {
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
 
   RefPtr<mozilla::layout::VsyncParent> actor =
       mozilla::layout::VsyncParent::Create();
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -102,16 +102,22 @@ protected:
   DeallocPBroadcastChannelParent(PBroadcastChannelParent* aActor) override;
 
   virtual PChildToParentStreamParent*
   AllocPChildToParentStreamParent() override;
 
   virtual bool
   DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) override;
 
+  virtual PParentToChildStreamParent*
+  AllocPParentToChildStreamParent() override;
+
+  virtual bool
+  DeallocPParentToChildStreamParent(PParentToChildStreamParent* aActor) override;
+
   virtual PServiceWorkerManagerParent*
   AllocPServiceWorkerManagerParent() override;
 
   virtual bool
   DeallocPServiceWorkerManagerParent(PServiceWorkerManagerParent* aActor) override;
 
   virtual PCamerasParent*
   AllocPCamerasParent() override;
--- a/ipc/glue/IPCStream.ipdlh
+++ b/ipc/glue/IPCStream.ipdlh
@@ -1,13 +1,14 @@
 /* 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 PChildToParentStream;
+include protocol PParentToChildStream;
 include BlobTypes;
 include InputStreamParams;
 
 namespace mozilla {
 namespace ipc {
 
 // Do not use this directly.  See IPCStream below.
 struct InputStreamParamsWithFds
@@ -18,16 +19,17 @@ struct InputStreamParamsWithFds
 
 // Use IPCStream or OptionalIPCStream in your ipdl to represent serialized
 // nsIInputStreams.  Then use AutoIPCStream from IPCStreamUtils.h to perform
 // the serialization.
 union IPCStream
 {
   InputStreamParamsWithFds;
   PChildToParentStream;
+  PParentToChildStream;
 };
 
 union OptionalIPCStream
 {
   IPCStream;
   void_t;
 };
 
rename from ipc/glue/SendStreamAlloc.h
rename to ipc/glue/IPCStreamAlloc.h
--- a/ipc/glue/SendStreamAlloc.h
+++ b/ipc/glue/IPCStreamAlloc.h
@@ -1,21 +1,25 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_ipc_SendStreamAlloc_h
-#define mozilla_ipc_SendStreamAlloc_h
+#ifndef mozilla_ipc_IPCStreamAlloc_h
+#define mozilla_ipc_IPCStreamAlloc_h
 
 namespace mozilla {
 namespace ipc {
 
 class PChildToParentStreamParent;
+class PParentToChildStreamChild;
 
 PChildToParentStreamParent*
 AllocPChildToParentStreamParent();
 
+PParentToChildStreamChild*
+AllocPParentToChildStreamChild();
+
 } // ipc namespace
 } // mozilla namespace
 
-#endif // mozilla_ipc_SendStreamAlloc_h
+#endif // mozilla_ipc_IPCStreamAlloc_h
rename from ipc/glue/SendStreamChild.cpp
rename to ipc/glue/IPCStreamChild.cpp
--- a/ipc/glue/SendStreamChild.cpp
+++ b/ipc/glue/IPCStreamChild.cpp
@@ -1,429 +1,212 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/ipc/SendStream.h"
+#include "IPCStreamDestination.h"
+#include "IPCStreamSource.h"
 
 #include "mozilla/Unused.h"
 #include "mozilla/dom/nsIContentChild.h"
-#include "mozilla/dom/WorkerPrivate.h"
-#include "mozilla/dom/workers/bindings/WorkerHolder.h"
 #include "mozilla/ipc/PBackgroundChild.h"
-#include "nsIAsyncInputStream.h"
-#include "nsICancelableRunnable.h"
-#include "nsIRunnable.h"
-#include "nsIThread.h"
-#include "nsStreamUtils.h"
+#include "mozilla/ipc/PChildToParentStreamChild.h"
+#include "mozilla/ipc/PParentToChildStreamChild.h"
 
 namespace mozilla {
 namespace ipc {
 
-using mozilla::dom::nsIContentChild;
-using mozilla::dom::workers::Canceling;
-using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
-using mozilla::dom::workers::Status;
-using mozilla::dom::workers::WorkerHolder;
-using mozilla::dom::workers::WorkerPrivate;
+// Child to Parent implementation
+// ----------------------------------------------------------------------------
 
 namespace {
 
-class SendStreamChildImpl final : public SendStreamChild
-                                , public WorkerHolder
+class IPCStreamSourceChild final : public PChildToParentStreamChild
+                                 , public IPCStreamSource
 {
 public:
-  explicit SendStreamChildImpl(nsIAsyncInputStream* aStream);
-  ~SendStreamChildImpl();
-
-  void Start() override;
-  void StartDestroy() override;
+  static IPCStreamSourceChild*
+  Create(nsIAsyncInputStream* aInputStream)
+  {
+    MOZ_ASSERT(aInputStream);
 
-  bool
-  AddAsWorkerHolder(dom::workers::WorkerPrivate* aWorkerPrivate);
+    IPCStreamSourceChild* source = new IPCStreamSourceChild(aInputStream);
+    if (!source->Initialize()) {
+      delete source;
+      return nullptr;
+    }
 
-private:
-  class Callback;
+    return source;
+  }
 
   // PChildToParentStreamChild methods
-  virtual void
-  ActorDestroy(ActorDestroyReason aReason) override;
 
-  virtual mozilla::ipc::IPCResult
-  RecvRequestClose(const nsresult& aRv) override;
-
-  // WorkerHolder methods
-  virtual bool
-  Notify(Status aStatus) override;
-
-  void DoRead();
-
-  void Wait();
-
-  void OnStreamReady(Callback* aCallback);
-
-  void OnEnd(nsresult aRv);
-
-  nsCOMPtr<nsIAsyncInputStream> mStream;
-  RefPtr<Callback> mCallback;
-  WorkerPrivate* mWorkerPrivate;
-  bool mClosed;
-
-  NS_DECL_OWNINGTHREAD
-};
-
-class SendStreamChildImpl::Callback final : public nsIInputStreamCallback
-                                          , public nsIRunnable
-                                          , public nsICancelableRunnable
-{
-public:
-  explicit Callback(SendStreamChildImpl* aActor)
-    : mActor(aActor)
-    , mOwningThread(NS_GetCurrentThread())
+  void
+  ActorDestroy(ActorDestroyReason aReason) override
   {
-    MOZ_ASSERT(mActor);
+    ActorDestroyed();
   }
 
-  NS_IMETHOD
-  OnInputStreamReady(nsIAsyncInputStream* aStream) override
+  IPCResult
+  RecvRequestClose(const nsresult& aRv) override
   {
-    // any thread
-    if (mOwningThread == NS_GetCurrentThread()) {
-      return Run();
-    }
-
-    // If this fails, then it means the owning thread is a Worker that has
-    // been shutdown.  Its ok to lose the event in this case because the
-    // SendStreamChild listens for this event through the WorkerHolder.
-    nsresult rv = mOwningThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Failed to dispatch stream readable event to owning thread");
-    }
-
-    return NS_OK;
-  }
-
-  NS_IMETHOD
-  Run() override
-  {
-    MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
-    if (mActor) {
-      mActor->OnStreamReady(this);
-    }
-    return NS_OK;
-  }
-
-  nsresult
-  Cancel() override
-  {
-    // Cancel() gets called when the Worker thread is being shutdown.  We have
-    // nothing to do here because SendStreamChild handles this case via
-    // the WorkerHolder.
-    return NS_OK;
+    OnEnd(aRv);
+    return IPC_OK();
   }
 
   void
-  ClearActor()
+  Close(nsresult aRv) override
   {
-    MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
-    MOZ_ASSERT(mActor);
-    mActor = nullptr;
+    MOZ_ASSERT(IPCStreamSource::mState == IPCStreamSource::eClosed);
+    Unused << SendClose(aRv);
+  }
+
+  void
+  SendData(const nsCString& aBuffer) override
+  {
+    Unused << SendBuffer(aBuffer);
   }
 
 private:
-  ~Callback()
-  {
-    // called on any thread
-
-    // ClearActor() should be called before the Callback is destroyed
-    MOZ_ASSERT(!mActor);
-  }
-
-  SendStreamChildImpl* mActor;
-  nsCOMPtr<nsIThread> mOwningThread;
-
-  NS_DECL_THREADSAFE_ISUPPORTS
+  explicit IPCStreamSourceChild(nsIAsyncInputStream* aInputStream)
+    :IPCStreamSource(aInputStream)
+  {}
 };
 
-NS_IMPL_ISUPPORTS(SendStreamChildImpl::Callback, nsIInputStreamCallback,
-                                                 nsIRunnable,
-                                                 nsICancelableRunnable);
-
-SendStreamChildImpl::SendStreamChildImpl(nsIAsyncInputStream* aStream)
-  : mStream(aStream)
-  , mWorkerPrivate(nullptr)
-  , mClosed(false)
-{
-  MOZ_ASSERT(mStream);
-}
-
-SendStreamChildImpl::~SendStreamChildImpl()
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(mClosed);
-  MOZ_ASSERT(!mCallback);
-  MOZ_ASSERT(!mWorkerPrivate);
-}
-
-void
-SendStreamChildImpl::Start()
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerPrivate);
-  DoRead();
-}
-
-void
-SendStreamChildImpl::StartDestroy()
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  OnEnd(NS_ERROR_ABORT);
-}
-
-bool
-SendStreamChildImpl::AddAsWorkerHolder(WorkerPrivate* aWorkerPrivate)
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(aWorkerPrivate);
-  bool result = HoldWorker(aWorkerPrivate, Canceling);
-  if (result) {
-    mWorkerPrivate = aWorkerPrivate;
-  }
-  return result;
-}
-
-void
-SendStreamChildImpl::ActorDestroy(ActorDestroyReason aReason)
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-
-  // If the parent side runs into a problem it will ask the child to
-  // close the connection via RequestClose().  Therefore OnEnd() should
-  // always run before the actor is destroyed.
-  MOZ_ASSERT(mClosed);
-
-  if (mCallback) {
-    mCallback->ClearActor();
-    mCallback = nullptr;
-  }
-
-  if (mWorkerPrivate) {
-    ReleaseWorker();
-    mWorkerPrivate = nullptr;
-  }
-}
-
-mozilla::ipc::IPCResult
-SendStreamChildImpl::RecvRequestClose(const nsresult& aRv)
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  OnEnd(aRv);
-  return IPC_OK();
-}
-
-bool
-SendStreamChildImpl::Notify(Status aStatus)
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-
-  // Keep the worker thread alive until the stream is finished.
-  return true;
-}
-
-void
-SendStreamChildImpl::DoRead()
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(!mClosed);
-  MOZ_ASSERT(!mCallback);
-
-  // The input stream (likely a pipe) probably uses a segment size of
-  // 4kb.  If there is data already buffered it would be nice to aggregate
-  // multiple segments into a single IPC call.  Conversely, don't send too
-  // too large of a buffer in a single call to avoid spiking memory.
-  static const uint64_t kMaxBytesPerMessage = 32 * 1024;
-  static_assert(kMaxBytesPerMessage <= static_cast<uint64_t>(UINT32_MAX),
-                "kMaxBytesPerMessage must cleanly cast to uint32_t");
-
-  while (true) {
-    // It should not be possible to transition to closed state without
-    // this loop terminating via a return.
-    MOZ_ASSERT(!mClosed);
-
-    // Use non-auto here as we're unlikely to hit stack storage with the
-    // sizes we are sending.  Also, it would be nice to avoid another copy
-    // to the IPC layer which we avoid if we use COW strings.  Unfortunately
-    // IPC does not seem to support passing dependent storage types.
-    nsCString buffer;
-
-    uint64_t available = 0;
-    nsresult rv = mStream->Available(&available);
-    if (NS_FAILED(rv)) {
-      OnEnd(rv);
-      return;
-    }
-
-    if (available == 0) {
-      Wait();
-      return;
-    }
-
-    uint32_t expectedBytes =
-      static_cast<uint32_t>(std::min(available, kMaxBytesPerMessage));
-
-    buffer.SetLength(expectedBytes);
-
-    uint32_t bytesRead = 0;
-    rv = mStream->Read(buffer.BeginWriting(), buffer.Length(), &bytesRead);
-    MOZ_ASSERT_IF(NS_FAILED(rv), bytesRead == 0);
-    buffer.SetLength(bytesRead);
-
-    // If we read any data from the stream, send it across.
-    if (!buffer.IsEmpty()) {
-      Unused << SendBuffer(buffer);
-    }
-
-    if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
-      Wait();
-      return;
-    }
-
-    // Any other error or zero-byte read indicates end-of-stream
-    if (NS_FAILED(rv) || buffer.IsEmpty()) {
-      OnEnd(rv);
-      return;
-    }
-  }
-}
-
-void
-SendStreamChildImpl::Wait()
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(!mClosed);
-  MOZ_ASSERT(!mCallback);
-
-  // Set mCallback immediately instead of waiting for success.  Its possible
-  // AsyncWait() will callback synchronously.
-  mCallback = new Callback(this);
-  nsresult rv = mStream->AsyncWait(mCallback, 0, 0, nullptr);
-  if (NS_FAILED(rv)) {
-    OnEnd(rv);
-    return;
-  }
-}
-
-void
-SendStreamChildImpl::OnStreamReady(Callback* aCallback)
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(mCallback);
-  MOZ_ASSERT(aCallback == mCallback);
-  mCallback->ClearActor();
-  mCallback = nullptr;
-  DoRead();
-}
-
-void
-SendStreamChildImpl::OnEnd(nsresult aRv)
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(aRv != NS_BASE_STREAM_WOULD_BLOCK);
-
-  if (mClosed) {
-    return;
-  }
-
-  mClosed = true;
-
-  mStream->CloseWithStatus(aRv);
-
-  if (aRv == NS_BASE_STREAM_CLOSED) {
-    aRv = NS_OK;
-  }
-
-  // This will trigger an ActorDestroy() from the parent side
-  Unused << SendClose(aRv);
-}
-
-bool
-IsBlocking(nsIAsyncInputStream* aInputStream)
-{
-  bool nonBlocking = false;
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aInputStream->IsNonBlocking(&nonBlocking)));
-  return !nonBlocking;
-}
-
 } // anonymous namespace
 
-// static
-SendStreamChild*
-SendStreamChild::Create(nsIAsyncInputStream* aInputStream,
-                        nsIContentChild* aManager)
+/* static */ PChildToParentStreamChild*
+IPCStreamSource::Create(nsIAsyncInputStream* aInputStream,
+                        dom::nsIContentChild* aManager)
 {
   MOZ_ASSERT(aInputStream);
   MOZ_ASSERT(aManager);
 
   // PContent can only be used on the main thread
   MOZ_ASSERT(NS_IsMainThread());
 
-  // SendStreamChild reads in the current thread, so it is only supported
-  // on non-blocking, async channels
-  if (NS_WARN_IF(IsBlocking(aInputStream))) {
+  IPCStreamSourceChild* source = IPCStreamSourceChild::Create(aInputStream);
+  if (!source) {
     return nullptr;
   }
 
-  SendStreamChild* actor = new SendStreamChildImpl(aInputStream);
-  aManager->SendPChildToParentStreamConstructor(actor);
+  if (!aManager->SendPChildToParentStreamConstructor(source)) {
+    return nullptr;
+  }
 
-  return actor;
+  source->ActorConstructed();
+  return source;
 }
 
-// static
-SendStreamChild*
-SendStreamChild::Create(nsIAsyncInputStream* aInputStream,
+/* static */ PChildToParentStreamChild*
+IPCStreamSource::Create(nsIAsyncInputStream* aInputStream,
                         PBackgroundChild* aManager)
 {
   MOZ_ASSERT(aInputStream);
   MOZ_ASSERT(aManager);
 
-  // PBackground can be used on any thread, but we only support SendStream on
-  // main thread and Worker threads right now.  This is due to the requirement
-  // that the thread be guaranteed to live long enough to receive messages
-  // sent from parent to child.  We can enforce this guarantee with a feature
-  // on worker threads, but not other threads.
-  WorkerPrivate* workerPrivate = nullptr;
-  if (!NS_IsMainThread()) {
-    workerPrivate = GetCurrentThreadWorkerPrivate();
-    MOZ_ASSERT(workerPrivate);
+  IPCStreamSourceChild* source = IPCStreamSourceChild::Create(aInputStream);
+  if (!source) {
+    return nullptr;
   }
 
-  // SendStreamChild reads in the current thread, so it is only supported
-  // on non-blocking, async channels
-  if (NS_WARN_IF(IsBlocking(aInputStream))) {
+  if (!aManager->SendPChildToParentStreamConstructor(source)) {
     return nullptr;
   }
 
-  SendStreamChildImpl* actor = new SendStreamChildImpl(aInputStream);
+  source->ActorConstructed();
+  return source;
+}
+
+/* static */ IPCStreamSource*
+IPCStreamSource::Cast(PChildToParentStreamChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+  return static_cast<IPCStreamSourceChild*>(aActor);
+}
+
+// Parent to Child implementation
+// ----------------------------------------------------------------------------
+
+namespace {
 
-  if (workerPrivate && !actor->AddAsWorkerHolder(workerPrivate)) {
-    delete actor;
-    return nullptr;
+class IPCStreamDestinationChild final : public PParentToChildStreamChild
+                                      , public IPCStreamDestination
+{
+public:
+  nsresult Initialize()
+  {
+    return IPCStreamDestination::Initialize();
+  }
+
+  ~IPCStreamDestinationChild()
+  {}
+
+private:
+  // PParentToChildStreamChild methods
+
+  void
+  ActorDestroy(ActorDestroyReason aReason) override
+  {
+    ActorDestroyed();
   }
 
-  aManager->SendPChildToParentStreamConstructor(actor);
+  IPCResult
+  RecvBuffer(const nsCString& aBuffer) override
+  {
+    BufferReceived(aBuffer);
+    return IPC_OK();
+  }
+
+  IPCResult
+  RecvClose(const nsresult& aRv) override
+  {
+    CloseReceived(aRv);
+    return IPC_OK();
+  }
+
+  // IPCStreamDestination methods
+
+  void
+  RequestClose(nsresult aRv) override
+  {
+    Unused << SendRequestClose(aRv);
+  }
+
+  void
+  TerminateDestination() override
+  {
+    Unused << Send__delete__(this);
+  }
+};
+
+} // anonymous namespace
+
+PParentToChildStreamChild*
+AllocPParentToChildStreamChild()
+{
+  IPCStreamDestinationChild* actor = new IPCStreamDestinationChild();
+
+  if (NS_WARN_IF(NS_FAILED(actor->Initialize()))) {
+    delete actor;
+    actor = nullptr;
+  }
+
   return actor;
 }
 
-SendStreamChild::~SendStreamChild()
-{
-}
-
 void
-DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
+DeallocPParentToChildStreamChild(PParentToChildStreamChild* aActor)
 {
   delete aActor;
 }
 
+/* static */ IPCStreamDestination*
+IPCStreamDestination::Cast(PParentToChildStreamChild* aActor)
+{
+  MOZ_ASSERT(aActor);
+  return static_cast<IPCStreamDestinationChild*>(aActor);
+}
+
 } // namespace ipc
 } // namespace mozilla
rename from ipc/glue/SendStreamParent.cpp
rename to ipc/glue/IPCStreamDestination.cpp
--- a/ipc/glue/SendStreamParent.cpp
+++ b/ipc/glue/IPCStreamDestination.cpp
@@ -1,136 +1,90 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/ipc/SendStream.h"
-
-#include "mozilla/Unused.h"
+#include "IPCStreamDestination.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIPipe.h"
 
 namespace mozilla {
 namespace ipc {
 
-namespace {
-
-class SendStreamParentImpl final : public SendStreamParent
+IPCStreamDestination::IPCStreamDestination()
 {
-public:
-  SendStreamParentImpl(nsIAsyncInputStream* aReader,
-                        nsIAsyncOutputStream* aWriter);
-  ~SendStreamParentImpl();
-
-private:
-  // PChildToParentStreamParentImpl methods
-  virtual void
-  ActorDestroy(ActorDestroyReason aReason) override;
+}
 
-  // SendStreamparent methods
-  already_AddRefed<nsIInputStream>
-  TakeReader() override;
-
-  virtual mozilla::ipc::IPCResult
-  RecvBuffer(const nsCString& aBuffer) override;
-
-  virtual mozilla::ipc::IPCResult
-  RecvClose(const nsresult& aRv) override;
-
-  nsCOMPtr<nsIAsyncInputStream> mReader;
-  nsCOMPtr<nsIAsyncOutputStream> mWriter;
-
-  NS_DECL_OWNINGTHREAD
-};
-
-SendStreamParentImpl::~SendStreamParentImpl()
+IPCStreamDestination::~IPCStreamDestination()
 {
 }
 
+nsresult
+IPCStreamDestination::Initialize()
+{
+  MOZ_ASSERT(!mReader);
+  MOZ_ASSERT(!mWriter);
+
+  // use async versions for both reader and writer even though we are
+  // opening the writer as an infinite stream.  We want to be able to
+  // use CloseWithStatus() to communicate errors through the pipe.
+
+  // Use an "infinite" pipe because we cannot apply back-pressure through
+  // the async IPC layer at the moment.  Blocking the IPC worker thread
+  // is not desirable, either.
+  nsresult rv = NS_NewPipe2(getter_AddRefs(mReader),
+                            getter_AddRefs(mWriter),
+                            true, true,   // non-blocking
+                            0,            // segment size
+                            UINT32_MAX);  // "infinite" pipe
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  return NS_OK;
+}
+
 already_AddRefed<nsIInputStream>
-SendStreamParentImpl::TakeReader()
+IPCStreamDestination::TakeReader()
 {
   MOZ_ASSERT(mReader);
   return mReader.forget();
 }
 
 void
-SendStreamParentImpl::ActorDestroy(ActorDestroyReason aReason)
+IPCStreamDestination::ActorDestroyed()
 {
+  MOZ_ASSERT(mWriter);
+
   // If we were gracefully closed we should have gotten RecvClose().  In
   // that case, the writer will already be closed and this will have no
   // effect.  This just aborts the writer in the case where the child process
   // crashes.
   mWriter->CloseWithStatus(NS_ERROR_ABORT);
 }
 
-mozilla::ipc::IPCResult
-SendStreamParentImpl::RecvBuffer(const nsCString& aBuffer)
+void
+IPCStreamDestination::BufferReceived(const nsCString& aBuffer)
 {
+  MOZ_ASSERT(mWriter);
+
   uint32_t numWritten = 0;
 
   // This should only fail if we hit an OOM condition.
   nsresult rv = mWriter->Write(aBuffer.get(), aBuffer.Length(), &numWritten);
   if (NS_WARN_IF(NS_FAILED(rv))) {
-    Unused << SendRequestClose(rv);
+    RequestClose(rv);
   }
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-SendStreamParentImpl::RecvClose(const nsresult& aRv)
-{
-  mWriter->CloseWithStatus(aRv);
-  Unused << Send__delete__(this);
-  return IPC_OK();
-}
-
-SendStreamParentImpl::SendStreamParentImpl(nsIAsyncInputStream* aReader,
-                                             nsIAsyncOutputStream* aWriter)
-  : mReader(aReader)
-  , mWriter(aWriter)
-{
-  MOZ_ASSERT(mReader);
-  MOZ_ASSERT(mWriter);
-}
-
-} // anonymous namespace
-
-SendStreamParent::~SendStreamParent()
-{
-}
-
-PChildToParentStreamParent*
-AllocPChildToParentStreamParent()
-{
-  // use async versions for both reader and writer even though we are
-  // opening the writer as an infinite stream.  We want to be able to
-  // use CloseWithStatus() to communicate errors through the pipe.
-  nsCOMPtr<nsIAsyncInputStream> reader;
-  nsCOMPtr<nsIAsyncOutputStream> writer;
-
-  // Use an "infinite" pipe because we cannot apply back-pressure through
-  // the async IPC layer at the moment.  Blocking the IPC worker thread
-  // is not desirable, either.
-  nsresult rv = NS_NewPipe2(getter_AddRefs(reader),
-                            getter_AddRefs(writer),
-                            true, true,   // non-blocking
-                            0,            // segment size
-                            UINT32_MAX);  // "infinite" pipe
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return nullptr;
-  }
-
-  return new SendStreamParentImpl(reader, writer);
 }
 
 void
-DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
+IPCStreamDestination::CloseReceived(nsresult aRv)
 {
-  delete aActor;
+  MOZ_ASSERT(mWriter);
+  mWriter->CloseWithStatus(aRv);
+  TerminateDestination();
 }
 
 } // namespace ipc
 } // namespace mozilla
rename from ipc/glue/SendStream.h
rename to ipc/glue/IPCStreamDestination.h
--- a/ipc/glue/SendStream.h
+++ b/ipc/glue/IPCStreamDestination.h
@@ -1,101 +1,69 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_ipc_SendStream_h
-#define mozilla_ipc_SendStream_h
+#ifndef mozilla_ipc_IPCStreamDestination_h
+#define mozilla_ipc_IPCStreamDestination_h
 
 #include "mozilla/AlreadyAddRefed.h"
-#include "mozilla/ipc/PChildToParentStreamChild.h"
-#include "mozilla/ipc/PChildToParentStreamParent.h"
 
 class nsIInputStream;
 class nsIAsyncInputStream;
+class nsIAsyncOutputStream;
 
 namespace mozilla {
-
-namespace dom {
-class nsIContentChild;
-} // dom namespace
-
 namespace ipc {
 
-class PBackgroundChild;
+class PChildToParentStreamParent;
+class PParentToChildStreamChild;
 
-// The SendStream IPC actor is designed to push an nsIInputStream from child to
-// parent incrementally.  This is mainly needed for streams such as nsPipe that
-// may not yet have all their data available when the stream must be sent across
-// an IPC boundary.  While many streams are handled by SerializeInputStream(),
-// these streams cannot be serialized and must be sent using this actor.
-//
-// The SendStream actor only supports sending data from child to parent.
-//
-// The SendStream actor only support async, non-blocking streams because they
-// must be read inline on the main thread and Worker threads.
-//
-// In general, the creation and handling of the SendStream actor cannot be
-// abstracted away behind SerializeInputStream() because the actor must be
-// carefully managed.  Specifically:
-//
-//  1) The data flow must be explicitly initiated by calling
-//     SendStreamChild::Start() after the actor has been sent to the parent.
-//  2) If the actor is never sent to the parent, then the child code must
-//     call SendStreamChild::StartDestroy() to avoid memory leaks.
-//  3) The SendStreamChild actor can only be used on threads that can be
-//     guaranteed to stay alive as long as the actor is alive.  Right now
-//     this limits SendStream to the main thread and Worker threads.
-//
-// In general you should probably use the AutoIPCStreamChild RAII class
-// defined in InputStreamUtils.h instead of using SendStreamChild directly.
-class SendStreamChild : public PChildToParentStreamChild
+// On the destination side, you must simply call TakeReader() upon receiving a
+// reference to the IPCStream{Child,Parent} actor.  You do not need to maintain
+// a reference to the actor itself.
+class IPCStreamDestination
 {
 public:
-  // Create a SendStreamChild using a PContent IPC manager on the
-  // main thread.  This can return nullptr if the provided stream is
-  // blocking.
-  static SendStreamChild*
-  Create(nsIAsyncInputStream* aInputStream, dom::nsIContentChild* aManager);
-
-  // Create a SendStreamChild using a PBackground IPC manager on the
-  // main thread or a Worker thread.  This can return nullptr if the provided
-  // stream is blocking or if the Worker thread is already shutting down.
-  static SendStreamChild*
-  Create(nsIAsyncInputStream* aInputStream, PBackgroundChild* aManager);
+  static IPCStreamDestination*
+  Cast(PChildToParentStreamParent* aActor);
 
-  // Start reading data from the nsIAsyncInputStream used to create the actor.
-  // This must be called after the actor is passed to the parent.  If you
-  // use AutoIPCStream this is handled automatically.
-  virtual void
-  Start() = 0;
+  static IPCStreamDestination*
+  Cast(PParentToChildStreamChild* aActor);
 
-  // Start cleaning up the actor.  This must be called if the actor is never
-  // sent to the parent.  If you use AutoIPCStream this is handled
-  // automatically.
-  virtual void
-  StartDestroy() = 0;
+  virtual already_AddRefed<nsIInputStream>
+  TakeReader();
 
 protected:
-  virtual
-  ~SendStreamChild() = 0;
-};
+  IPCStreamDestination();
+  virtual ~IPCStreamDestination();
+
+  nsresult Initialize();
+
+  // The implementation of the actor should call these methods.
+
+  void
+  ActorDestroyed();
+
+  void
+  BufferReceived(const nsCString& aBuffer);
 
-// On the parent side, you must simply call TakeReader() upon receiving a
-// reference to the SendStreamParent actor.  You do not need to maintain a
-// reference to the actor itself.
-class SendStreamParent : public PChildToParentStreamParent
-{
-public:
-  virtual already_AddRefed<nsIInputStream>
-  TakeReader() = 0;
+  void
+  CloseReceived(nsresult aRv);
+
+  // These methods will be implemented by the actor.
 
-protected:
-  virtual
-  ~SendStreamParent() = 0;
+  virtual void
+  RequestClose(nsresult aRv) = 0;
+
+  virtual void
+  TerminateDestination() = 0;
+
+  nsCOMPtr<nsIAsyncInputStream> mReader;
+  nsCOMPtr<nsIAsyncOutputStream> mWriter;
 };
 
 } // namespace ipc
 } // namespace mozilla
 
-#endif // mozilla_ipc_SendStream_h
+#endif // mozilla_ipc_IPCStreamDestination_h
copy from ipc/glue/SendStreamParent.cpp
copy to ipc/glue/IPCStreamParent.cpp
--- a/ipc/glue/SendStreamParent.cpp
+++ b/ipc/glue/IPCStreamParent.cpp
@@ -1,136 +1,212 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/ipc/SendStream.h"
-
+#include "IPCStreamDestination.h"
+#include "mozilla/dom/nsIContentParent.h"
+#include "mozilla/ipc/PBackgroundParent.h"
+#include "mozilla/ipc/PChildToParentStreamParent.h"
+#include "mozilla/ipc/PParentToChildStreamParent.h"
 #include "mozilla/Unused.h"
-#include "nsIAsyncInputStream.h"
-#include "nsIAsyncOutputStream.h"
-#include "nsIPipe.h"
 
 namespace mozilla {
 namespace ipc {
 
+// Child to Parent implementation
+// ----------------------------------------------------------------------------
+
 namespace {
 
-class SendStreamParentImpl final : public SendStreamParent
+class IPCStreamSourceParent final : public PParentToChildStreamParent
+                                  , public IPCStreamSource
 {
 public:
-  SendStreamParentImpl(nsIAsyncInputStream* aReader,
-                        nsIAsyncOutputStream* aWriter);
-  ~SendStreamParentImpl();
+  static IPCStreamSourceParent*
+  Create(nsIAsyncInputStream* aInputStream)
+  {
+    MOZ_ASSERT(aInputStream);
+
+    IPCStreamSourceParent* source = new IPCStreamSourceParent(aInputStream);
+    if (!source->Initialize()) {
+      delete source;
+      return nullptr;
+    }
+
+    return source;
+  }
+
+  // PParentToChildStreamParent methods
+
+  void
+  ActorDestroy(ActorDestroyReason aReason) override
+  {
+    ActorDestroyed();
+  }
+
+  IPCResult
+  RecvRequestClose(const nsresult& aRv) override
+  {
+    OnEnd(aRv);
+    return IPC_OK();
+  }
+
+  void
+  Close(nsresult aRv) override
+  {
+    MOZ_ASSERT(IPCStreamSource::mState == IPCStreamSource::eClosed);
+    Unused << SendClose(aRv);
+  }
+
+  void
+  SendData(const nsCString& aBuffer) override
+  {
+    Unused << SendBuffer(aBuffer);
+  }
 
 private:
-  // PChildToParentStreamParentImpl methods
-  virtual void
-  ActorDestroy(ActorDestroyReason aReason) override;
-
-  // SendStreamparent methods
-  already_AddRefed<nsIInputStream>
-  TakeReader() override;
-
-  virtual mozilla::ipc::IPCResult
-  RecvBuffer(const nsCString& aBuffer) override;
-
-  virtual mozilla::ipc::IPCResult
-  RecvClose(const nsresult& aRv) override;
-
-  nsCOMPtr<nsIAsyncInputStream> mReader;
-  nsCOMPtr<nsIAsyncOutputStream> mWriter;
-
-  NS_DECL_OWNINGTHREAD
+  explicit IPCStreamSourceParent(nsIAsyncInputStream* aInputStream)
+    :IPCStreamSource(aInputStream)
+  {}
 };
 
-SendStreamParentImpl::~SendStreamParentImpl()
-{
-}
-
-already_AddRefed<nsIInputStream>
-SendStreamParentImpl::TakeReader()
-{
-  MOZ_ASSERT(mReader);
-  return mReader.forget();
-}
-
-void
-SendStreamParentImpl::ActorDestroy(ActorDestroyReason aReason)
-{
-  // If we were gracefully closed we should have gotten RecvClose().  In
-  // that case, the writer will already be closed and this will have no
-  // effect.  This just aborts the writer in the case where the child process
-  // crashes.
-  mWriter->CloseWithStatus(NS_ERROR_ABORT);
-}
-
-mozilla::ipc::IPCResult
-SendStreamParentImpl::RecvBuffer(const nsCString& aBuffer)
-{
-  uint32_t numWritten = 0;
-
-  // This should only fail if we hit an OOM condition.
-  nsresult rv = mWriter->Write(aBuffer.get(), aBuffer.Length(), &numWritten);
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    Unused << SendRequestClose(rv);
-  }
-
-  return IPC_OK();
-}
-
-mozilla::ipc::IPCResult
-SendStreamParentImpl::RecvClose(const nsresult& aRv)
-{
-  mWriter->CloseWithStatus(aRv);
-  Unused << Send__delete__(this);
-  return IPC_OK();
-}
-
-SendStreamParentImpl::SendStreamParentImpl(nsIAsyncInputStream* aReader,
-                                             nsIAsyncOutputStream* aWriter)
-  : mReader(aReader)
-  , mWriter(aWriter)
-{
-  MOZ_ASSERT(mReader);
-  MOZ_ASSERT(mWriter);
-}
-
 } // anonymous namespace
 
-SendStreamParent::~SendStreamParent()
+/* static */ PParentToChildStreamParent*
+IPCStreamSource::Create(nsIAsyncInputStream* aInputStream,
+                        dom::nsIContentParent* aManager)
+{
+  MOZ_ASSERT(aInputStream);
+  MOZ_ASSERT(aManager);
+
+  // PContent can only be used on the main thread
+  MOZ_ASSERT(NS_IsMainThread());
+
+  IPCStreamSourceParent* source = IPCStreamSourceParent::Create(aInputStream);
+  if (!source) {
+    return nullptr;
+  }
+
+  if (!aManager->SendPParentToChildStreamConstructor(source)) {
+    // no delete here, the manager will delete the actor for us.
+    return nullptr;
+  }
+
+  source->ActorConstructed();
+  return source;
+}
+
+/* static */ PParentToChildStreamParent*
+IPCStreamSource::Create(nsIAsyncInputStream* aInputStream,
+                        PBackgroundParent* aManager)
+{
+  MOZ_ASSERT(aInputStream);
+  MOZ_ASSERT(aManager);
+
+  IPCStreamSourceParent* source = IPCStreamSourceParent::Create(aInputStream);
+  if (!source) {
+    return nullptr;
+  }
+
+  if (!aManager->SendPParentToChildStreamConstructor(source)) {
+    // no delete here, the manager will delete the actor for us.
+    return nullptr;
+  }
+
+  source->ActorConstructed();
+  return source;
+}
+
+/* static */ IPCStreamSource*
+IPCStreamSource::Cast(PParentToChildStreamParent* aActor)
 {
+  MOZ_ASSERT(aActor);
+  return static_cast<IPCStreamSourceParent*>(aActor);
 }
 
+// Child to Parent implementation
+// ----------------------------------------------------------------------------
+
+namespace {
+
+class IPCStreamDestinationParent final : public PChildToParentStreamParent
+                                       , public IPCStreamDestination
+{
+public:
+  nsresult Initialize()
+  {
+    return IPCStreamDestination::Initialize();
+  }
+
+  ~IPCStreamDestinationParent()
+  {}
+
+private:
+  // PChildToParentStreamParent methods
+
+  void
+  ActorDestroy(ActorDestroyReason aReason) override
+  {
+    ActorDestroyed();
+  }
+
+  IPCResult
+  RecvBuffer(const nsCString& aBuffer) override
+  {
+    BufferReceived(aBuffer);
+    return IPC_OK();
+  }
+
+  IPCResult
+  RecvClose(const nsresult& aRv) override
+  {
+    CloseReceived(aRv);
+    return IPC_OK();
+  }
+
+  // IPCStreamDestination methods
+
+  void
+  RequestClose(nsresult aRv) override
+  {
+    Unused << SendRequestClose(aRv);
+  }
+
+  void
+  TerminateDestination() override
+  {
+    Unused << Send__delete__(this);
+  }
+};
+
+} // anonymous namespace
+
 PChildToParentStreamParent*
 AllocPChildToParentStreamParent()
 {
-  // use async versions for both reader and writer even though we are
-  // opening the writer as an infinite stream.  We want to be able to
-  // use CloseWithStatus() to communicate errors through the pipe.
-  nsCOMPtr<nsIAsyncInputStream> reader;
-  nsCOMPtr<nsIAsyncOutputStream> writer;
+  IPCStreamDestinationParent* actor = new IPCStreamDestinationParent();
 
-  // Use an "infinite" pipe because we cannot apply back-pressure through
-  // the async IPC layer at the moment.  Blocking the IPC worker thread
-  // is not desirable, either.
-  nsresult rv = NS_NewPipe2(getter_AddRefs(reader),
-                            getter_AddRefs(writer),
-                            true, true,   // non-blocking
-                            0,            // segment size
-                            UINT32_MAX);  // "infinite" pipe
-  if (NS_WARN_IF(NS_FAILED(rv))) {
-    return nullptr;
+  if (NS_WARN_IF(NS_FAILED(actor->Initialize()))) {
+    delete actor;
+    actor = nullptr;
   }
 
-  return new SendStreamParentImpl(reader, writer);
+  return actor;
 }
 
 void
 DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor)
 {
   delete aActor;
 }
 
+/* static */ IPCStreamDestination*
+IPCStreamDestination::Cast(PChildToParentStreamParent* aActor)
+{
+  MOZ_ASSERT(aActor);
+  return static_cast<IPCStreamDestinationParent*>(aActor);
+}
+
 } // namespace ipc
 } // namespace mozilla
copy from ipc/glue/SendStreamChild.cpp
copy to ipc/glue/IPCStreamSource.cpp
--- a/ipc/glue/SendStreamChild.cpp
+++ b/ipc/glue/IPCStreamSource.cpp
@@ -1,259 +1,226 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/ipc/SendStream.h"
-
-#include "mozilla/Unused.h"
-#include "mozilla/dom/nsIContentChild.h"
-#include "mozilla/dom/WorkerPrivate.h"
-#include "mozilla/dom/workers/bindings/WorkerHolder.h"
-#include "mozilla/ipc/PBackgroundChild.h"
+#include "IPCStreamSource.h"
 #include "nsIAsyncInputStream.h"
 #include "nsICancelableRunnable.h"
 #include "nsIRunnable.h"
 #include "nsIThread.h"
 #include "nsStreamUtils.h"
 
-namespace mozilla {
-namespace ipc {
-
-using mozilla::dom::nsIContentChild;
 using mozilla::dom::workers::Canceling;
 using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
 using mozilla::dom::workers::Status;
-using mozilla::dom::workers::WorkerHolder;
 using mozilla::dom::workers::WorkerPrivate;
 
-namespace {
+namespace mozilla {
+namespace ipc {
 
-class SendStreamChildImpl final : public SendStreamChild
-                                , public WorkerHolder
+class IPCStreamSource::Callback final : public nsIInputStreamCallback
+                                      , public nsIRunnable
+                                      , public nsICancelableRunnable
 {
 public:
-  explicit SendStreamChildImpl(nsIAsyncInputStream* aStream);
-  ~SendStreamChildImpl();
-
-  void Start() override;
-  void StartDestroy() override;
-
-  bool
-  AddAsWorkerHolder(dom::workers::WorkerPrivate* aWorkerPrivate);
-
-private:
-  class Callback;
-
-  // PChildToParentStreamChild methods
-  virtual void
-  ActorDestroy(ActorDestroyReason aReason) override;
-
-  virtual mozilla::ipc::IPCResult
-  RecvRequestClose(const nsresult& aRv) override;
-
-  // WorkerHolder methods
-  virtual bool
-  Notify(Status aStatus) override;
-
-  void DoRead();
-
-  void Wait();
-
-  void OnStreamReady(Callback* aCallback);
-
-  void OnEnd(nsresult aRv);
-
-  nsCOMPtr<nsIAsyncInputStream> mStream;
-  RefPtr<Callback> mCallback;
-  WorkerPrivate* mWorkerPrivate;
-  bool mClosed;
-
-  NS_DECL_OWNINGTHREAD
-};
-
-class SendStreamChildImpl::Callback final : public nsIInputStreamCallback
-                                          , public nsIRunnable
-                                          , public nsICancelableRunnable
-{
-public:
-  explicit Callback(SendStreamChildImpl* aActor)
-    : mActor(aActor)
+  explicit Callback(IPCStreamSource* aSource)
+    : mSource(aSource)
     , mOwningThread(NS_GetCurrentThread())
   {
-    MOZ_ASSERT(mActor);
+    MOZ_ASSERT(mSource);
   }
 
   NS_IMETHOD
   OnInputStreamReady(nsIAsyncInputStream* aStream) override
   {
     // any thread
     if (mOwningThread == NS_GetCurrentThread()) {
       return Run();
     }
 
     // If this fails, then it means the owning thread is a Worker that has
     // been shutdown.  Its ok to lose the event in this case because the
-    // SendStreamChild listens for this event through the WorkerHolder.
+    // IPCStreamChild listens for this event through the WorkerHolder.
     nsresult rv = mOwningThread->Dispatch(this, nsIThread::DISPATCH_NORMAL);
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to dispatch stream readable event to owning thread");
     }
 
     return NS_OK;
   }
 
   NS_IMETHOD
   Run() override
   {
     MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
-    if (mActor) {
-      mActor->OnStreamReady(this);
+    if (mSource) {
+      mSource->OnStreamReady(this);
     }
     return NS_OK;
   }
 
   nsresult
   Cancel() override
   {
     // Cancel() gets called when the Worker thread is being shutdown.  We have
-    // nothing to do here because SendStreamChild handles this case via
+    // nothing to do here because IPCStreamChild handles this case via
     // the WorkerHolder.
     return NS_OK;
   }
 
   void
-  ClearActor()
+  ClearSource()
   {
     MOZ_ASSERT(mOwningThread == NS_GetCurrentThread());
-    MOZ_ASSERT(mActor);
-    mActor = nullptr;
+    MOZ_ASSERT(mSource);
+    mSource = nullptr;
   }
 
 private:
   ~Callback()
   {
     // called on any thread
 
-    // ClearActor() should be called before the Callback is destroyed
-    MOZ_ASSERT(!mActor);
+    // ClearSource() should be called before the Callback is destroyed
+    MOZ_ASSERT(!mSource);
   }
 
-  SendStreamChildImpl* mActor;
+  // This is a raw pointer because the source keeps alive the callback and,
+  // before beeing destroyed, it nullifies this pointer (this happens when
+  // ActorDestroyed() is called).
+  IPCStreamSource* mSource;
+
   nsCOMPtr<nsIThread> mOwningThread;
 
   NS_DECL_THREADSAFE_ISUPPORTS
 };
 
-NS_IMPL_ISUPPORTS(SendStreamChildImpl::Callback, nsIInputStreamCallback,
-                                                 nsIRunnable,
-                                                 nsICancelableRunnable);
+NS_IMPL_ISUPPORTS(IPCStreamSource::Callback, nsIInputStreamCallback,
+                                             nsIRunnable,
+                                             nsICancelableRunnable);
 
-SendStreamChildImpl::SendStreamChildImpl(nsIAsyncInputStream* aStream)
-  : mStream(aStream)
+IPCStreamSource::IPCStreamSource(nsIAsyncInputStream* aInputStream)
+  : mStream(aInputStream)
   , mWorkerPrivate(nullptr)
-  , mClosed(false)
+  , mState(ePending)
 {
-  MOZ_ASSERT(mStream);
+  MOZ_ASSERT(aInputStream);
 }
 
-SendStreamChildImpl::~SendStreamChildImpl()
+IPCStreamSource::~IPCStreamSource()
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(mClosed);
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
+  MOZ_ASSERT(mState == eClosed);
   MOZ_ASSERT(!mCallback);
   MOZ_ASSERT(!mWorkerPrivate);
 }
 
-void
-SendStreamChildImpl::Start()
+bool
+IPCStreamSource::Initialize()
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerPrivate);
-  DoRead();
+  bool nonBlocking = false;
+  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mStream->IsNonBlocking(&nonBlocking)));
+  // IPCStreamChild reads in the current thread, so it is only supported on
+  // non-blocking, async channels
+  if (!nonBlocking) {
+    return false;
+  }
+
+  // A source can be used on any thread, but we only support IPCStream on
+  // main thread and Worker threads right now.  This is due to the requirement
+  // that the thread be guaranteed to live long enough to receive messages.
+  // We can enforce this guarantee with a feature on worker threads, but not
+  // other threads.
+  WorkerPrivate* workerPrivate = nullptr;
+  if (!NS_IsMainThread()) {
+    workerPrivate = GetCurrentThreadWorkerPrivate();
+    MOZ_RELEASE_ASSERT(workerPrivate);
+
+    bool result = HoldWorker(workerPrivate, Canceling);
+    if (!result) {
+      return false;
+    }
+
+    mWorkerPrivate = workerPrivate;
+  }
+
+  return true;
 }
 
 void
-SendStreamChildImpl::StartDestroy()
+IPCStreamSource::ActorConstructed()
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  OnEnd(NS_ERROR_ABORT);
+  MOZ_ASSERT(mState == ePending);
+  mState = eActorConstructed;
 }
 
 bool
-SendStreamChildImpl::AddAsWorkerHolder(WorkerPrivate* aWorkerPrivate)
+IPCStreamSource::Notify(Status aStatus)
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(aWorkerPrivate);
-  bool result = HoldWorker(aWorkerPrivate, Canceling);
-  if (result) {
-    mWorkerPrivate = aWorkerPrivate;
-  }
-  return result;
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
+
+  // Keep the worker thread alive until the stream is finished.
+  return true;
 }
 
 void
-SendStreamChildImpl::ActorDestroy(ActorDestroyReason aReason)
+IPCStreamSource::ActorDestroyed()
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
 
-  // If the parent side runs into a problem it will ask the child to
-  // close the connection via RequestClose().  Therefore OnEnd() should
-  // always run before the actor is destroyed.
-  MOZ_ASSERT(mClosed);
+  mState = eClosed;
 
   if (mCallback) {
-    mCallback->ClearActor();
+    mCallback->ClearSource();
     mCallback = nullptr;
   }
 
   if (mWorkerPrivate) {
     ReleaseWorker();
     mWorkerPrivate = nullptr;
   }
 }
 
-mozilla::ipc::IPCResult
-SendStreamChildImpl::RecvRequestClose(const nsresult& aRv)
+void
+IPCStreamSource::Start()
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  OnEnd(aRv);
-  return IPC_OK();
-}
-
-bool
-SendStreamChildImpl::Notify(Status aStatus)
-{
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-
-  // Keep the worker thread alive until the stream is finished.
-  return true;
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
+  MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerPrivate);
+  DoRead();
 }
 
 void
-SendStreamChildImpl::DoRead()
+IPCStreamSource::StartDestroy()
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(!mClosed);
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
+  OnEnd(NS_ERROR_ABORT);
+}
+
+void
+IPCStreamSource::DoRead()
+{
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
+  MOZ_ASSERT(mState == eActorConstructed);
   MOZ_ASSERT(!mCallback);
 
   // The input stream (likely a pipe) probably uses a segment size of
   // 4kb.  If there is data already buffered it would be nice to aggregate
   // multiple segments into a single IPC call.  Conversely, don't send too
   // too large of a buffer in a single call to avoid spiking memory.
   static const uint64_t kMaxBytesPerMessage = 32 * 1024;
   static_assert(kMaxBytesPerMessage <= static_cast<uint64_t>(UINT32_MAX),
                 "kMaxBytesPerMessage must cleanly cast to uint32_t");
 
   while (true) {
     // It should not be possible to transition to closed state without
     // this loop terminating via a return.
-    MOZ_ASSERT(!mClosed);
+    MOZ_ASSERT(mState == eActorConstructed);
 
     // Use non-auto here as we're unlikely to hit stack storage with the
     // sizes we are sending.  Also, it would be nice to avoid another copy
     // to the IPC layer which we avoid if we use COW strings.  Unfortunately
     // IPC does not seem to support passing dependent storage types.
     nsCString buffer;
 
     uint64_t available = 0;
@@ -275,155 +242,76 @@ SendStreamChildImpl::DoRead()
 
     uint32_t bytesRead = 0;
     rv = mStream->Read(buffer.BeginWriting(), buffer.Length(), &bytesRead);
     MOZ_ASSERT_IF(NS_FAILED(rv), bytesRead == 0);
     buffer.SetLength(bytesRead);
 
     // If we read any data from the stream, send it across.
     if (!buffer.IsEmpty()) {
-      Unused << SendBuffer(buffer);
+      SendData(buffer);
     }
 
     if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
       Wait();
       return;
     }
 
     // Any other error or zero-byte read indicates end-of-stream
     if (NS_FAILED(rv) || buffer.IsEmpty()) {
       OnEnd(rv);
       return;
     }
   }
 }
 
 void
-SendStreamChildImpl::Wait()
+IPCStreamSource::Wait()
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
-  MOZ_ASSERT(!mClosed);
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
+  MOZ_ASSERT(mState == eActorConstructed);
   MOZ_ASSERT(!mCallback);
 
   // Set mCallback immediately instead of waiting for success.  Its possible
   // AsyncWait() will callback synchronously.
   mCallback = new Callback(this);
   nsresult rv = mStream->AsyncWait(mCallback, 0, 0, nullptr);
   if (NS_FAILED(rv)) {
     OnEnd(rv);
     return;
   }
 }
 
 void
-SendStreamChildImpl::OnStreamReady(Callback* aCallback)
+IPCStreamSource::OnStreamReady(Callback* aCallback)
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
   MOZ_ASSERT(mCallback);
   MOZ_ASSERT(aCallback == mCallback);
-  mCallback->ClearActor();
+  mCallback->ClearSource();
   mCallback = nullptr;
   DoRead();
 }
 
 void
-SendStreamChildImpl::OnEnd(nsresult aRv)
+IPCStreamSource::OnEnd(nsresult aRv)
 {
-  NS_ASSERT_OWNINGTHREAD(SendStreamChild);
+  NS_ASSERT_OWNINGTHREAD(IPCStreamSource);
   MOZ_ASSERT(aRv != NS_BASE_STREAM_WOULD_BLOCK);
 
-  if (mClosed) {
+  if (mState == eClosed) {
     return;
   }
 
-  mClosed = true;
+  mState = eClosed;
 
   mStream->CloseWithStatus(aRv);
 
   if (aRv == NS_BASE_STREAM_CLOSED) {
     aRv = NS_OK;
   }
 
-  // This will trigger an ActorDestroy() from the parent side
-  Unused << SendClose(aRv);
-}
-
-bool
-IsBlocking(nsIAsyncInputStream* aInputStream)
-{
-  bool nonBlocking = false;
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aInputStream->IsNonBlocking(&nonBlocking)));
-  return !nonBlocking;
-}
-
-} // anonymous namespace
-
-// static
-SendStreamChild*
-SendStreamChild::Create(nsIAsyncInputStream* aInputStream,
-                        nsIContentChild* aManager)
-{
-  MOZ_ASSERT(aInputStream);
-  MOZ_ASSERT(aManager);
-
-  // PContent can only be used on the main thread
-  MOZ_ASSERT(NS_IsMainThread());
-
-  // SendStreamChild reads in the current thread, so it is only supported
-  // on non-blocking, async channels
-  if (NS_WARN_IF(IsBlocking(aInputStream))) {
-    return nullptr;
-  }
-
-  SendStreamChild* actor = new SendStreamChildImpl(aInputStream);
-  aManager->SendPChildToParentStreamConstructor(actor);
-
-  return actor;
-}
-
-// static
-SendStreamChild*
-SendStreamChild::Create(nsIAsyncInputStream* aInputStream,
-                        PBackgroundChild* aManager)
-{
-  MOZ_ASSERT(aInputStream);
-  MOZ_ASSERT(aManager);
-
-  // PBackground can be used on any thread, but we only support SendStream on
-  // main thread and Worker threads right now.  This is due to the requirement
-  // that the thread be guaranteed to live long enough to receive messages
-  // sent from parent to child.  We can enforce this guarantee with a feature
-  // on worker threads, but not other threads.
-  WorkerPrivate* workerPrivate = nullptr;
-  if (!NS_IsMainThread()) {
-    workerPrivate = GetCurrentThreadWorkerPrivate();
-    MOZ_ASSERT(workerPrivate);
-  }
-
-  // SendStreamChild reads in the current thread, so it is only supported
-  // on non-blocking, async channels
-  if (NS_WARN_IF(IsBlocking(aInputStream))) {
-    return nullptr;
-  }
-
-  SendStreamChildImpl* actor = new SendStreamChildImpl(aInputStream);
-
-  if (workerPrivate && !actor->AddAsWorkerHolder(workerPrivate)) {
-    delete actor;
-    return nullptr;
-  }
-
-  aManager->SendPChildToParentStreamConstructor(actor);
-  return actor;
-}
-
-SendStreamChild::~SendStreamChild()
-{
-}
-
-void
-DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
-{
-  delete aActor;
+  // This will trigger an ActorDestroy() from the other side
+  Close(aRv);
 }
 
 } // namespace ipc
 } // namespace mozilla
copy from ipc/glue/SendStream.h
copy to ipc/glue/IPCStreamSource.h
--- a/ipc/glue/SendStream.h
+++ b/ipc/glue/IPCStreamSource.h
@@ -1,101 +1,155 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#ifndef mozilla_ipc_SendStream_h
-#define mozilla_ipc_SendStream_h
+#ifndef mozilla_ipc_IPCStreamSource_h
+#define mozilla_ipc_IPCStreamSource_h
 
 #include "mozilla/AlreadyAddRefed.h"
-#include "mozilla/ipc/PChildToParentStreamChild.h"
-#include "mozilla/ipc/PChildToParentStreamParent.h"
+#include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/workers/bindings/WorkerHolder.h"
 
-class nsIInputStream;
 class nsIAsyncInputStream;
 
 namespace mozilla {
 
 namespace dom {
 class nsIContentChild;
+class nsIContentParent;
 } // dom namespace
 
 namespace ipc {
 
 class PBackgroundChild;
+class PBackgroundParent;
 
-// The SendStream IPC actor is designed to push an nsIInputStream from child to
-// parent incrementally.  This is mainly needed for streams such as nsPipe that
-// may not yet have all their data available when the stream must be sent across
-// an IPC boundary.  While many streams are handled by SerializeInputStream(),
-// these streams cannot be serialized and must be sent using this actor.
+// The IPCStream IPC actor is designed to push an nsIInputStream from child to
+// parent or parent to child incrementally.  This is mainly needed for streams
+// such as nsPipe that may not yet have all their data available when the
+// stream must be sent across an IPC boundary.  While many streams are handled
+// by SerializeInputStream(), these streams cannot be serialized and must be
+// sent using this actor.
 //
-// The SendStream actor only supports sending data from child to parent.
-//
-// The SendStream actor only support async, non-blocking streams because they
+// The IPCStream actor only support async, non-blocking streams because they
 // must be read inline on the main thread and Worker threads.
 //
-// In general, the creation and handling of the SendStream actor cannot be
+// In general, the creation and handling of the IPCStream actor cannot be
 // abstracted away behind SerializeInputStream() because the actor must be
 // carefully managed.  Specifically:
 //
 //  1) The data flow must be explicitly initiated by calling
-//     SendStreamChild::Start() after the actor has been sent to the parent.
-//  2) If the actor is never sent to the parent, then the child code must
-//     call SendStreamChild::StartDestroy() to avoid memory leaks.
-//  3) The SendStreamChild actor can only be used on threads that can be
+//     IPCStreamSource{Child,Parent}::Start() after the actor has been sent to
+//     the other-side actor.
+//  2) If the actor is never sent to the other-side, then this code must
+//     call IPCStreamSource{Child,Parent}::StartDestroy() to avoid memory leaks.
+//  3) The IPCStreamSource actor can only be used on threads that can be
 //     guaranteed to stay alive as long as the actor is alive.  Right now
-//     this limits SendStream to the main thread and Worker threads.
+//     this limits IPCStream to the main thread and Worker threads.
 //
-// In general you should probably use the AutoIPCStreamChild RAII class
-// defined in InputStreamUtils.h instead of using SendStreamChild directly.
-class SendStreamChild : public PChildToParentStreamChild
+// In general you should probably use the AutoIPCStreamSource RAII class
+// defined in InputStreamUtils.h instead of using IPCStreamSource directly.
+class IPCStreamSource : public dom::workers::WorkerHolder
 {
 public:
-  // Create a SendStreamChild using a PContent IPC manager on the
+  // Create a IPCStreamSource using a PContent IPC manager on the
   // main thread.  This can return nullptr if the provided stream is
   // blocking.
-  static SendStreamChild*
+  static PChildToParentStreamChild*
   Create(nsIAsyncInputStream* aInputStream, dom::nsIContentChild* aManager);
 
-  // Create a SendStreamChild using a PBackground IPC manager on the
+  // Create a IPCStreamSource using a PBackground IPC manager on the
   // main thread or a Worker thread.  This can return nullptr if the provided
   // stream is blocking or if the Worker thread is already shutting down.
-  static SendStreamChild*
+  static PChildToParentStreamChild*
   Create(nsIAsyncInputStream* aInputStream, PBackgroundChild* aManager);
 
+  // Create a IPCStreamSource using a PContent IPC manager on the
+  // main thread.  This can return nullptr if the provided stream is
+  // blocking.
+  static PParentToChildStreamParent*
+  Create(nsIAsyncInputStream* aInputStream, dom::nsIContentParent* aManager);
+
+  // Create a IPCStreamSource using a PBackground IPC manager on the
+  // main thread or a Worker thread.  This can return nullptr if the provided
+  // stream is blocking or if the Worker thread is already shutting down.
+  static PParentToChildStreamParent*
+  Create(nsIAsyncInputStream* aInputStream, PBackgroundParent* aManager);
+
+  static IPCStreamSource*
+  Cast(PChildToParentStreamChild* aActor);
+
+  static IPCStreamSource*
+  Cast(PParentToChildStreamParent* aActor);
+
   // Start reading data from the nsIAsyncInputStream used to create the actor.
   // This must be called after the actor is passed to the parent.  If you
   // use AutoIPCStream this is handled automatically.
-  virtual void
-  Start() = 0;
+  void
+  Start();
 
   // Start cleaning up the actor.  This must be called if the actor is never
-  // sent to the parent.  If you use AutoIPCStream this is handled
+  // sent to the other side.  If you use AutoIPCStream this is handled
   // automatically.
-  virtual void
-  StartDestroy() = 0;
+  void
+  StartDestroy();
 
 protected:
-  virtual
-  ~SendStreamChild() = 0;
-};
+  IPCStreamSource(nsIAsyncInputStream* aInputStream);
+  virtual ~IPCStreamSource();
+
+  bool Initialize();
+
+  void ActorDestroyed();
+
+  void OnEnd(nsresult aRv);
+
+  virtual void
+  Close(nsresult aRv) = 0;
+
+  virtual void
+  SendData(const nsCString& aBuffer) = 0;
+
+  void
+  ActorConstructed();
+
+private:
+  class Callback;
+
+  // WorkerHolder methods
+  virtual bool
+  Notify(dom::workers::Status aStatus) override;
 
-// On the parent side, you must simply call TakeReader() upon receiving a
-// reference to the SendStreamParent actor.  You do not need to maintain a
-// reference to the actor itself.
-class SendStreamParent : public PChildToParentStreamParent
-{
-public:
-  virtual already_AddRefed<nsIInputStream>
-  TakeReader() = 0;
+  void DoRead();
+
+  void Wait();
+
+  void OnStreamReady(Callback* aCallback);
+
+  nsCOMPtr<nsIAsyncInputStream> mStream;
+  RefPtr<Callback> mCallback;
 
+  // Raw pointer because this IPCStreamSource keeps the worker alive using a
+  // WorkerHolder. The worker is kept alive when the actor is created and,
+  // released when the actor is destroyed.
+  dom::workers::WorkerPrivate* mWorkerPrivate;
+
+#ifdef DEBUG
 protected:
-  virtual
-  ~SendStreamParent() = 0;
+#endif
+
+  enum {
+   ePending,
+   eActorConstructed,
+   eClosed
+  } mState;
+
+private:
+  NS_DECL_OWNINGTHREAD
 };
 
 } // namespace ipc
 } // namespace mozilla
 
-#endif // mozilla_ipc_SendStream_h
+#endif // mozilla_ipc_IPCStreamSource_h
--- a/ipc/glue/IPCStreamUtils.cpp
+++ b/ipc/glue/IPCStreamUtils.cpp
@@ -10,96 +10,103 @@
 
 #include "mozilla/Assertions.h"
 #include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/dom/PContentParent.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
+#include "mozilla/ipc/IPCStreamDestination.h"
+#include "mozilla/ipc/IPCStreamSource.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/PBackgroundParent.h"
-#include "mozilla/ipc/SendStream.h"
 #include "mozilla/Unused.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIPipe.h"
 #include "nsStreamUtils.h"
 
 namespace mozilla {
 namespace ipc {
 
 namespace {
 
+void
+AssertValidValueToTake(const IPCStream& aVal)
+{
+  MOZ_ASSERT(aVal.type() == IPCStream::TPChildToParentStreamChild ||
+             aVal.type() == IPCStream::TPParentToChildStreamParent ||
+             aVal.type() == IPCStream::TInputStreamParamsWithFds);
+}
+
+void
+AssertValidValueToTake(const OptionalIPCStream& aVal)
+{
+  MOZ_ASSERT(aVal.type() == OptionalIPCStream::Tvoid_t ||
+             aVal.type() == OptionalIPCStream::TIPCStream);
+  if (aVal.type() == OptionalIPCStream::TIPCStream) {
+    AssertValidValueToTake(aVal.get_IPCStream());
+  }
+}
+
 // These serialization and cleanup functions could be externally exposed.  For
 // now, though, keep them private to encourage use of the safer RAII
 // AutoIPCStream class.
 
 template<typename M>
-void
-SerializeInputStreamWithFdsChild(nsIInputStream* aStream,
+bool
+SerializeInputStreamWithFdsChild(nsIIPCSerializableInputStream* aStream,
                                  IPCStream& aValue,
                                  M* aManager)
 {
-  MOZ_ASSERT(aStream);
+  MOZ_RELEASE_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
-  // First attempt simple stream serialization
-  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
-    do_QueryInterface(aStream);
-  if (!serializable) {
-    MOZ_CRASH("Input stream is not serializable!");
-  }
-
   aValue = InputStreamParamsWithFds();
   InputStreamParamsWithFds& streamWithFds =
     aValue.get_InputStreamParamsWithFds();
 
   AutoTArray<FileDescriptor, 4> fds;
-  serializable->Serialize(streamWithFds.stream(), fds);
+  aStream->Serialize(streamWithFds.stream(), fds);
 
   if (streamWithFds.stream().type() == InputStreamParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 
   if (fds.IsEmpty()) {
     streamWithFds.optionalFds() = void_t();
   } else {
     PFileDescriptorSetChild* fdSet =
       aManager->SendPFileDescriptorSetConstructor(fds[0]);
     for (uint32_t i = 1; i < fds.Length(); ++i) {
       Unused << fdSet->SendAddFileDescriptor(fds[i]);
     }
 
     streamWithFds.optionalFds() = fdSet;
   }
+
+  return true;
 }
 
 template<typename M>
-void
-SerializeInputStreamWithFdsParent(nsIInputStream* aStream,
+bool
+SerializeInputStreamWithFdsParent(nsIIPCSerializableInputStream* aStream,
                                   IPCStream& aValue,
                                   M* aManager)
 {
-  MOZ_ASSERT(aStream);
+  MOZ_RELEASE_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
-  // First attempt simple stream serialization
-  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
-    do_QueryInterface(aStream);
-  if (!serializable) {
-    MOZ_CRASH("Input stream is not serializable!");
-  }
-
   aValue = InputStreamParamsWithFds();
   InputStreamParamsWithFds& streamWithFds =
     aValue.get_InputStreamParamsWithFds();
 
   AutoTArray<FileDescriptor, 4> fds;
-  serializable->Serialize(streamWithFds.stream(), fds);
+  aStream->Serialize(streamWithFds.stream(), fds);
 
   if (streamWithFds.stream().type() == InputStreamParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 
   streamWithFds.optionalFds() = void_t();
   if (!fds.IsEmpty()) {
     PFileDescriptorSetParent* fdSet =
@@ -111,94 +118,127 @@ SerializeInputStreamWithFdsParent(nsIInp
         break;
       }
     }
 
     if (fdSet) {
       streamWithFds.optionalFds() = fdSet;
     }
   }
+
+  return true;
 }
 
 template<typename M>
-void
-SerializeInputStreamWithFdsParent(nsIInputStream* aStream,
-                                  OptionalIPCStream& aValue,
-                                  M* aManager)
-{
-  if (!aStream) {
-    aValue = void_t();
-    return;
-  }
-
-  aValue = IPCStream();
-  SerializeInputStreamWithFdsParent(aStream, aValue.get_IPCStream(), aManager);
-}
-
-template<typename M>
-void
+bool
 SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue, M* aManager)
 {
   MOZ_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
+  // As a fallback, attempt to stream the data across using a IPCStream
+  // actor. For blocking streams, create a nonblocking pipe instead,
+  nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
+  if (!asyncStream) {
+    const uint32_t kBufferSize = 32768; // matches IPCStream buffer size.
+    nsCOMPtr<nsIAsyncOutputStream> sink;
+    nsresult rv = NS_NewPipe2(getter_AddRefs(asyncStream),
+                              getter_AddRefs(sink),
+                              true,
+                              false,
+                              kBufferSize,
+                              UINT32_MAX);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return false;
+    }
+
+    nsCOMPtr<nsIEventTarget> target =
+      do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
+
+    rv = NS_AsyncCopy(aStream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
+                      kBufferSize);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return false;
+    }
+  }
+
+  MOZ_ASSERT(asyncStream);
+  aValue = IPCStreamSource::Create(asyncStream, aManager);
+  return true;
+}
+
+template<typename M>
+bool
+SerializeInputStreamChild(nsIInputStream* aStream, M* aManager,
+                          IPCStream* aValue,
+                          OptionalIPCStream* aOptionalValue)
+{
+  MOZ_ASSERT(aStream);
+  MOZ_ASSERT(aManager);
+  MOZ_ASSERT(aValue || aOptionalValue);
+
   // If a stream is known to be larger than 1MB, prefer sending it in chunks.
   const uint64_t kTooLargeStream = 1024 * 1024;
 
-  // First attempt simple stream serialization
+  nsCOMPtr<nsIIPCSerializableInputStream> serializable =
+    do_QueryInterface(aStream);
+
+  // ExpectedSerializedLength() returns the length of the stream if serialized.
+  // This is useful to decide if we want to continue using the serialization
+  // directly, or if it's better to use IPCStream.
+  uint64_t expectedLength =
+    serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
+  if (serializable && expectedLength < kTooLargeStream) {
+    if (aValue) {
+      return SerializeInputStreamWithFdsChild(serializable, *aValue, aManager);
+    }
+
+    return SerializeInputStreamWithFdsChild(serializable, *aOptionalValue,
+                                            aManager);
+  }
+
+  if (aValue) {
+    return SerializeInputStream(aStream, *aValue, aManager);
+  }
+
+  return SerializeInputStream(aStream, *aOptionalValue, aManager);
+}
+
+template<typename M>
+bool
+SerializeInputStreamParent(nsIInputStream* aStream, M* aManager,
+                           IPCStream* aValue,
+                           OptionalIPCStream* aOptionalValue)
+{
+  MOZ_ASSERT(aStream);
+  MOZ_ASSERT(aManager);
+  MOZ_ASSERT(aValue || aOptionalValue);
+
+  // If a stream is known to be larger than 1MB, prefer sending it in chunks.
+  const uint64_t kTooLargeStream = 1024 * 1024;
+
   nsCOMPtr<nsIIPCSerializableInputStream> serializable =
     do_QueryInterface(aStream);
   uint64_t expectedLength =
     serializable ? serializable->ExpectedSerializedLength().valueOr(0) : 0;
+
   if (serializable && expectedLength < kTooLargeStream) {
-    SerializeInputStreamWithFdsChild(aStream, aValue, aManager);
-    return;
+    if (aValue) {
+      return SerializeInputStreamWithFdsParent(serializable, *aValue, aManager);
+    }
+
+    return SerializeInputStreamWithFdsParent(serializable, *aOptionalValue,
+                                             aManager);
   }
 
-  // As a fallback, attempt to stream the data across using a SendStream
-  // actor. For blocking streams, create a nonblocking pipe instead,
-  nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
-  if (!asyncStream) {
-    const uint32_t kBufferSize = 32768; // matches SendStream buffer size.
-    nsCOMPtr<nsIAsyncOutputStream> sink;
-    DebugOnly<nsresult> rv = NS_NewPipe2(getter_AddRefs(asyncStream),
-                                         getter_AddRefs(sink),
-                                         true,
-                                         false,
-                                         kBufferSize,
-                                         UINT32_MAX);
-    MOZ_ASSERT(NS_SUCCEEDED(rv));
-
-    nsCOMPtr<nsIEventTarget> target =
-        do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
-
-    rv = NS_AsyncCopy(aStream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS, kBufferSize);
-    MOZ_ASSERT(NS_SUCCEEDED(rv));
+  if (aValue) {
+    return SerializeInputStream(aStream, *aValue, aManager);
   }
 
-  MOZ_ASSERT(asyncStream);
-  aValue = SendStreamChild::Create(asyncStream, aManager);
-
-  if (!aValue.get_PChildToParentStreamChild()) {
-    MOZ_CRASH("SendStream creation failed!");
-  }
-}
-
-template<typename M>
-void
-SerializeInputStream(nsIInputStream* aStream, OptionalIPCStream& aValue,
-                     M* aManager)
-{
-  if (!aStream) {
-    aValue = void_t();
-    return;
-  }
-
-  aValue = IPCStream();
-  SerializeInputStream(aStream, aValue.get_IPCStream(), aManager);
+  return SerializeInputStream(aStream, *aOptionalValue, aManager);
 }
 
 void
 CleanupIPCStream(IPCStream& aValue, bool aConsumedByIPC)
 {
   if (aValue.type() == IPCStream::T__None) {
     return;
   }
@@ -244,54 +284,86 @@ CleanupIPCStream(IPCStream& aValue, bool
       if (!aConsumedByIPC) {
         Unused << fdSetActor->Send__delete__(fdSetActor);
       }
     }
 
     return;
   }
 
-  MOZ_ASSERT(aValue.type() == IPCStream::TPChildToParentStreamChild);
+  IPCStreamSource* source = nullptr;
+  if (aValue.type() == IPCStream::TPChildToParentStreamChild) {
+    source = IPCStreamSource::Cast(aValue.get_PChildToParentStreamChild());
+  } else {
+    MOZ_ASSERT(aValue.type() == IPCStream::TPParentToChildStreamParent);
+    source = IPCStreamSource::Cast(aValue.get_PParentToChildStreamParent());
+  }
 
-  auto sendStream =
-    static_cast<SendStreamChild*>(aValue.get_PChildToParentStreamChild());
+  MOZ_ASSERT(source);
 
   if (!aConsumedByIPC) {
-    sendStream->StartDestroy();
+    source->StartDestroy();
     return;
   }
 
-  // If the SendStream was taken to be sent to the parent, then we need to
-  // start it before forgetting about it.
-  sendStream->Start();
+  // If the source stream was taken to be sent to the other side, then we need
+  // to start it before forgetting about it.
+  source->Start();
 }
 
 void
 CleanupIPCStream(OptionalIPCStream& aValue, bool aConsumedByIPC)
 {
   if (aValue.type() == OptionalIPCStream::Tvoid_t) {
     return;
   }
 
   CleanupIPCStream(aValue.get_IPCStream(), aConsumedByIPC);
 }
 
+// Returns false if the serialization should not proceed. This means that the
+// inputStream is null.
+bool
+NormalizeOptionalValue(nsIInputStream* aStream,
+                       IPCStream* aValue,
+                       OptionalIPCStream* aOptionalValue)
+{
+  if (aValue) {
+    // if aStream is null, we will crash when serializing.
+    return true;
+  }
+
+  if (!aStream) {
+    *aOptionalValue = void_t();
+    return false;
+  }
+
+  *aOptionalValue = IPCStream();
+  return true;
+}
+
 } // anonymous namespace
 
 already_AddRefed<nsIInputStream>
 DeserializeIPCStream(const IPCStream& aValue)
 {
   if (aValue.type() == IPCStream::TPChildToParentStreamParent) {
     auto sendStream =
-      static_cast<SendStreamParent*>(aValue.get_PChildToParentStreamParent());
+      IPCStreamDestination::Cast(aValue.get_PChildToParentStreamParent());
+    return sendStream->TakeReader();
+  }
+
+  if (aValue.type() == IPCStream::TPParentToChildStreamChild) {
+    auto sendStream =
+      IPCStreamDestination::Cast(aValue.get_PParentToChildStreamChild());
     return sendStream->TakeReader();
   }
 
   // Note, we explicitly do not support deserializing the PChildToParentStream actor on
-  // the child side.  It can only be sent from child to parent.
+  // the child side nor the PParentToChildStream actor on the parent side.
   MOZ_ASSERT(aValue.type() == IPCStream::TInputStreamParamsWithFds);
 
   const InputStreamParamsWithFds& streamWithFds =
     aValue.get_InputStreamParamsWithFds();
 
   AutoTArray<FileDescriptor, 4> fds;
   if (streamWithFds.optionalFds().type() ==
       OptionalFileDescriptorSet::TPFileDescriptorSetParent) {
@@ -328,37 +400,16 @@ DeserializeIPCStream(const OptionalIPCSt
 {
   if (aValue.type() == OptionalIPCStream::Tvoid_t) {
     return nullptr;
   }
 
   return DeserializeIPCStream(aValue.get_IPCStream());
 }
 
-namespace {
-
-void
-AssertValidValueToTake(const IPCStream& aVal)
-{
-  MOZ_ASSERT(aVal.type() == IPCStream::TPChildToParentStreamChild ||
-             aVal.type() == IPCStream::TInputStreamParamsWithFds);
-}
-
-void
-AssertValidValueToTake(const OptionalIPCStream& aVal)
-{
-  MOZ_ASSERT(aVal.type() == OptionalIPCStream::Tvoid_t ||
-             aVal.type() == OptionalIPCStream::TIPCStream);
-  if (aVal.type() == OptionalIPCStream::TIPCStream) {
-    AssertValidValueToTake(aVal.get_IPCStream());
-  }
-}
-
-} // anonymous namespace
-
 AutoIPCStream::AutoIPCStream()
   : mInlineValue(void_t())
   , mValue(nullptr)
   , mOptionalValue(&mInlineValue)
   , mTaken(false)
 {
 }
 
@@ -384,86 +435,123 @@ AutoIPCStream::~AutoIPCStream()
   MOZ_ASSERT(mValue || mOptionalValue);
   if (mValue && IsSet()) {
     CleanupIPCStream(*mValue, mTaken);
   } else {
     CleanupIPCStream(*mOptionalValue, mTaken);
   }
 }
 
-void
+bool
 AutoIPCStream::Serialize(nsIInputStream* aStream, dom::nsIContentChild* aManager)
 {
   MOZ_ASSERT(aStream || !mValue);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mValue || mOptionalValue);
   MOZ_ASSERT(!mTaken);
   MOZ_ASSERT(!IsSet());
 
+  // If NormalizeOptionalValue returns false, we don't have to proceed.
+  if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
+    return true;
+  }
+
+  if (!SerializeInputStreamChild(aStream, aManager, mValue, mOptionalValue)) {
+    MOZ_CRASH("IPCStream creation failed!");
+  }
+
   if (mValue) {
-    SerializeInputStream(aStream, *mValue, aManager);
     AssertValidValueToTake(*mValue);
   } else {
-    SerializeInputStream(aStream, *mOptionalValue, aManager);
     AssertValidValueToTake(*mOptionalValue);
   }
+
+  return true;
 }
 
-void
+bool
 AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundChild* aManager)
 {
   MOZ_ASSERT(aStream || !mValue);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mValue || mOptionalValue);
   MOZ_ASSERT(!mTaken);
   MOZ_ASSERT(!IsSet());
 
+  // If NormalizeOptionalValue returns false, we don't have to proceed.
+  if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
+    return true;
+  }
+
+  if (!SerializeInputStreamChild(aStream, aManager, mValue, mOptionalValue)) {
+    MOZ_CRASH("IPCStream creation failed!");
+  }
+
   if (mValue) {
-    SerializeInputStream(aStream, *mValue, aManager);
     AssertValidValueToTake(*mValue);
   } else {
-    SerializeInputStream(aStream, *mOptionalValue, aManager);
     AssertValidValueToTake(*mOptionalValue);
   }
+
+  return true;
 }
 
-void
-AutoIPCStream::Serialize(nsIInputStream* aStream, dom::PContentParent* aManager)
+bool
+AutoIPCStream::Serialize(nsIInputStream* aStream,
+                         dom::nsIContentParent* aManager)
 {
   MOZ_ASSERT(aStream || !mValue);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mValue || mOptionalValue);
   MOZ_ASSERT(!mTaken);
   MOZ_ASSERT(!IsSet());
 
+  // If NormalizeOptionalValue returns false, we don't have to proceed.
+  if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
+    return true;
+  }
+
+  if (!SerializeInputStreamParent(aStream, aManager, mValue, mOptionalValue)) {
+    return false;
+  }
+
   if (mValue) {
-    SerializeInputStreamWithFdsParent(aStream, *mValue, aManager);
     AssertValidValueToTake(*mValue);
   } else {
-    SerializeInputStreamWithFdsParent(aStream, *mOptionalValue, aManager);
     AssertValidValueToTake(*mOptionalValue);
   }
+
+  return true;
 }
 
-void
+bool
 AutoIPCStream::Serialize(nsIInputStream* aStream, PBackgroundParent* aManager)
 {
   MOZ_ASSERT(aStream || !mValue);
   MOZ_ASSERT(aManager);
   MOZ_ASSERT(mValue || mOptionalValue);
   MOZ_ASSERT(!mTaken);
   MOZ_ASSERT(!IsSet());
 
+  // If NormalizeOptionalValue returns false, we don't have to proceed.
+  if (!NormalizeOptionalValue(aStream, mValue, mOptionalValue)) {
+    return true;
+  }
+
+  if (!SerializeInputStreamParent(aStream, aManager, mValue, mOptionalValue)) {
+    return false;
+  }
+
   if (mValue) {
-    SerializeInputStreamWithFdsParent(aStream, *mValue, aManager);
     AssertValidValueToTake(*mValue);
   } else {
-    SerializeInputStreamWithFdsParent(aStream, *mOptionalValue, aManager);
     AssertValidValueToTake(*mOptionalValue);
   }
+
+  return true;
 }
 
 bool
 AutoIPCStream::IsSet() const
 {
   MOZ_ASSERT(mValue || mOptionalValue);
   if (mValue) {
     return mValue->type() != IPCStream::T__None;
--- a/ipc/glue/IPCStreamUtils.h
+++ b/ipc/glue/IPCStreamUtils.h
@@ -9,17 +9,17 @@
 
 #include "mozilla/ipc/IPCStream.h"
 #include "nsIInputStream.h"
 
 namespace mozilla {
 
 namespace dom {
 class nsIContentChild;
-class PContentParent;
+class nsIContentParent;
 }
 
 namespace ipc {
 
 class PBackgroundChild;
 class PBackgroundParent;
 
 // Deserialize an IPCStream received from an actor call.  These methods
@@ -96,16 +96,19 @@ DeserializeIPCStream(const OptionalIPCSt
 //
 //  // in parent c++ code
 //  bool
 //  MyStuffParent::RecvDoStuff(const Stuff& aStuff) {
 //    nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aStuff.stream());
 //    /* do something with the nsIInputStream */
 //  }
 //
+// Note: This example is about child-to-parent inputStream, but AutoIPCStream
+// works also parent-to-child.
+//
 // The AutoIPCStream class also supports OptionalIPCStream values.  As long as
 // you did not initialize the object with a non-optional IPCStream, you can call
 // TakeOptionalValue() instead.
 //
 // The AutoIPCStream class can also be used to serialize nsIInputStream objects
 // on the parent side to send to the child.  Currently, however, this only
 // works for directly serializable stream types.  The PChildToParentStream actor
 // mechanism is not supported in this direction yet.
@@ -141,45 +144,43 @@ public:
   // or TakeOptionalValue can be used.
   explicit AutoIPCStream(OptionalIPCStream& aTarget);
 
   ~AutoIPCStream();
 
   // Serialize the input stream or create a SendStream actor using the PContent
   // manager.  If neither of these succeed, then crash.  This should only be
   // used on the main thread.
-  void
+  bool
   Serialize(nsIInputStream* aStream, dom::nsIContentChild* aManager);
 
   // Serialize the input stream or create a SendStream actor using the
   // PBackground manager.  If neither of these succeed, then crash.  This can
   // be called on the main thread or Worker threads.
-  void
+  bool
   Serialize(nsIInputStream* aStream, PBackgroundChild* aManager);
 
-  // Serialize the input stream.  A PChildToParentStream cannot be used when going
-  // from parent-to-child.
-  void
-  Serialize(nsIInputStream* aStream, dom::PContentParent* aManager);
+  // Serialize the input stream.
+  MOZ_MUST_USE bool
+  Serialize(nsIInputStream* aStream, dom::nsIContentParent* aManager);
 
-  // Serialize the input stream.  A PChildToParentStream cannot be used when going
-  // from parent-to-child.
-  void
+  // Serialize the input stream.
+  MOZ_MUST_USE bool
   Serialize(nsIInputStream* aStream, PBackgroundParent* aManager);
 
   // Get the IPCStream as a non-optional value.  This will
   // assert if a stream has not been serialized or if it has already been taken.
   // This should only be called if the value is being, or has already been, sent
-  // to the parent
+  // to the other side.
   IPCStream&
   TakeValue();
 
   // Get the OptionalIPCStream value.  This will assert if
   // the value has already been taken.  This should only be called if the value
-  // is being, or has already been, sent to the parent
+  // is being, or has already been, sent to the other side.
   OptionalIPCStream&
   TakeOptionalValue();
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_IPCStreamUtils_h
--- a/ipc/glue/MessageLink.cpp
+++ b/ipc/glue/MessageLink.cpp
@@ -13,16 +13,17 @@
 
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "nsDebug.h"
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 #include "nsISupportsImpl.h"
+#include "nsPrintfCString.h"
 #include "nsXULAppAPI.h"
 
 using namespace mozilla;
 using namespace std;
 
 // We rely on invariants about the lifetime of the transport:
 //
 //  - outlives this MessageChannel
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -14,16 +14,17 @@ include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
 include protocol PFileSystemRequest;
 include protocol PGamepadEventChannel;
 include protocol PGamepadTestChannel;
 include protocol PMessagePort;
 include protocol PCameras;
 include protocol PQuota;
 include protocol PChildToParentStream;
+include protocol PParentToChildStream;
 include protocol PServiceWorkerManager;
 include protocol PUDPSocket;
 include protocol PVsync;
 
 include DOMTypes;
 include PBackgroundSharedTypes;
 include PBackgroundIDBSharedTypes;
 include PFileSystemParams;
@@ -57,16 +58,17 @@ sync protocol PBackground
   manages PFileDescriptorSet;
   manages PFileSystemRequest;
   manages PGamepadEventChannel;
   manages PGamepadTestChannel;
   manages PMessagePort;
   manages PCameras;
   manages PQuota;
   manages PChildToParentStream;
+  manages PParentToChildStream;
   manages PServiceWorkerManager;
   manages PUDPSocket;
   manages PVsync;
 
 parent:
   // Only called at startup during mochitests to check the basic infrastructure.
   async PBackgroundTest(nsCString testArg);
 
@@ -107,16 +109,18 @@ parent:
   async PGamepadEventChannel();
 
   async PGamepadTestChannel();
 
 child:
   async PCache();
   async PCacheStreamControl();
 
+  async PParentToChildStream();
+
 both:
   async PBlob(BlobConstructorParams params);
 
   async PFileDescriptorSet(FileDescriptor fd);
 };
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/PChildToParentStream.ipdl
+++ b/ipc/glue/PChildToParentStream.ipdl
@@ -4,16 +4,18 @@
 
 include protocol PBackground;
 include protocol PContent;
 include protocol PContentBridge;
 
 namespace mozilla {
 namespace ipc {
 
+// This is protocol is the opposite of PParentToChildStream. Please keep these
+// protocols in sync.
 protocol PChildToParentStream
 {
   manager PBackground or PContent or PContentBridge;
 
 parent:
   async Buffer(nsCString aBuffer);
   async Close(nsresult aRv);
 
copy from ipc/glue/PChildToParentStream.ipdl
copy to ipc/glue/PParentToChildStream.ipdl
--- a/ipc/glue/PChildToParentStream.ipdl
+++ b/ipc/glue/PParentToChildStream.ipdl
@@ -4,25 +4,27 @@
 
 include protocol PBackground;
 include protocol PContent;
 include protocol PContentBridge;
 
 namespace mozilla {
 namespace ipc {
 
-protocol PChildToParentStream
+// This is protocol is the opposite of PChildToParentStream. Please keep these
+// protocols in sync.
+protocol PParentToChildStream
 {
   manager PBackground or PContent or PContentBridge;
 
-parent:
+child:
   async Buffer(nsCString aBuffer);
   async Close(nsresult aRv);
 
-child:
+parent:
   // The parent side has hit an error condition and has requested the child
   // actor issue a Close() message.  The close must be initiated by the child
   // to avoid racing with an in-flight Buffer() message.
   async RequestClose(nsresult aRv);
 
   // Stream is always destroyed from the parent side.  This occurs if the
   // parent encounters an error while writing to its pipe or if the child
   // signals the stream should close by SendClose().
--- a/ipc/glue/moz.build
+++ b/ipc/glue/moz.build
@@ -22,25 +22,26 @@ EXPORTS.mozilla.ipc += [
     'CrossProcessSemaphore.h',
     'FileDescriptor.h',
     'FileDescriptorSetChild.h',
     'FileDescriptorSetParent.h',
     'FileDescriptorUtils.h',
     'GeckoChildProcessHost.h',
     'InputStreamUtils.h',
     'IOThreadChild.h',
+    'IPCStreamAlloc.h',
+    'IPCStreamDestination.h',
+    'IPCStreamSource.h',
     'IPCStreamUtils.h',
     'MessageChannel.h',
     'MessageLink.h',
     'Neutering.h',
     'ProcessChild.h',
     'ProtocolUtils.h',
     'ScopedXREEmbed.h',
-    'SendStream.h',
-    'SendStreamAlloc.h',
     'SharedMemory.h',
     'SharedMemoryBasic.h',
     'Shmem.h',
     'TaskFactory.h',
     'Transport.h',
     'URIUtils.h',
     'WindowsMessageLoop.h',
 ]
@@ -138,25 +139,27 @@ UNIFIED_SOURCES += [
     'BrowserProcessSubThread.cpp',
     'CrashReporterClient.cpp',
     'CrashReporterHost.cpp',
     'CrashReporterMetadataShmem.cpp',
     'FileDescriptor.cpp',
     'FileDescriptorUtils.cpp',
     'InputStreamUtils.cpp',
     'IPCMessageUtils.cpp',
+    'IPCStreamChild.cpp',
+    'IPCStreamDestination.cpp',
+    'IPCStreamParent.cpp',
+    'IPCStreamSource.cpp',
     'IPCStreamUtils.cpp',
     'MessageChannel.cpp',
     'MessageLink.cpp',
     'MessagePump.cpp',
     'ProcessChild.cpp',
     'ProtocolUtils.cpp',
     'ScopedXREEmbed.cpp',
-    'SendStreamChild.cpp',
-    'SendStreamParent.cpp',
     'SharedMemory.cpp',
     'Shmem.cpp',
     'StringUtil.cpp',
 ]
 
 # GeckoChildProcessHost.cpp cannot be built in unified mode because it uses plarena.h.
 # URIUtils.cpp cannot be built in unified mode because of name clashes on strdup.
 SOURCES += [
@@ -186,16 +189,17 @@ LOCAL_INCLUDES += [
 IPDL_SOURCES = [
     'InputStreamParams.ipdlh',
     'IPCStream.ipdlh',
     'PBackground.ipdl',
     'PBackgroundSharedTypes.ipdlh',
     'PBackgroundTest.ipdl',
     'PChildToParentStream.ipdl',
     'PFileDescriptorSet.ipdl',
+    'PParentToChildStream.ipdl',
     'ProtocolTypes.ipdlh',
     'URIParams.ipdlh',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/ipc',
     '/toolkit/crashreporter',
     '/toolkit/xre',
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -17,17 +17,18 @@ include protocol PTCPSocket;
 include protocol PTCPServerSocket;
 include protocol PUDPSocket;
 include protocol PDNSRequest;
 include protocol PChannelDiverter;
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet;
 include protocol PDataChannel;
 include protocol PTransportProvider;
-include protocol PChildToParentStream;
+include protocol PChildToParentStream; //FIXME: bug #792908
+include protocol PParentToChildStream; //FIXME: bug #792908
 
 include protocol PRtspController;
 include protocol PRtspChannel;
 include URIParams;
 include NeckoChannelParams;
 include PBrowserOrId;
 include protocol PAltDataOutputStream;
 
@@ -140,16 +141,16 @@ child:
   async PredOnPredictDNS(URIParams uri);
 
   async SpeculativeConnectRequest();
 
   async PTransportProvider();
 
 both:
   // Actually we need PTCPSocket() for parent. But ipdl disallows us having different
-  // signatures on parent and child. So when constructing the parent side object, we just 
+  // signatures on parent and child. So when constructing the parent side object, we just
   // leave host/port unused.
   async PTCPSocket(nsString host, uint16_t port);
 };
 
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/protocol/websocket/PWebSocket.ipdl
+++ b/netwerk/protocol/websocket/PWebSocket.ipdl
@@ -10,16 +10,17 @@ include protocol PBrowser;
 include protocol PTransportProvider;
 include IPCStream;
 include URIParams;
 include NeckoChannelParams;
 
 include protocol PBlob; //FIXME: bug #792908
 include protocol PFileDescriptorSet; //FIXME: bug #792908
 include protocol PChildToParentStream; //FIXME: bug #792908
+include protocol PParentToChildStream; //FIXME: bug #792908
 
 using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace net {
 
 union OptionalTransportProvider