Bug 1353629 - PBlob refactoring - part 4 - IPCBlobInputStream, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 24 Apr 2017 12:09:40 +0200
changeset 354619 e9400156bf733aa1a928969529eea5d5e6ed7f98
parent 354618 e257576d44a4bcee8eef180c67f5f2318def5d90
child 354620 8fd6cad1a8d9198d0c91a03aafb18126592d3e98
push id31707
push userkwierso@gmail.com
push dateMon, 24 Apr 2017 22:53:41 +0000
treeherdermozilla-central@abdcc8dfc283 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1353629
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 1353629 - PBlob refactoring - part 4 - IPCBlobInputStream, r=smaug IPCBlobInputStream is a new type of nsIInputStream that is used only in content process when a Blob is sent from parent to child. This inputStream is for now, just cloneable. When the parent process sends a Blob to a content process, it has the Blob and its inputStream. With its inputStream it creates a IPCBlobInputStreamParent actor. This actor keeps the inputStream alive for following uses (not part of this patch). On the child side we will have, of course, a IPCBlobInputStreamChild actor. This actor is able to create a IPCBlobInputStream when CreateStream() is called. This means that 1 IPCBlobInputStreamChild can manage multiple IPCBlobInputStreams each time one of them is cloned. When the last one of this stream is released, the child actor sends a __delete__ request to the parent side; the parent will be deleted, and the original inputStream, on the parent side, will be released as well. IPCBlobInputStream is a special inputStream because each method, except for Available() fails. Basically, this inputStream cannot be used on the content process for nothing else than knowing the size of the original stream. In the following patches, I'll introduce an async way to use it.
dom/broadcastchannel/PBroadcastChannel.ipdl
dom/file/ipc/IPCBlobInputStream.cpp
dom/file/ipc/IPCBlobInputStream.h
dom/file/ipc/IPCBlobInputStreamChild.cpp
dom/file/ipc/IPCBlobInputStreamChild.h
dom/file/ipc/IPCBlobInputStreamParent.cpp
dom/file/ipc/IPCBlobInputStreamParent.h
dom/file/ipc/PIPCBlobInputStream.ipdl
dom/file/ipc/moz.build
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/PBrowser.ipdl
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/messagechannel/PMessagePort.ipdl
ipc/glue/BackgroundChildImpl.cpp
ipc/glue/BackgroundChildImpl.h
ipc/glue/BackgroundParentImpl.cpp
ipc/glue/BackgroundParentImpl.h
ipc/glue/PBackground.ipdl
--- a/dom/broadcastchannel/PBroadcastChannel.ipdl
+++ b/dom/broadcastchannel/PBroadcastChannel.ipdl
@@ -1,16 +1,17 @@
 /* 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 PBackground;
 include protocol PBlob;
 include protocol PChildToParentStream;
 include protocol PFileDescriptorSet;
+include protocol PIPCBlobInputStream;
 include protocol PParentToChildStream;
 include DOMTypes;
 
 using struct mozilla::SerializedStructuredCloneBuffer from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace dom {
 
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/IPCBlobInputStream.cpp
@@ -0,0 +1,98 @@
+/* -*- 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 "IPCBlobInputStream.h"
+#include "IPCBlobInputStreamChild.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_ADDREF(IPCBlobInputStream);
+NS_IMPL_RELEASE(IPCBlobInputStream);
+
+NS_INTERFACE_MAP_BEGIN(IPCBlobInputStream)
+  NS_INTERFACE_MAP_ENTRY(nsIInputStream)
+  NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
+NS_INTERFACE_MAP_END
+
+IPCBlobInputStream::IPCBlobInputStream(IPCBlobInputStreamChild* aActor)
+  : mActor(aActor)
+{
+  MOZ_ASSERT(aActor);
+}
+
+IPCBlobInputStream::~IPCBlobInputStream()
+{
+  Close();
+}
+
+// nsIInputStream interface
+
+NS_IMETHODIMP
+IPCBlobInputStream::Available(uint64_t* aLength)
+{
+  if (!mActor) {
+    return NS_BASE_STREAM_CLOSED;
+  }
+
+  *aLength = mActor->Size();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IPCBlobInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+IPCBlobInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
+                                 uint32_t aCount, uint32_t *aResult)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+IPCBlobInputStream::IsNonBlocking(bool* aNonBlocking)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+IPCBlobInputStream::Close()
+{
+  if (mActor) {
+    mActor->ForgetStream(this);
+    mActor = nullptr;
+  }
+
+  return NS_OK;
+}
+
+// nsICloneableInputStream interface
+
+NS_IMETHODIMP
+IPCBlobInputStream::GetCloneable(bool* aCloneable)
+{
+  *aCloneable = !!mActor;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IPCBlobInputStream::Clone(nsIInputStream** aResult)
+{
+  if (!mActor) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIInputStream> stream = mActor->CreateStream();
+  stream.forget(aResult);
+  return NS_OK;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/IPCBlobInputStream.h
@@ -0,0 +1,37 @@
+/* -*- 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_dom_ipc_IPCBlobInputStream_h
+#define mozilla_dom_ipc_IPCBlobInputStream_h
+
+#include "nsIInputStream.h"
+#include "nsICloneableInputStream.h"
+
+namespace mozilla {
+namespace dom {
+
+class IPCBlobInputStreamChild;
+
+class IPCBlobInputStream final : public nsIInputStream
+                               , public nsICloneableInputStream
+{
+public:
+  NS_DECL_THREADSAFE_ISUPPORTS
+  NS_DECL_NSIINPUTSTREAM
+  NS_DECL_NSICLONEABLEINPUTSTREAM
+
+  explicit IPCBlobInputStream(IPCBlobInputStreamChild* aActor);
+
+private:
+  ~IPCBlobInputStream();
+
+  RefPtr<IPCBlobInputStreamChild> mActor;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ipc_IPCBlobInputStream_h
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/IPCBlobInputStreamChild.cpp
@@ -0,0 +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 "IPCBlobInputStreamChild.h"
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+
+// This runnable is used in case the last stream is forgotten on the 'wrong'
+// thread.
+class DeleteRunnable final : public Runnable
+{
+public:
+  explicit DeleteRunnable(IPCBlobInputStreamChild* aActor)
+    : mActor(aActor)
+  {}
+
+  NS_IMETHOD
+  Run() override
+  {
+    mActor->Send__delete__(mActor);
+    return NS_OK;
+  }
+
+private:
+  RefPtr<IPCBlobInputStreamChild> mActor;
+};
+
+} // anonymous
+
+IPCBlobInputStreamChild::IPCBlobInputStreamChild(const nsID& aID,
+                                                 uint64_t aSize)
+  : mMutex("IPCBlobInputStreamChild::mMutex")
+  , mID(aID)
+  , mSize(aSize)
+  , mActorAlive(true)
+  , mOwningThread(NS_GetCurrentThread())
+{}
+
+IPCBlobInputStreamChild::~IPCBlobInputStreamChild()
+{}
+
+void
+IPCBlobInputStreamChild::ActorDestroy(IProtocol::ActorDestroyReason aReason)
+{
+  mActorAlive = false;
+}
+
+already_AddRefed<nsIInputStream>
+IPCBlobInputStreamChild::CreateStream()
+{
+  MutexAutoLock lock(mMutex);
+
+  RefPtr<IPCBlobInputStream> stream = new IPCBlobInputStream(this);
+  mStreams.AppendElement(stream);
+  return stream.forget();
+}
+
+void
+IPCBlobInputStreamChild::ForgetStream(IPCBlobInputStream* aStream)
+{
+  MOZ_ASSERT(aStream);
+
+  RefPtr<IPCBlobInputStreamChild> kungFoDeathGrip = this;
+
+  {
+    MutexAutoLock lock(mMutex);
+    mStreams.RemoveElement(aStream);
+
+    if (!mStreams.IsEmpty() || !mActorAlive) {
+      return;
+    }
+  }
+
+  if (mOwningThread == NS_GetCurrentThread()) {
+    Send__delete__(this);
+    return;
+  }
+
+  RefPtr<DeleteRunnable> runnable = new DeleteRunnable(this);
+  mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/IPCBlobInputStreamChild.h
@@ -0,0 +1,66 @@
+/* -*- 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_dom_ipc_IPCBlobInputStreamChild_h
+#define mozilla_dom_ipc_IPCBlobInputStreamChild_h
+
+#include "mozilla/ipc/PIPCBlobInputStreamChild.h"
+#include "mozilla/Mutex.h"
+#include "nsIThread.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+class IPCBlobInputStream;
+
+class IPCBlobInputStreamChild final
+  : public mozilla::ipc::PIPCBlobInputStreamChild
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(IPCBlobInputStreamChild)
+
+  IPCBlobInputStreamChild(const nsID& aID, uint64_t aSize);
+
+  void
+  ActorDestroy(IProtocol::ActorDestroyReason aReason) override;
+
+  already_AddRefed<nsIInputStream>
+  CreateStream();
+
+  void
+  ForgetStream(IPCBlobInputStream* aStream);
+
+  uint64_t
+  Size() const
+  {
+    return mSize;
+  }
+
+private:
+  ~IPCBlobInputStreamChild();
+
+  // Raw pointers because these streams keep this actor alive. When the last
+  // stream is unregister, the actor will be deleted. This list is protected by
+  // mutex.
+  nsTArray<IPCBlobInputStream*> mStreams;
+
+  // This mutex protects mStreams because that can be touched in any thread.
+  Mutex mMutex;
+
+  const nsID mID;
+  const uint64_t mSize;
+
+  // false when ActorDestroy() is called.
+  bool mActorAlive;
+
+  nsCOMPtr<nsIThread> mOwningThread;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ipc_IPCBlobInputStreamChild_h
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/IPCBlobInputStreamParent.cpp
@@ -0,0 +1,44 @@
+/* -*- 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 "IPCBlobInputStreamParent.h"
+#include "nsContentUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+/* static */ IPCBlobInputStreamParent*
+IPCBlobInputStreamParent::Create(nsIInputStream* aInputStream, uint64_t aSize,
+                                 nsresult* aRv)
+{
+  MOZ_ASSERT(aInputStream);
+  MOZ_ASSERT(aRv);
+
+  nsID id;
+  *aRv = nsContentUtils::GenerateUUIDInPlace(id);
+  if (NS_WARN_IF(NS_FAILED(*aRv))) {
+    return nullptr;
+  }
+
+  // TODO: register to a service.
+
+  return new IPCBlobInputStreamParent(id, aSize);
+}
+
+IPCBlobInputStreamParent::IPCBlobInputStreamParent(const nsID& aID,
+                                                   uint64_t aSize)
+  : mID(aID)
+  , mSize(aSize)
+{}
+
+void
+IPCBlobInputStreamParent::ActorDestroy(IProtocol::ActorDestroyReason aReason)
+{
+  // TODO: unregister
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/IPCBlobInputStreamParent.h
@@ -0,0 +1,52 @@
+/* -*- 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_dom_ipc_IPCBlobInputStreamParent_h
+#define mozilla_dom_ipc_IPCBlobInputStreamParent_h
+
+#include "mozilla/ipc/PIPCBlobInputStreamParent.h"
+
+class nsIInputStream;
+
+namespace mozilla {
+namespace dom {
+
+class IPCBlobInputStreamParent final
+  : public mozilla::ipc::PIPCBlobInputStreamParent
+{
+public:
+  // The size of the inputStream must be passed as argument in order to avoid
+  // the use of nsIInputStream::Available() which could open a fileDescriptor in
+  // case the stream is a nsFileStream.
+  static IPCBlobInputStreamParent*
+  Create(nsIInputStream* aInputStream, uint64_t aSize, nsresult* aRv);
+
+  void
+  ActorDestroy(IProtocol::ActorDestroyReason aReason) override;
+
+  const nsID&
+  ID() const
+  {
+    return mID;
+  }
+
+  uint64_t
+  Size() const
+  {
+    return mSize;
+  }
+
+private:
+  IPCBlobInputStreamParent(const nsID& aID, uint64_t aSize);
+
+  const nsID mID;
+  const uint64_t mSize;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_ipc_IPCBlobInputStreamParent_h
new file mode 100644
--- /dev/null
+++ b/dom/file/ipc/PIPCBlobInputStream.ipdl
@@ -0,0 +1,22 @@
+/* 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 PBackground;
+include protocol PContent;
+include protocol PContentBridge;
+
+namespace mozilla {
+namespace ipc {
+
+protocol PIPCBlobInputStream
+{
+  manager PBackground or PContent or PContentBridge;
+
+parent:
+  async __delete__();
+};
+
+} // namespace dom
+} // namespace mozilla
+
--- a/dom/file/ipc/moz.build
+++ b/dom/file/ipc/moz.build
@@ -2,36 +2,43 @@
 # vim: set filetype=python:
 # 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/.
 
 EXPORTS.mozilla.dom.ipc += [
     'BlobChild.h',
     'BlobParent.h',
+    'IPCBlobInputStream.h',
+    'IPCBlobInputStreamChild.h',
+    'IPCBlobInputStreamParent.h',
     'MemoryStreamChild.h',
     'MemoryStreamParent.h',
     'nsIRemoteBlob.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'IPCBlobUtils.h',
 ]
 
 UNIFIED_SOURCES += [
     'Blob.cpp',
+    'IPCBlobInputStream.cpp',
+    'IPCBlobInputStreamChild.cpp',
+    'IPCBlobInputStreamParent.cpp',
     'IPCBlobUtils.cpp',
     'MemoryStreamParent.cpp',
 ]
 
 IPDL_SOURCES += [
     'BlobTypes.ipdlh',
     'IPCBlob.ipdlh',
     'PBlob.ipdl',
     'PBlobStream.ipdl',
+    'PIPCBlobInputStream.ipdl',
     'PMemoryStream.ipdl',
 ]
 
 LOCAL_INCLUDES += [
     '/dom/file',
     '/dom/ipc',
     '/dom/workers',
 ]
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -187,16 +187,29 @@ ContentBridgeChild::AllocPMemoryStreamCh
 }
 
 bool
 ContentBridgeChild::DeallocPMemoryStreamChild(PMemoryStreamChild* aActor)
 {
   return nsIContentChild::DeallocPMemoryStreamChild(aActor);
 }
 
+PIPCBlobInputStreamChild*
+ContentBridgeChild::AllocPIPCBlobInputStreamChild(const nsID& aID,
+                                                  const uint64_t& aSize)
+{
+  return nsIContentChild::AllocPIPCBlobInputStreamChild(aID, aSize);
+}
+
+bool
+ContentBridgeChild::DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor)
+{
+  return nsIContentChild::DeallocPIPCBlobInputStreamChild(aActor);
+}
+
 PChildToParentStreamChild*
 ContentBridgeChild::AllocPChildToParentStreamChild()
 {
   return nsIContentChild::AllocPChildToParentStreamChild();
 }
 
 bool
 ContentBridgeChild::DeallocPChildToParentStreamChild(PChildToParentStreamChild* aActor)
--- a/dom/ipc/ContentBridgeChild.h
+++ b/dom/ipc/ContentBridgeChild.h
@@ -87,16 +87,23 @@ protected:
 
   virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams) override;
   virtual bool DeallocPBlobChild(PBlobChild*) override;
 
   virtual PMemoryStreamChild*
   AllocPMemoryStreamChild(const uint64_t& aSize) override;
   virtual bool DeallocPMemoryStreamChild(PMemoryStreamChild*) override;
 
+  virtual PIPCBlobInputStreamChild*
+  AllocPIPCBlobInputStreamChild(const nsID& aID,
+                                const uint64_t& aSize) override;
+
+  virtual bool
+  DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild*) override;
+
   virtual mozilla::ipc::PChildToParentStreamChild*
   AllocPChildToParentStreamChild() override;
 
   virtual bool
   DeallocPChildToParentStreamChild(mozilla::ipc::PChildToParentStreamChild* aActor) override;
 
   virtual PParentToChildStreamChild* AllocPParentToChildStreamChild() override;
 
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -126,28 +126,50 @@ ContentBridgeParent::AllocPBlobParent(co
 }
 
 bool
 ContentBridgeParent::DeallocPBlobParent(PBlobParent* aActor)
 {
   return nsIContentParent::DeallocPBlobParent(aActor);
 }
 
+PIPCBlobInputStreamParent*
+ContentBridgeParent::SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor,
+                                                        const nsID& aID,
+                                                        const uint64_t& aSize)
+{
+  return
+    PContentBridgeParent::SendPIPCBlobInputStreamConstructor(aActor, aID, aSize);
+}
+
 PMemoryStreamParent*
 ContentBridgeParent::AllocPMemoryStreamParent(const uint64_t& aSize)
 {
   return nsIContentParent::AllocPMemoryStreamParent(aSize);
 }
 
 bool
 ContentBridgeParent::DeallocPMemoryStreamParent(PMemoryStreamParent* aActor)
 {
   return nsIContentParent::DeallocPMemoryStreamParent(aActor);
 }
 
+PIPCBlobInputStreamParent*
+ContentBridgeParent::AllocPIPCBlobInputStreamParent(const nsID& aID,
+                                                    const uint64_t& aSize)
+{
+  return nsIContentParent::AllocPIPCBlobInputStreamParent(aID, aSize);
+}
+
+bool
+ContentBridgeParent::DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor)
+{
+  return nsIContentParent::DeallocPIPCBlobInputStreamParent(aActor);
+}
+
 mozilla::jsipc::PJavaScriptParent *
 ContentBridgeParent::AllocPJavaScriptParent()
 {
   return nsIContentParent::AllocPJavaScriptParent();
 }
 
 bool
 ContentBridgeParent::DeallocPJavaScriptParent(PJavaScriptParent *parent)
--- a/dom/ipc/ContentBridgeParent.h
+++ b/dom/ipc/ContentBridgeParent.h
@@ -138,16 +138,28 @@ protected:
 
   virtual bool DeallocPBlobParent(PBlobParent*) override;
 
   virtual PMemoryStreamParent*
   AllocPMemoryStreamParent(const uint64_t& aSize) override;
 
   virtual bool DeallocPMemoryStreamParent(PMemoryStreamParent*) override;
 
+  virtual PIPCBlobInputStreamParent*
+  SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor,
+                                     const nsID& aID,
+                                     const uint64_t& aSize) override;
+
+  virtual PIPCBlobInputStreamParent*
+  AllocPIPCBlobInputStreamParent(const nsID& aID,
+                                 const uint64_t& aSize) override;
+
+  virtual bool
+  DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent*) override;
+
   virtual PChildToParentStreamParent* AllocPChildToParentStreamParent() override;
 
   virtual bool
   DeallocPChildToParentStreamParent(PChildToParentStreamParent* aActor) override;
 
   virtual mozilla::ipc::PParentToChildStreamParent*
   AllocPParentToChildStreamParent() override;
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -1579,16 +1579,29 @@ ContentChild::AllocPMemoryStreamChild(co
 }
 
 bool
 ContentChild::DeallocPMemoryStreamChild(PMemoryStreamChild* aActor)
 {
   return nsIContentChild::DeallocPMemoryStreamChild(aActor);
 }
 
+PIPCBlobInputStreamChild*
+ContentChild::AllocPIPCBlobInputStreamChild(const nsID& aID,
+                                            const uint64_t& aSize)
+{
+  return nsIContentChild::AllocPIPCBlobInputStreamChild(aID, aSize);
+}
+
+bool
+ContentChild::DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor)
+{
+  return nsIContentChild::DeallocPIPCBlobInputStreamChild(aActor);
+}
+
 PBlobChild*
 ContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
 {
   return nsIContentChild::AllocPBlobChild(aParams);
 }
 
 mozilla::PRemoteSpellcheckEngineChild *
 ContentChild::AllocPRemoteSpellcheckEngineChild()
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -186,16 +186,23 @@ public:
   virtual bool DeallocPBlobChild(PBlobChild* aActor) override;
 
   virtual PMemoryStreamChild*
   AllocPMemoryStreamChild(const uint64_t& aSize) override;
 
   virtual bool
   DeallocPMemoryStreamChild(PMemoryStreamChild* aActor) override;
 
+  virtual PIPCBlobInputStreamChild*
+  AllocPIPCBlobInputStreamChild(const nsID& aID,
+                                const uint64_t& aSize) override;
+
+  virtual bool
+  DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor) override;
+
   virtual PHalChild* AllocPHalChild() override;
   virtual bool DeallocPHalChild(PHalChild*) override;
 
   virtual PHeapSnapshotTempFileHelperChild*
   AllocPHeapSnapshotTempFileHelperChild() override;
 
   virtual bool
   DeallocPHeapSnapshotTempFileHelperChild(PHeapSnapshotTempFileHelperChild*) override;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2833,16 +2833,29 @@ ContentParent::AllocPMemoryStreamParent(
 }
 
 bool
 ContentParent::DeallocPMemoryStreamParent(PMemoryStreamParent* aActor)
 {
   return nsIContentParent::DeallocPMemoryStreamParent(aActor);
 }
 
+PIPCBlobInputStreamParent*
+ContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID,
+                                              const uint64_t& aSize)
+{
+  return nsIContentParent::AllocPIPCBlobInputStreamParent(aID, aSize);
+}
+
+bool
+ContentParent::DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor)
+{
+  return nsIContentParent::DeallocPIPCBlobInputStreamParent(aActor);
+}
+
 mozilla::ipc::IPCResult
 ContentParent::RecvPBlobConstructor(PBlobParent* aActor,
                                     const BlobConstructorParams& aParams)
 {
   const ParentBlobConstructorParams& params = aParams.get_ParentBlobConstructorParams();
   if (params.blobParams().type() == AnyBlobConstructorParams::TKnownBlobConstructorParams) {
     if (!aActor->SendCreatedFromKnownBlob()) {
       return IPC_FAIL_NO_REASON(this);
@@ -3830,16 +3843,24 @@ ContentParent::DoSendAsyncMessage(JSCont
 
 PBlobParent*
 ContentParent::SendPBlobConstructor(PBlobParent* aActor,
                                     const BlobConstructorParams& aParams)
 {
   return PContentParent::SendPBlobConstructor(aActor, aParams);
 }
 
+PIPCBlobInputStreamParent*
+ContentParent::SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor,
+                                                  const nsID& aID,
+                                                  const uint64_t& aSize)
+{
+  return PContentParent::SendPIPCBlobInputStreamConstructor(aActor, aID, aSize);
+}
+
 PBrowserParent*
 ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
                                        const TabId& aTabId,
                                        const TabId& aSameTabGroupAs,
                                        const IPCTabContext& aContext,
                                        const uint32_t& aChromeFlags,
                                        const ContentParentId& aCpId,
                                        const bool& aIsForBrowser)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -846,16 +846,28 @@ private:
 
   virtual bool DeallocPBlobParent(PBlobParent* aActor) override;
 
   virtual PMemoryStreamParent*
   AllocPMemoryStreamParent(const uint64_t& aSize) override;
 
   virtual bool DeallocPMemoryStreamParent(PMemoryStreamParent* aActor) override;
 
+  virtual PIPCBlobInputStreamParent*
+  SendPIPCBlobInputStreamConstructor(PIPCBlobInputStreamParent* aActor,
+                                     const nsID& aID,
+                                     const uint64_t& aSize) override;
+
+  virtual PIPCBlobInputStreamParent*
+  AllocPIPCBlobInputStreamParent(const nsID& aID,
+                                 const uint64_t& aSize) override;
+
+  virtual bool
+  DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor) override;
+
   virtual mozilla::ipc::IPCResult
   RecvPBlobConstructor(PBlobParent* aActor,
                        const BlobConstructorParams& params) override;
 
   virtual mozilla::ipc::IPCResult RecvNSSU2FTokenIsCompatibleVersion(const nsString& aVersion,
                                                                      bool* aIsCompatible) override;
 
   virtual mozilla::ipc::IPCResult RecvNSSU2FTokenIsRegistered(nsTArray<uint8_t>&& aKeyHandle,
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -14,16 +14,18 @@ include protocol PDocumentRenderer;
 include protocol PFilePicker;
 include protocol PIndexedDBPermissionRequest;
 include protocol PRenderFrame;
 include protocol PPluginWidget;
 include protocol PRemotePrintJob;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PFileDescriptorSet;
+include protocol PIPCBlobInputStream;
+
 include DOMTypes;
 include IPCBlob;
 include IPCStream;
 include JavaScriptTypes;
 include URIParams;
 include PPrintingTypes;
 include PTabContext;
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -14,16 +14,17 @@ include protocol PCycleCollectWithLogs;
 include protocol PPSMContentDownloader;
 include protocol PExternalHelperApp;
 include protocol PHandlerService;
 include protocol PFileDescriptorSet;
 include protocol PHal;
 include protocol PHeapSnapshotTempFileHelper;
 include protocol PProcessHangMonitor;
 include protocol PImageBridge;
+include protocol PIPCBlobInputStream;
 include protocol PMedia;
 include protocol PMemoryStream;
 include protocol PNecko;
 include protocol PGMPContent;
 include protocol PGMPService;
 include protocol PPluginModule;
 include protocol PGMP;
 include protocol PPrinting;
@@ -282,16 +283,17 @@ nested(upto inside_cpow) sync protocol P
     manages PContentPermissionRequest;
     manages PCycleCollectWithLogs;
     manages PPSMContentDownloader;
     manages PExternalHelperApp;
     manages PFileDescriptorSet;
     manages PHal;
     manages PHandlerService;
     manages PHeapSnapshotTempFileHelper;
+    manages PIPCBlobInputStream;
     manages PMedia;
     manages PMemoryStream;
     manages PNecko;
     manages POfflineCacheUpdate;
     manages PPrinting;
     manages PChildToParentStream;
     manages PParentToChildStream;
     manages PSpeechSynthesis;
@@ -604,16 +606,18 @@ child:
     async PParentToChildStream();
 
     async ProvideAnonymousTemporaryFile(uint64_t aID, FileDescOrError aFD);
 
     async SetPermissionsWithKey(nsCString aPermissionKey, Permission[] aPermissions);
 
     async RefreshScreens(ScreenDetails[] aScreens);
 
+    async PIPCBlobInputStream(nsID aID, uint64_t aSize);
+
 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
@@ -7,19 +7,21 @@
 include protocol PBlob;
 include protocol PBrowser;
 include protocol PContent;
 include protocol PJavaScript;
 include protocol PFileDescriptorSet;
 include protocol PChildToParentStream;
 include protocol PMemoryStream;
 include protocol PParentToChildStream;
+include protocol PIPCBlobInputStream;
 
 include DOMTypes;
 include JavaScriptTypes;
+include ProtocolTypes;
 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";
 using class mozilla::dom::MessagePort from "mozilla/dom/MessagePort.h";
 using class mozilla::dom::ipc::StructuredCloneData from "mozilla/dom/ipc/StructuredCloneData.h";
 
@@ -38,30 +40,33 @@ nested(upto inside_cpow) sync protocol P
 {
     manages PBlob;
     manages PBrowser;
     manages PFileDescriptorSet;
     manages PJavaScript;
     manages PChildToParentStream;
     manages PMemoryStream;
     manages PParentToChildStream;
+    manages PIPCBlobInputStream;
 
 child:
     async PParentToChildStream();
 
 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 PIPCBlobInputStream(nsID aID, uint64_t aSize);
+
 parent:
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
     async PJavaScript();
 
     async PChildToParentStream();
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/InputStreamUtils.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 "mozilla/dom/ipc/MemoryStreamChild.h"
+#include "mozilla/dom/ipc/IPCBlobInputStreamChild.h"
 
 #include "nsPrintfCString.h"
 #include "xpcpublic.h"
 
 using namespace mozilla::ipc;
 using namespace mozilla::jsipc;
 
 namespace mozilla {
@@ -114,16 +115,36 @@ nsIContentChild::AllocPMemoryStreamChild
 
 bool
 nsIContentChild::DeallocPMemoryStreamChild(PMemoryStreamChild* aActor)
 {
   delete aActor;
   return true;
 }
 
+PIPCBlobInputStreamChild*
+nsIContentChild::AllocPIPCBlobInputStreamChild(const nsID& aID,
+                                               const uint64_t& aSize)
+{
+  // IPCBlobInputStreamChild is refcounted. Here it's created and in
+  // DeallocPIPCBlobInputStreamChild is released.
+
+  RefPtr<IPCBlobInputStreamChild> actor =
+    new IPCBlobInputStreamChild(aID, aSize);
+  return actor.forget().take();
+}
+
+bool
+nsIContentChild::DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor)
+{
+  RefPtr<IPCBlobInputStreamChild> actor =
+    dont_AddRef(static_cast<IPCBlobInputStreamChild*>(aActor));
+  return true;
+}
+
 PBlobChild*
 nsIContentChild::AllocPBlobChild(const BlobConstructorParams& aParams)
 {
   return BlobChild::Create(this, aParams);
 }
 
 bool
 nsIContentChild::DeallocPBlobChild(PBlobChild* aActor)
--- a/dom/ipc/nsIContentChild.h
+++ b/dom/ipc/nsIContentChild.h
@@ -106,16 +106,22 @@ protected:
 
   virtual bool DeallocPBlobChild(PBlobChild* aActor);
 
   virtual mozilla::ipc::PMemoryStreamChild*
   AllocPMemoryStreamChild(const uint64_t& aSize);
 
   virtual bool DeallocPMemoryStreamChild(mozilla::ipc::PMemoryStreamChild* aActor);
 
+  virtual mozilla::ipc::PIPCBlobInputStreamChild*
+  AllocPIPCBlobInputStreamChild(const nsID& aID, const uint64_t& aSize);
+
+  virtual bool
+  DeallocPIPCBlobInputStreamChild(mozilla::ipc::PIPCBlobInputStreamChild* aActor);
+
   virtual mozilla::ipc::PChildToParentStreamChild* AllocPChildToParentStreamChild();
 
   virtual bool
   DeallocPChildToParentStreamChild(mozilla::ipc::PChildToParentStreamChild* aActor);
 
   virtual mozilla::ipc::PParentToChildStreamChild* AllocPParentToChildStreamChild();
 
   virtual bool
--- a/dom/ipc/nsIContentParent.cpp
+++ b/dom/ipc/nsIContentParent.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #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/IPCBlobInputStreamParent.h"
 #include "mozilla/dom/ipc/MemoryStreamParent.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/IPCStreamAlloc.h"
 #include "mozilla/ipc/IPCStreamDestination.h"
 #include "mozilla/ipc/IPCStreamSource.h"
@@ -199,16 +200,31 @@ nsIContentParent::AllocPMemoryStreamPare
 
 bool
 nsIContentParent::DeallocPMemoryStreamParent(PMemoryStreamParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+PIPCBlobInputStreamParent*
+nsIContentParent::AllocPIPCBlobInputStreamParent(const nsID& aID,
+                                                 const uint64_t& aSize)
+{
+  MOZ_CRASH("PIPCBlobInputStreamParent actors should be manually constructed!");
+  return nullptr;
+}
+
+bool
+nsIContentParent::DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor)
+{
+  delete aActor;
+  return true;
+}
+
 BlobParent*
 nsIContentParent::GetOrCreateActorForBlob(Blob* aBlob)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlob);
 
   RefPtr<BlobImpl> blobImpl = aBlob->Impl();
   MOZ_ASSERT(blobImpl);
--- a/dom/ipc/nsIContentParent.h
+++ b/dom/ipc/nsIContentParent.h
@@ -32,16 +32,17 @@ class PJavaScriptParent;
 class CpowEntry;
 } // namespace jsipc
 
 namespace ipc {
 class PFileDescriptorSetParent;
 class PChildToParentStreamParent;
 class PParentToChildStreamParent;
 class PMemoryStreamParent;
+class PIPCBlobInputStreamParent;
 }
 
 namespace dom {
 
 class Blob;
 class BlobConstructorParams;
 class BlobImpl;
 class BlobParent;
@@ -66,16 +67,21 @@ public:
 
   virtual ContentParentId ChildID() const = 0;
   virtual bool IsForBrowser() const = 0;
 
   MOZ_MUST_USE virtual PBlobParent*
   SendPBlobConstructor(PBlobParent* aActor,
                        const BlobConstructorParams& aParams) = 0;
 
+  virtual mozilla::ipc::PIPCBlobInputStreamParent*
+  SendPIPCBlobInputStreamConstructor(mozilla::ipc::PIPCBlobInputStreamParent* aActor,
+                                     const nsID& aID,
+                                     const uint64_t& aSize) = 0;
+
   MOZ_MUST_USE virtual PBrowserParent*
   SendPBrowserConstructor(PBrowserParent* actor,
                           const TabId& aTabId,
                           const TabId& aSameTabGroupAs,
                           const IPCTabContext& context,
                           const uint32_t& chromeFlags,
                           const ContentParentId& aCpId,
                           const bool& aIsForBrowser) = 0;
@@ -124,16 +130,22 @@ protected: // IPDL methods
 
   virtual bool DeallocPBlobParent(PBlobParent* aActor);
 
   virtual mozilla::ipc::PMemoryStreamParent*
   AllocPMemoryStreamParent(const uint64_t& aSize);
 
   virtual bool DeallocPMemoryStreamParent(mozilla::ipc::PMemoryStreamParent* aActor);
 
+  virtual mozilla::ipc::PIPCBlobInputStreamParent*
+  AllocPIPCBlobInputStreamParent(const nsID& aID, const uint64_t& aSize);
+
+  virtual bool
+  DeallocPIPCBlobInputStreamParent(mozilla::ipc::PIPCBlobInputStreamParent* aActor);
+
   virtual mozilla::ipc::PFileDescriptorSetParent*
   AllocPFileDescriptorSetParent(const mozilla::ipc::FileDescriptor& aFD);
 
   virtual bool
   DeallocPFileDescriptorSetParent(mozilla::ipc::PFileDescriptorSetParent* aActor);
 
   virtual mozilla::ipc::PChildToParentStreamParent* AllocPChildToParentStreamParent();
 
--- a/dom/messagechannel/PMessagePort.ipdl
+++ b/dom/messagechannel/PMessagePort.ipdl
@@ -1,15 +1,16 @@
 /* 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 PBackground;
 include protocol PChildToParentStream;
 include protocol PFileDescriptorSet;
+include protocol PIPCBlobInputStream;
 include protocol PParentToChildStream;
 include protocol PBlob;
 
 include DOMTypes;
 
 using struct mozilla::SerializedStructuredCloneBuffer
   from "ipc/IPCMessageUtils.h";
 
--- a/ipc/glue/BackgroundChildImpl.cpp
+++ b/ipc/glue/BackgroundChildImpl.cpp
@@ -18,16 +18,17 @@
 #include "mozilla/dom/PBlobChild.h"
 #include "mozilla/dom/PFileSystemRequestChild.h"
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #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/ipc/IPCBlobInputStreamChild.h"
 #include "mozilla/dom/ipc/MemoryStreamChild.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"
@@ -224,16 +225,36 @@ BackgroundChildImpl::AllocPMemoryStreamC
 
 bool
 BackgroundChildImpl::DeallocPMemoryStreamChild(PMemoryStreamChild* aActor)
 {
   delete aActor;
   return true;
 }
 
+PIPCBlobInputStreamChild*
+BackgroundChildImpl::AllocPIPCBlobInputStreamChild(const nsID& aID,
+                                                   const uint64_t& aSize)
+{
+  // IPCBlobInputStreamChild is refcounted. Here it's created and in
+  // DeallocPIPCBlobInputStreamChild is released.
+
+  RefPtr<mozilla::dom::IPCBlobInputStreamChild> actor =
+    new mozilla::dom::IPCBlobInputStreamChild(aID, aSize);
+  return actor.forget().take();
+}
+
+bool
+BackgroundChildImpl::DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor)
+{
+  RefPtr<mozilla::dom::IPCBlobInputStreamChild> actor =
+    dont_AddRef(static_cast<mozilla::dom::IPCBlobInputStreamChild*>(aActor));
+  return true;
+}
+
 PFileDescriptorSetChild*
 BackgroundChildImpl::AllocPFileDescriptorSetChild(
                                           const FileDescriptor& aFileDescriptor)
 {
   return new FileDescriptorSetChild(aFileDescriptor);
 }
 
 bool
--- a/ipc/glue/BackgroundChildImpl.h
+++ b/ipc/glue/BackgroundChildImpl.h
@@ -77,16 +77,23 @@ protected:
   DeallocPBlobChild(PBlobChild* aActor) override;
 
   virtual PMemoryStreamChild*
   AllocPMemoryStreamChild(const uint64_t& aSize) override;
 
   virtual bool
   DeallocPMemoryStreamChild(PMemoryStreamChild* aActor) override;
 
+  virtual PIPCBlobInputStreamChild*
+  AllocPIPCBlobInputStreamChild(const nsID& aID,
+                                const uint64_t& aSize) override;
+
+  virtual bool
+  DeallocPIPCBlobInputStreamChild(PIPCBlobInputStreamChild* aActor) override;
+
   virtual PFileDescriptorSetChild*
   AllocPFileDescriptorSetChild(const FileDescriptor& aFileDescriptor)
                                override;
 
   virtual bool
   DeallocPFileDescriptorSetChild(PFileDescriptorSetChild* aActor) override;
 
   virtual PCamerasChild*
--- a/ipc/glue/BackgroundParentImpl.cpp
+++ b/ipc/glue/BackgroundParentImpl.cpp
@@ -23,16 +23,17 @@
 #include "mozilla/dom/PGamepadEventChannelParent.h"
 #include "mozilla/dom/PGamepadTestChannelParent.h"
 #include "mozilla/dom/MessagePortParent.h"
 #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/ipc/IPCBlobInputStreamParent.h"
 #include "mozilla/dom/ipc/MemoryStreamParent.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"
@@ -282,16 +283,34 @@ BackgroundParentImpl::DeallocPMemoryStre
   AssertIsInMainProcess();
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aActor);
 
   delete aActor;
   return true;
 }
 
+PIPCBlobInputStreamParent*
+BackgroundParentImpl::AllocPIPCBlobInputStreamParent(const nsID& aID,
+                                                     const uint64_t& aSize)
+{
+  MOZ_CRASH("PIPCBlobInputStreamParent actors should be manually constructed!");
+}
+
+bool
+BackgroundParentImpl::DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor)
+{
+  AssertIsInMainProcess();
+  AssertIsOnBackgroundThread();
+  MOZ_ASSERT(aActor);
+
+  delete aActor;
+  return true;
+}
+
 mozilla::ipc::IPCResult
 BackgroundParentImpl::RecvPBlobConstructor(PBlobParent* aActor,
                                            const BlobConstructorParams& aParams)
 {
   const ParentBlobConstructorParams& params = aParams;
   if (params.blobParams().type() == AnyBlobConstructorParams::TKnownBlobConstructorParams) {
     if (!aActor->SendCreatedFromKnownBlob()) {
       return IPC_FAIL_NO_REASON(this);
--- a/ipc/glue/BackgroundParentImpl.h
+++ b/ipc/glue/BackgroundParentImpl.h
@@ -70,16 +70,23 @@ protected:
   DeallocPBlobParent(PBlobParent* aActor) override;
 
   virtual PMemoryStreamParent*
   AllocPMemoryStreamParent(const uint64_t& aSize) override;
 
   virtual bool
   DeallocPMemoryStreamParent(PMemoryStreamParent* aActor) override;
 
+  virtual PIPCBlobInputStreamParent*
+  AllocPIPCBlobInputStreamParent(const nsID& aID,
+                                 const uint64_t& aSize) override;
+
+  virtual bool
+  DeallocPIPCBlobInputStreamParent(PIPCBlobInputStreamParent* aActor) override;
+
   virtual mozilla::ipc::IPCResult
   RecvPBlobConstructor(PBlobParent* aActor,
                        const BlobConstructorParams& params) override;
 
   virtual PFileDescriptorSetParent*
   AllocPFileDescriptorSetParent(const FileDescriptor& aFileDescriptor)
                                 override;
 
--- a/ipc/glue/PBackground.ipdl
+++ b/ipc/glue/PBackground.ipdl
@@ -10,16 +10,17 @@ include protocol PBlob;
 include protocol PBroadcastChannel;
 include protocol PCache;
 include protocol PCacheStorage;
 include protocol PCacheStreamControl;
 include protocol PFileDescriptorSet;
 include protocol PFileSystemRequest;
 include protocol PGamepadEventChannel;
 include protocol PGamepadTestChannel;
+include protocol PIPCBlobInputStream;
 include protocol PMemoryStream;
 include protocol PMessagePort;
 include protocol PCameras;
 include protocol PQuota;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PServiceWorkerManager;
 include protocol PUDPSocket;
@@ -55,16 +56,17 @@ sync protocol PBackground
   manages PBroadcastChannel;
   manages PCache;
   manages PCacheStorage;
   manages PCacheStreamControl;
   manages PFileDescriptorSet;
   manages PFileSystemRequest;
   manages PGamepadEventChannel;
   manages PGamepadTestChannel;
+  manages PIPCBlobInputStream;
   manages PMemoryStream;
   manages PMessagePort;
   manages PCameras;
   manages PQuota;
   manages PChildToParentStream;
   manages PParentToChildStream;
   manages PServiceWorkerManager;
   manages PUDPSocket;
@@ -115,16 +117,18 @@ parent:
   async PMemoryStream(uint64_t aSize);
 
 child:
   async PCache();
   async PCacheStreamControl();
 
   async PParentToChildStream();
 
+  async PIPCBlobInputStream(nsID aID, uint64_t aSize);
+
 both:
   async PBlob(BlobConstructorParams params);
 
   async PFileDescriptorSet(FileDescriptor fd);
 };
 
 } // namespace ipc
 } // namespace mozilla