Bug 1523702 - Max IPC message size for InputStream serialization, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 04 Feb 2019 22:50:51 +0000
changeset 456730 183ac72fd6148db090d7958edcdc42314bf495a3
parent 456729 553538a675ecaf39eebcaf54d6dce1e5d159cca0
child 456731 903d62a948d206077bbcd0585bf8ff81568fd1fb
push id35504
push usercsabou@mozilla.com
push dateTue, 05 Feb 2019 21:57:12 +0000
treeherdermozilla-central@1e374e23c02f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1523702
milestone67.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 1523702 - Max IPC message size for InputStream serialization, r=smaug The total size of an IPC inputStream message must be less than 1mb. When we compose the message for the multiplex stream, each sub stream collaborates with its own size, deciding if it's better to be a pipe stream (IPCRemoteStream) or a full serialized one. Differential Revision: https://phabricator.services.mozilla.com/D18543
dom/file/TemporaryFileBlobImpl.cpp
dom/file/ipc/IPCBlobInputStream.cpp
dom/indexedDB/FileSnapshot.cpp
ipc/glue/IPCStreamUtils.cpp
ipc/glue/InputStreamUtils.cpp
ipc/glue/InputStreamUtils.h
ipc/glue/nsIIPCSerializableInputStream.h
netwerk/base/PartiallySeekableInputStream.cpp
netwerk/base/PartiallySeekableInputStream.h
netwerk/base/nsBufferedStreams.cpp
netwerk/base/nsBufferedStreams.h
netwerk/base/nsFileStreams.cpp
netwerk/base/nsMIMEInputStream.cpp
xpcom/io/InputStreamLengthWrapper.cpp
xpcom/io/InputStreamLengthWrapper.h
xpcom/io/NonBlockingAsyncInputStream.cpp
xpcom/io/NonBlockingAsyncInputStream.h
xpcom/io/SlicedInputStream.cpp
xpcom/io/SlicedInputStream.h
xpcom/io/nsMultiplexInputStream.cpp
xpcom/io/nsStorageStream.cpp
xpcom/io/nsStringStream.cpp
xpcom/tests/gtest/TestNonBlockingAsyncInputStream.cpp
--- a/dom/file/TemporaryFileBlobImpl.cpp
+++ b/dom/file/TemporaryFileBlobImpl.cpp
@@ -47,34 +47,38 @@ class TemporaryFileInputStream final : p
     }
 
     stream.forget(aInputStream);
     return NS_OK;
   }
 
   void Serialize(InputStreamParams& aParams,
                  FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+                 uint32_t aMaxSize, uint32_t* aSizeUsed,
                  nsIContentChild* aManager) override {
     MOZ_CRASH("This inputStream cannot be serialized.");
   }
 
   void Serialize(InputStreamParams& aParams,
                  FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+                 uint32_t aMaxSize, uint32_t* aSizeUsed,
                  PBackgroundChild* aManager) override {
     MOZ_CRASH("This inputStream cannot be serialized.");
   }
 
   void Serialize(InputStreamParams& aParams,
                  FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+                 uint32_t aMaxSize, uint32_t* aSizeUsed,
                  nsIContentParent* aManager) override {
     MOZ_CRASH("This inputStream cannot be serialized.");
   }
 
   void Serialize(InputStreamParams& aParams,
                  FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+                 uint32_t aMaxSize, uint32_t* aSizeUsed,
                  PBackgroundParent* aManager) override {
     MOZ_CRASH("This inputStream cannot be serialized.");
   }
 
   bool Deserialize(const InputStreamParams& aParams,
                    const FileDescriptorArray& aFileDescriptors) override {
     MOZ_CRASH("This inputStream cannot be deserialized.");
     return false;
--- a/dom/file/ipc/IPCBlobInputStream.cpp
+++ b/dom/file/ipc/IPCBlobInputStream.cpp
@@ -560,39 +560,55 @@ IPCBlobInputStream::OnInputStreamReady(n
   InputStreamCallbackRunnable::Execute(callback, callbackEventTarget, this);
   return NS_OK;
 }
 
 // nsIIPCSerializableInputStream
 
 void IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
                                    FileDescriptorArray& aFileDescriptors,
-                                   bool aDelayedStart,
+                                   bool aDelayedStart, uint32_t aMaxSize,
+                                   uint32_t* aSizeUsed,
                                    nsIContentChild* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   SerializeInternal(aParams);
 }
 
 void IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
                                    FileDescriptorArray& aFileDescriptors,
-                                   bool aDelayedStart,
+                                   bool aDelayedStart, uint32_t aMaxSize,
+                                   uint32_t* aSizeUsed,
                                    mozilla::ipc::PBackgroundChild* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   SerializeInternal(aParams);
 }
 
 void IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
                                    FileDescriptorArray& aFileDescriptors,
-                                   bool aDelayedStart,
+                                   bool aDelayedStart, uint32_t aMaxSize,
+                                   uint32_t* aSizeUsed,
                                    nsIContentParent* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   SerializeInternal(aParams);
 }
 
 void IPCBlobInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
                                    FileDescriptorArray& aFileDescriptors,
-                                   bool aDelayedStart,
+                                   bool aDelayedStart, uint32_t aMaxSize,
+                                   uint32_t* aSizeUsed,
                                    mozilla::ipc::PBackgroundParent* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   SerializeInternal(aParams);
 }
 
 void IPCBlobInputStream::SerializeInternal(
     mozilla::ipc::InputStreamParams& aParams) {
   MutexAutoLock lock(mMutex);
 
   mozilla::ipc::IPCBlobInputStreamParams params;
--- a/dom/indexedDB/FileSnapshot.cpp
+++ b/dom/indexedDB/FileSnapshot.cpp
@@ -56,17 +56,18 @@ class StreamWrapper final : public nsIAs
   }
 
  private:
   virtual ~StreamWrapper();
 
   template <typename M>
   void SerializeInternal(InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart, M* aManager);
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed, M* aManager);
 
   bool IsOnOwningThread() const {
     MOZ_ASSERT(mOwningThread);
 
     bool current;
     return NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(&current)) && current;
   }
 
@@ -266,47 +267,61 @@ StreamWrapper::ReadSegments(nsWriteSegme
 
 NS_IMETHODIMP
 StreamWrapper::IsNonBlocking(bool* _retval) {
   return mInputStream->IsNonBlocking(_retval);
 }
 
 void StreamWrapper::Serialize(InputStreamParams& aParams,
                               FileDescriptorArray& aFileDescriptors,
-                              bool aDelayedStart, nsIContentChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+                              bool aDelayedStart, uint32_t aMaxSize,
+                              uint32_t* aSizeUsed, nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void StreamWrapper::Serialize(InputStreamParams& aParams,
                               FileDescriptorArray& aFileDescriptors,
-                              bool aDelayedStart, PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+                              bool aDelayedStart, uint32_t aMaxSize,
+                              uint32_t* aSizeUsed, PBackgroundChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void StreamWrapper::Serialize(InputStreamParams& aParams,
                               FileDescriptorArray& aFileDescriptors,
-                              bool aDelayedStart, nsIContentParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+                              bool aDelayedStart, uint32_t aMaxSize,
+                              uint32_t* aSizeUsed, nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void StreamWrapper::Serialize(InputStreamParams& aParams,
                               FileDescriptorArray& aFileDescriptors,
-                              bool aDelayedStart, PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+                              bool aDelayedStart, uint32_t aMaxSize,
+                              uint32_t* aSizeUsed,
+                              PBackgroundParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 template <typename M>
 void StreamWrapper::SerializeInternal(InputStreamParams& aParams,
                                       FileDescriptorArray& aFileDescriptors,
-                                      bool aDelayedStart, M* aManager) {
+                                      bool aDelayedStart, uint32_t aMaxSize,
+                                      uint32_t* aSizeUsed, M* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   nsCOMPtr<nsIIPCSerializableInputStream> stream =
       do_QueryInterface(mInputStream);
 
   if (stream) {
-    stream->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);
+    stream->Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                      aSizeUsed, aManager);
   }
 }
 
 bool StreamWrapper::Deserialize(const InputStreamParams& aParams,
                                 const FileDescriptorArray& aFileDescriptors) {
   MOZ_CRASH("This method should never be called");
   return false;
 }
--- a/ipc/glue/IPCStreamUtils.cpp
+++ b/ipc/glue/IPCStreamUtils.cpp
@@ -33,18 +33,24 @@ namespace {
 
 template <typename M>
 bool SerializeInputStreamWithFdsChild(nsIIPCSerializableInputStream* aStream,
                                       IPCStream& aValue, bool aDelayedStart,
                                       M* aManager) {
   MOZ_RELEASE_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
+  const uint64_t kTooLargeStream = 1024 * 1024;
+
+  uint32_t sizeUsed = 0;
   AutoTArray<FileDescriptor, 4> fds;
-  aStream->Serialize(aValue.stream(), fds, aDelayedStart, aManager);
+  aStream->Serialize(aValue.stream(), fds, aDelayedStart, kTooLargeStream,
+                     &sizeUsed, aManager);
+
+  MOZ_ASSERT(sizeUsed <= kTooLargeStream);
 
   if (aValue.stream().type() == InputStreamParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 
   if (fds.IsEmpty()) {
     aValue.optionalFds() = void_t();
   } else {
@@ -62,18 +68,24 @@ bool SerializeInputStreamWithFdsChild(ns
 
 template <typename M>
 bool SerializeInputStreamWithFdsParent(nsIIPCSerializableInputStream* aStream,
                                        IPCStream& aValue, bool aDelayedStart,
                                        M* aManager) {
   MOZ_RELEASE_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
+  const uint64_t kTooLargeStream = 1024 * 1024;
+
+  uint32_t sizeUsed = 0;
   AutoTArray<FileDescriptor, 4> fds;
-  aStream->Serialize(aValue.stream(), fds, aDelayedStart, aManager);
+  aStream->Serialize(aValue.stream(), fds, aDelayedStart, kTooLargeStream,
+                     &sizeUsed, aManager);
+
+  MOZ_ASSERT(sizeUsed <= kTooLargeStream);
 
   if (aValue.stream().type() == InputStreamParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 
   aValue.optionalFds() = void_t();
   if (!fds.IsEmpty()) {
     PFileDescriptorSetParent* fdSet =
--- a/ipc/glue/InputStreamUtils.cpp
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -48,27 +48,29 @@ namespace mozilla {
 namespace ipc {
 
 namespace {
 
 template <typename M>
 void SerializeInputStreamInternal(nsIInputStream* aInputStream,
                                   InputStreamParams& aParams,
                                   nsTArray<FileDescriptor>& aFileDescriptors,
-                                  bool aDelayedStart, M* aManager) {
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed, M* aManager) {
   MOZ_ASSERT(aInputStream);
   MOZ_ASSERT(aManager);
 
   nsCOMPtr<nsIIPCSerializableInputStream> serializable =
       do_QueryInterface(aInputStream);
   if (!serializable) {
     MOZ_CRASH("Input stream is not serializable!");
   }
 
-  serializable->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);
+  serializable->Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                          aSizeUsed, aManager);
 
   if (aParams.type() == InputStreamParams::T__None) {
     MOZ_CRASH("Serialize failed!");
   }
 }
 
 template <typename M>
 void SerializeInputStreamAsPipeInternal(nsIInputStream* aInputStream,
@@ -113,43 +115,43 @@ void SerializeInputStreamAsPipeInternal(
       aDelayedStart, IPCStreamSource::Create(asyncStream, aManager), length);
 }
 
 }  // namespace
 
 void InputStreamHelper::SerializeInputStream(
     nsIInputStream* aInputStream, InputStreamParams& aParams,
     nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
-    nsIContentChild* aManager) {
+    uint32_t aMaxSize, uint32_t* aSizeUsed, nsIContentChild* aManager) {
   SerializeInputStreamInternal(aInputStream, aParams, aFileDescriptors,
-                               aDelayedStart, aManager);
+                               aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void InputStreamHelper::SerializeInputStream(
     nsIInputStream* aInputStream, InputStreamParams& aParams,
     nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
-    PBackgroundChild* aManager) {
+    uint32_t aMaxSize, uint32_t* aSizeUsed, PBackgroundChild* aManager) {
   SerializeInputStreamInternal(aInputStream, aParams, aFileDescriptors,
-                               aDelayedStart, aManager);
+                               aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void InputStreamHelper::SerializeInputStream(
     nsIInputStream* aInputStream, InputStreamParams& aParams,
     nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
-    nsIContentParent* aManager) {
+    uint32_t aMaxSize, uint32_t* aSizeUsed, nsIContentParent* aManager) {
   SerializeInputStreamInternal(aInputStream, aParams, aFileDescriptors,
-                               aDelayedStart, aManager);
+                               aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void InputStreamHelper::SerializeInputStream(
     nsIInputStream* aInputStream, InputStreamParams& aParams,
     nsTArray<FileDescriptor>& aFileDescriptors, bool aDelayedStart,
-    PBackgroundParent* aManager) {
+    uint32_t aMaxSize, uint32_t* aSizeUsed, PBackgroundParent* aManager) {
   SerializeInputStreamInternal(aInputStream, aParams, aFileDescriptors,
-                               aDelayedStart, aManager);
+                               aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void InputStreamHelper::SerializeInputStreamAsPipe(nsIInputStream* aInputStream,
                                                    InputStreamParams& aParams,
                                                    bool aDelayedStart,
                                                    nsIContentChild* aManager) {
   SerializeInputStreamAsPipeInternal(aInputStream, aParams, aDelayedStart,
                                      aManager);
--- a/ipc/glue/InputStreamUtils.h
+++ b/ipc/glue/InputStreamUtils.h
@@ -18,42 +18,48 @@ namespace ipc {
 class FileDescriptor;
 
 // If you want to serialize an inputStream, please use AutoIPCStream.
 class InputStreamHelper {
  public:
   // These 4 methods allow to serialize an inputStream into InputStreamParams.
   // The manager is needed in case a stream needs to serialize itself as
   // IPCRemoteStream.
-  // In case the stream wants to serialize itself as IPCRemoteStream, its
-  // content will be sent to the other side of the IPC pipe in chunks. This
-  // sending can start immediatelly or at the first read based on the value of
-  // |aDelayedStart|.
+  // The stream serializes itself fully only if the resulting IPC message will
+  // be smaller than |aMaxSize|. Otherwise, the stream serializes itself as
+  // IPCRemoteStream, and, its content will be sent to the other side of the IPC
+  // pipe in chunks. This sending can start immediatelly or at the first read
+  // based on the value of |aDelayedStart|. The IPC message size is returned
+  // into |aSizeUsed|.
   static void SerializeInputStream(nsIInputStream* aInputStream,
                                    InputStreamParams& aParams,
                                    nsTArray<FileDescriptor>& aFileDescriptors,
-                                   bool aDelayedStart,
+                                   bool aDelayedStart, uint32_t aMaxSize,
+                                   uint32_t* aSizeUsed,
                                    mozilla::dom::nsIContentChild* aManager);
 
   static void SerializeInputStream(nsIInputStream* aInputStream,
                                    InputStreamParams& aParams,
                                    nsTArray<FileDescriptor>& aFileDescriptors,
-                                   bool aDelayedStart,
+                                   bool aDelayedStart, uint32_t aMaxSize,
+                                   uint32_t* aSizeUsed,
                                    PBackgroundChild* aManager);
 
   static void SerializeInputStream(nsIInputStream* aInputStream,
                                    InputStreamParams& aParams,
                                    nsTArray<FileDescriptor>& aFileDescriptors,
-                                   bool aDelayedStart,
+                                   bool aDelayedStart, uint32_t aMaxSize,
+                                   uint32_t* aSizeUsed,
                                    mozilla::dom::nsIContentParent* aManager);
 
   static void SerializeInputStream(nsIInputStream* aInputStream,
                                    InputStreamParams& aParams,
                                    nsTArray<FileDescriptor>& aFileDescriptors,
-                                   bool aDelayedStart,
+                                   bool aDelayedStart, uint32_t aMaxSize,
+                                   uint32_t* aSizeUsed,
                                    PBackgroundParent* aManager);
 
   // When a stream wants to serialize itself as IPCRemoteStream, it uses one of
   // these methods.
   static void SerializeInputStreamAsPipe(
       nsIInputStream* aInputStream, InputStreamParams& aParams,
       bool aDelayedStart, mozilla::dom::nsIContentChild* aManager);
 
--- a/ipc/glue/nsIIPCSerializableInputStream.h
+++ b/ipc/glue/nsIIPCSerializableInputStream.h
@@ -42,130 +42,150 @@ class PBackgroundParent;
 class NS_NO_VTABLE nsIIPCSerializableInputStream : public nsISupports {
  public:
   typedef nsTArray<mozilla::ipc::FileDescriptor> FileDescriptorArray;
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IIPCSERIALIZABLEINPUTSTREAM_IID)
 
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart,
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed,
                          mozilla::dom::nsIContentChild* aManager) = 0;
 
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart,
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed,
                          mozilla::ipc::PBackgroundChild* aManager) = 0;
 
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart,
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed,
                          mozilla::dom::nsIContentParent* aManager) = 0;
 
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart,
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed,
                          mozilla::ipc::PBackgroundParent* aManager) = 0;
 
   virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,
                            const FileDescriptorArray& aFileDescriptors) = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream,
                               NS_IIPCSERIALIZABLEINPUTSTREAM_IID)
 
-#define NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM                        \
-  virtual void Serialize(mozilla::ipc::InputStreamParams&,           \
-                         FileDescriptorArray&, bool,                 \
-                         mozilla::dom::nsIContentChild*) override;   \
-                                                                     \
-  virtual void Serialize(mozilla::ipc::InputStreamParams&,           \
-                         FileDescriptorArray&, bool,                 \
-                         mozilla::ipc::PBackgroundChild*) override;  \
-                                                                     \
-  virtual void Serialize(mozilla::ipc::InputStreamParams&,           \
-                         FileDescriptorArray&, bool,                 \
-                         mozilla::dom::nsIContentParent*) override;  \
-                                                                     \
-  virtual void Serialize(mozilla::ipc::InputStreamParams&,           \
-                         FileDescriptorArray&, bool,                 \
-                         mozilla::ipc::PBackgroundParent*) override; \
-                                                                     \
-  virtual bool Deserialize(const mozilla::ipc::InputStreamParams&,   \
+#define NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM                             \
+  virtual void Serialize(mozilla::ipc::InputStreamParams&,                \
+                         FileDescriptorArray&, bool, uint32_t, uint32_t*, \
+                         mozilla::dom::nsIContentChild*) override;        \
+                                                                          \
+  virtual void Serialize(mozilla::ipc::InputStreamParams&,                \
+                         FileDescriptorArray&, bool, uint32_t, uint32_t*, \
+                         mozilla::ipc::PBackgroundChild*) override;       \
+                                                                          \
+  virtual void Serialize(mozilla::ipc::InputStreamParams&,                \
+                         FileDescriptorArray&, bool, uint32_t, uint32_t*, \
+                         mozilla::dom::nsIContentParent*) override;       \
+                                                                          \
+  virtual void Serialize(mozilla::ipc::InputStreamParams&,                \
+                         FileDescriptorArray&, bool, uint32_t, uint32_t*, \
+                         mozilla::ipc::PBackgroundParent*) override;      \
+                                                                          \
+  virtual bool Deserialize(const mozilla::ipc::InputStreamParams&,        \
                            const FileDescriptorArray&) override;
 
 #define NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(_to)                          \
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
                          FileDescriptorArray& aFileDescriptors,                \
-                         bool aDelayedStart,                                   \
+                         bool aDelayedStart, uint32_t aMaxSize,                \
+                         uint32_t* aSizeUsed,                                  \
                          mozilla::dom::nsIContentChild* aManager) override {   \
-    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);         \
+    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,          \
+                  aSizeUsed, aManager);                                        \
   }                                                                            \
                                                                                \
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
                          FileDescriptorArray& aFileDescriptors,                \
-                         bool aDelayedStart,                                   \
+                         bool aDelayedStart, uint32_t aMaxSize,                \
+                         uint32_t* aSizeUsed,                                  \
                          mozilla::ipc::PBackgroundChild* aManager) override {  \
-    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);         \
+    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,          \
+                  aSizeUsed, aManager);                                        \
   }                                                                            \
                                                                                \
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
                          FileDescriptorArray& aFileDescriptors,                \
-                         bool aDelayedStart,                                   \
+                         bool aDelayedStart, uint32_t aMaxSize,                \
+                         uint32_t* aSizeUsed,                                  \
                          mozilla::dom::nsIContentParent* aManager) override {  \
-    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);         \
+    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,          \
+                  aSizeUsed, aManager);                                        \
   }                                                                            \
                                                                                \
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
                          FileDescriptorArray& aFileDescriptors,                \
-                         bool aDelayedStart,                                   \
+                         bool aDelayedStart, uint32_t aMaxSize,                \
+                         uint32_t* aSizeUsed,                                  \
                          mozilla::ipc::PBackgroundParent* aManager) override { \
-    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);         \
+    _to Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,          \
+                  aSizeUsed, aManager);                                        \
   }                                                                            \
                                                                                \
   virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,     \
                            const FileDescriptorArray& aFileDescriptors)        \
       override {                                                               \
     return _to Deserialize(aParams, aFileDescriptors);                         \
   }
 
 #define NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(_to)                     \
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
                          FileDescriptorArray& aFileDescriptors,                \
-                         bool aDelayedStart,                                   \
+                         bool aDelayedStart, uint32_t aMaxSize,                \
+                         uint32_t* aSizeUsed,                                  \
                          mozilla::dom::nsIContentChild* aManager) override {   \
     if (_to) {                                                                 \
-      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);      \
+      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,       \
+                     aSizeUsed, aManager);                                     \
     }                                                                          \
   }                                                                            \
                                                                                \
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
                          FileDescriptorArray& aFileDescriptors,                \
-                         bool aDelayedStart,                                   \
+                         bool aDelayedStart, uint32_t aMaxSize,                \
+                         uint32_t* aSizeUsed,                                  \
                          mozilla::ipc::PBackgroundChild* aManager) override {  \
     if (_to) {                                                                 \
-      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);      \
+      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,       \
+                     aSizeUsed, aManager);                                     \
     }                                                                          \
   }                                                                            \
                                                                                \
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
                          FileDescriptorArray& aFileDescriptors,                \
-                         bool aDelayedStart,                                   \
+                         bool aDelayedStart, uint32_t aMaxSize,                \
+                         uint32_t* aSizeUsed,                                  \
                          mozilla::dom::nsIContentParent* aManager) override {  \
     if (_to) {                                                                 \
-      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);      \
+      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,       \
+                     aSizeUsed, aManager);                                     \
     }                                                                          \
   }                                                                            \
                                                                                \
   virtual void Serialize(mozilla::ipc::InputStreamParams& aParams,             \
                          FileDescriptorArray& aFileDescriptors,                \
-                         bool aDelayedStart,                                   \
+                         bool aDelayedStart, uint32_t aMaxSize,                \
+                         uint32_t* aSizeUsed,                                  \
                          mozilla::ipc::PBackgroundParent* aManager) override { \
     if (_to) {                                                                 \
-      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aManager);      \
+      _to->Serialize(aParams, aFileDescriptors, aDelayedStart, aMaxSize,       \
+                     aSizeUsed, aManager);                                     \
     }                                                                          \
   }                                                                            \
                                                                                \
   virtual bool Deserialize(const mozilla::ipc::InputStreamParams& aParams,     \
                            const FileDescriptorArray& aFileDescriptors)        \
       override {                                                               \
     return _to ? _to->Deserialize(aParams, aFileDescriptors) : false;          \
   }
--- a/netwerk/base/PartiallySeekableInputStream.cpp
+++ b/netwerk/base/PartiallySeekableInputStream.cpp
@@ -276,49 +276,59 @@ PartiallySeekableInputStream::OnInputStr
   return callback->OnInputStreamReady(this);
 }
 
 // nsIIPCSerializableInputStream
 
 void PartiallySeekableInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void PartiallySeekableInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::ipc::PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void PartiallySeekableInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void PartiallySeekableInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::ipc::PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 template <typename M>
 void PartiallySeekableInputStream::SerializeInternal(
     mozilla::ipc::InputStreamParams& aParams,
-    FileDescriptorArray& aFileDescriptors, bool aDelayedStart, M* aManager) {
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
   MOZ_ASSERT(mWeakIPCSerializableInputStream);
   MOZ_DIAGNOSTIC_ASSERT(mCachedBuffer.IsEmpty());
   mozilla::ipc::InputStreamHelper::SerializeInputStream(
-      mInputStream, aParams, aFileDescriptors, aDelayedStart, aManager);
+      mInputStream, aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+      aSizeUsed, aManager);
 }
 
 bool PartiallySeekableInputStream::Deserialize(
     const mozilla::ipc::InputStreamParams& aParams,
     const FileDescriptorArray& aFileDescriptors) {
   MOZ_CRASH("This method should never be called!");
   return false;
 }
--- a/netwerk/base/PartiallySeekableInputStream.h
+++ b/netwerk/base/PartiallySeekableInputStream.h
@@ -53,17 +53,18 @@ class PartiallySeekableInputStream final
 
   ~PartiallySeekableInputStream() = default;
 
   void Init();
 
   template <typename M>
   void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart, M* aManager);
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed, M* aManager);
 
   nsCOMPtr<nsIInputStream> mInputStream;
 
   // Raw pointers because these are just QI of mInputStream.
   nsICloneableInputStream* mWeakCloneableInputStream;
   nsIIPCSerializableInputStream* mWeakIPCSerializableInputStream;
   nsIAsyncInputStream* mWeakAsyncInputStream;
   nsIInputStreamLength* mWeakInputStreamLength;
--- a/netwerk/base/nsBufferedStreams.cpp
+++ b/netwerk/base/nsBufferedStreams.cpp
@@ -586,54 +586,66 @@ nsBufferedInputStream::GetUnbufferedStre
 
   *aStream = mStream;
   NS_IF_ADDREF(*aStream);
   return NS_OK;
 }
 
 void nsBufferedInputStream::Serialize(InputStreamParams& aParams,
                                       FileDescriptorArray& aFileDescriptors,
-                                      bool aDelayedStart,
+                                      bool aDelayedStart, uint32_t aMaxSize,
+                                      uint32_t* aSizeUsed,
                                       mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsBufferedInputStream::Serialize(InputStreamParams& aParams,
                                       FileDescriptorArray& aFileDescriptors,
-                                      bool aDelayedStart,
+                                      bool aDelayedStart, uint32_t aMaxSize,
+                                      uint32_t* aSizeUsed,
                                       PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsBufferedInputStream::Serialize(
     InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
-    bool aDelayedStart, mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+    bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed,
+    mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsBufferedInputStream::Serialize(InputStreamParams& aParams,
                                       FileDescriptorArray& aFileDescriptors,
-                                      bool aDelayedStart,
+                                      bool aDelayedStart, uint32_t aMaxSize,
+                                      uint32_t* aSizeUsed,
                                       PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 template <typename M>
 void nsBufferedInputStream::SerializeInternal(
     InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
-    bool aDelayedStart, M* aManager) {
+    bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   BufferedInputStreamParams params;
 
   if (mStream) {
     nsCOMPtr<nsIInputStream> stream = do_QueryInterface(mStream);
     MOZ_ASSERT(stream);
 
     InputStreamParams wrappedParams;
-    InputStreamHelper::SerializeInputStream(
-        stream, wrappedParams, aFileDescriptors, aDelayedStart, aManager);
+    InputStreamHelper::SerializeInputStream(stream, wrappedParams,
+                                            aFileDescriptors, aDelayedStart,
+                                            aMaxSize, aSizeUsed, aManager);
 
     params.optionalStream() = wrappedParams;
   } else {
     params.optionalStream() = mozilla::void_t();
   }
 
   params.bufferSize() = mBufferSize;
 
--- a/netwerk/base/nsBufferedStreams.h
+++ b/netwerk/base/nsBufferedStreams.h
@@ -93,17 +93,18 @@ class nsBufferedInputStream final : publ
   nsIInputStream* Source() { return (nsIInputStream*)mStream; }
 
  protected:
   virtual ~nsBufferedInputStream() = default;
 
   template <typename M>
   void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart, M* aManager);
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed, M* aManager);
 
   NS_IMETHOD Fill() override;
   NS_IMETHOD Flush() override { return NS_OK; }  // no-op for input streams
 
   mozilla::Mutex mMutex;
 
   // This value is protected by mutex.
   nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
--- a/netwerk/base/nsFileStreams.cpp
+++ b/netwerk/base/nsFileStreams.cpp
@@ -532,39 +532,55 @@ nsFileInputStream::Tell(int64_t* aResult
 
 NS_IMETHODIMP
 nsFileInputStream::Available(uint64_t* aResult) {
   return nsFileStreamBase::Available(aResult);
 }
 
 void nsFileInputStream::Serialize(InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   mozilla::dom::nsIContentChild* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   SerializeInternal(aParams, aFileDescriptors);
 }
 
 void nsFileInputStream::Serialize(InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   PBackgroundChild* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   SerializeInternal(aParams, aFileDescriptors);
 }
 
 void nsFileInputStream::Serialize(InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   mozilla::dom::nsIContentParent* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   SerializeInternal(aParams, aFileDescriptors);
 }
 
 void nsFileInputStream::Serialize(InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   PBackgroundParent* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   SerializeInternal(aParams, aFileDescriptors);
 }
 
 void nsFileInputStream::SerializeInternal(
     InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors) {
   FileInputStreamParams params;
 
   if (NS_SUCCEEDED(DoPendingOpen())) {
--- a/netwerk/base/nsMIMEInputStream.cpp
+++ b/netwerk/base/nsMIMEInputStream.cpp
@@ -56,17 +56,18 @@ class nsMIMEInputStream : public nsIMIME
   NS_DECL_NSICLONEABLEINPUTSTREAM
 
  private:
   void InitStreams();
 
   template <typename M>
   void SerializeInternal(InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart, M* aManager);
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed, M* aManager);
 
   struct MOZ_STACK_CLASS ReadSegmentsState {
     nsCOMPtr<nsIInputStream> mThisStream;
     nsWriteSegmentFun mWriter;
     void* mClosure;
   };
   static nsresult ReadSegCb(nsIInputStream* aIn, void* aClosure,
                             const char* aFromRawSegment, uint32_t aToOffset,
@@ -332,52 +333,65 @@ nsresult nsMIMEInputStreamConstructor(ns
   RefPtr<nsMIMEInputStream> inst = new nsMIMEInputStream();
   if (!inst) return NS_ERROR_OUT_OF_MEMORY;
 
   return inst->QueryInterface(iid, result);
 }
 
 void nsMIMEInputStream::Serialize(InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsMIMEInputStream::Serialize(InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsMIMEInputStream::Serialize(InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsMIMEInputStream::Serialize(InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 template <typename M>
 void nsMIMEInputStream::SerializeInternal(InputStreamParams& aParams,
                                           FileDescriptorArray& aFileDescriptors,
-                                          bool aDelayedStart, M* aManager) {
+                                          bool aDelayedStart, uint32_t aMaxSize,
+                                          uint32_t* aSizeUsed, M* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   MIMEInputStreamParams params;
 
   if (mStream) {
     InputStreamParams wrappedParams;
-    InputStreamHelper::SerializeInputStream(
-        mStream, wrappedParams, aFileDescriptors, aDelayedStart, aManager);
+    InputStreamHelper::SerializeInputStream(mStream, wrappedParams,
+                                            aFileDescriptors, aDelayedStart,
+                                            aMaxSize, aSizeUsed, aManager);
 
     NS_ASSERTION(wrappedParams.type() != InputStreamParams::T__None,
                  "Wrapped stream failed to serialize!");
 
     params.optionalStream() = wrappedParams;
   } else {
     params.optionalStream() = mozilla::void_t();
   }
--- a/xpcom/io/InputStreamLengthWrapper.cpp
+++ b/xpcom/io/InputStreamLengthWrapper.cpp
@@ -254,51 +254,61 @@ InputStreamLengthWrapper::OnInputStreamR
   return callback->OnInputStreamReady(this);
 }
 
 // nsIIPCSerializableInputStream
 
 void InputStreamLengthWrapper::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void InputStreamLengthWrapper::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::ipc::PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void InputStreamLengthWrapper::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void InputStreamLengthWrapper::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::ipc::PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 template <typename M>
 void InputStreamLengthWrapper::SerializeInternal(
     mozilla::ipc::InputStreamParams& aParams,
-    FileDescriptorArray& aFileDescriptors, bool aDelayedStart, M* aManager) {
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
   MOZ_ASSERT(mInputStream);
   MOZ_ASSERT(mWeakIPCSerializableInputStream);
 
   InputStreamLengthWrapperParams params;
-  InputStreamHelper::SerializeInputStream(
-      mInputStream, params.stream(), aFileDescriptors, aDelayedStart, aManager);
+  InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
+                                          aFileDescriptors, aDelayedStart,
+                                          aMaxSize, aSizeUsed, aManager);
   params.length() = mLength;
   params.consumed() = mConsumed;
 
   aParams = params;
 }
 
 bool InputStreamLengthWrapper::Deserialize(
     const mozilla::ipc::InputStreamParams& aParams,
--- a/xpcom/io/InputStreamLengthWrapper.h
+++ b/xpcom/io/InputStreamLengthWrapper.h
@@ -57,17 +57,18 @@ class InputStreamLengthWrapper final : p
   InputStreamLengthWrapper();
 
  private:
   ~InputStreamLengthWrapper();
 
   template <typename M>
   void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart, M* aManager);
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed, M* aManager);
 
   void SetSourceStream(already_AddRefed<nsIInputStream> aInputStream);
 
   nsCOMPtr<nsIInputStream> mInputStream;
 
   // Raw pointers because these are just QI of mInputStream.
   nsICloneableInputStream* mWeakCloneableInputStream;
   nsIIPCSerializableInputStream* mWeakIPCSerializableInputStream;
--- a/xpcom/io/NonBlockingAsyncInputStream.cpp
+++ b/xpcom/io/NonBlockingAsyncInputStream.cpp
@@ -314,48 +314,58 @@ NonBlockingAsyncInputStream::AsyncWait(n
   return runnable->Run();
 }
 
 // nsIIPCSerializableInputStream
 
 void NonBlockingAsyncInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void NonBlockingAsyncInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::ipc::PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void NonBlockingAsyncInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void NonBlockingAsyncInputStream::Serialize(
     mozilla::ipc::InputStreamParams& aParams,
     FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::ipc::PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 template <typename M>
 void NonBlockingAsyncInputStream::SerializeInternal(
     mozilla::ipc::InputStreamParams& aParams,
-    FileDescriptorArray& aFileDescriptors, bool aDelayedStart, M* aManager) {
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
   MOZ_ASSERT(mWeakIPCSerializableInputStream);
-  InputStreamHelper::SerializeInputStream(
-      mInputStream, aParams, aFileDescriptors, aDelayedStart, aManager);
+  InputStreamHelper::SerializeInputStream(mInputStream, aParams,
+                                          aFileDescriptors, aDelayedStart,
+                                          aMaxSize, aSizeUsed, aManager);
 }
 
 bool NonBlockingAsyncInputStream::Deserialize(
     const mozilla::ipc::InputStreamParams& aParams,
     const FileDescriptorArray& aFileDescriptors) {
   MOZ_CRASH("NonBlockingAsyncInputStream cannot be deserialized!");
   return true;
 }
--- a/xpcom/io/NonBlockingAsyncInputStream.h
+++ b/xpcom/io/NonBlockingAsyncInputStream.h
@@ -42,17 +42,18 @@ class NonBlockingAsyncInputStream final 
  private:
   explicit NonBlockingAsyncInputStream(
       already_AddRefed<nsIInputStream> aInputStream);
   ~NonBlockingAsyncInputStream();
 
   template <typename M>
   void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart, M* aManager);
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed, M* aManager);
 
   class AsyncWaitRunnable;
 
   void RunAsyncWaitCallback(AsyncWaitRunnable* aRunnable,
                             already_AddRefed<nsIInputStreamCallback> aCallback);
 
   nsCOMPtr<nsIInputStream> mInputStream;
 
--- a/xpcom/io/SlicedInputStream.cpp
+++ b/xpcom/io/SlicedInputStream.cpp
@@ -417,52 +417,62 @@ SlicedInputStream::OnInputStreamReady(ns
   return mWeakAsyncInputStream->AsyncWait(
       this, asyncWaitFlags, asyncWaitRequestedCount, asyncWaitEventTarget);
 }
 
 // nsIIPCSerializableInputStream
 
 void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   mozilla::ipc::PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
                                   FileDescriptorArray& aFileDescriptors,
-                                  bool aDelayedStart,
+                                  bool aDelayedStart, uint32_t aMaxSize,
+                                  uint32_t* aSizeUsed,
                                   mozilla::ipc::PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 template <typename M>
 void SlicedInputStream::SerializeInternal(
     mozilla::ipc::InputStreamParams& aParams,
-    FileDescriptorArray& aFileDescriptors, bool aDelayedStart, M* aManager) {
+    FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
   MOZ_ASSERT(mInputStream);
   MOZ_ASSERT(mWeakIPCSerializableInputStream);
 
   SlicedInputStreamParams params;
-  InputStreamHelper::SerializeInputStream(
-      mInputStream, params.stream(), aFileDescriptors, aDelayedStart, aManager);
+  InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
+                                          aFileDescriptors, aDelayedStart,
+                                          aMaxSize, aSizeUsed, aManager);
   params.start() = mStart;
   params.length() = mLength;
   params.curPos() = mCurPos;
   params.closed() = mClosed;
 
   aParams = params;
 }
 
--- a/xpcom/io/SlicedInputStream.h
+++ b/xpcom/io/SlicedInputStream.h
@@ -59,17 +59,18 @@ class SlicedInputStream final : public n
   SlicedInputStream();
 
  private:
   ~SlicedInputStream();
 
   template <typename M>
   void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart, M* aManager);
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed, M* aManager);
 
   void SetSourceStream(already_AddRefed<nsIInputStream> aInputStream);
 
   uint64_t AdjustRange(uint64_t aRange);
 
   nsCOMPtr<nsIInputStream> mInputStream;
 
   // Raw pointers because these are just QI of mInputStream.
--- a/xpcom/io/nsMultiplexInputStream.cpp
+++ b/xpcom/io/nsMultiplexInputStream.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /**
  * The multiplex stream concatenates a list of input streams into a single
  * stream.
  */
 
 #include "mozilla/Attributes.h"
+#include "mozilla/CheckedInt.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Mutex.h"
 #include "mozilla/SystemGroup.h"
 
 #include "base/basictypes.h"
 
 #include "nsMultiplexInputStream.h"
 #include "nsIBufferedStreams.h"
@@ -107,17 +108,18 @@ class nsMultiplexInputStream final : pub
     nsWriteSegmentFun mWriter;
     void* mClosure;
     bool mDone;
   };
 
   template <typename M>
   void SerializeInternal(InputStreamParams& aParams,
                          FileDescriptorArray& aFileDescriptors,
-                         bool aDelayedStart, M* aManager);
+                         bool aDelayedStart, uint32_t aMaxSize,
+                         uint32_t* aSizeUsed, M* aManager);
 
   static nsresult ReadSegCb(nsIInputStream* aIn, void* aClosure,
                             const char* aFromRawSegment, uint32_t aToOffset,
                             uint32_t aCount, uint32_t* aWriteCount);
 
   bool IsSeekable() const;
   bool IsTellable() const;
   bool IsIPCSerializable() const;
@@ -985,69 +987,90 @@ nsresult nsMultiplexInputStreamConstruct
 
   RefPtr<nsMultiplexInputStream> inst = new nsMultiplexInputStream();
 
   return inst->QueryInterface(aIID, aResult);
 }
 
 void nsMultiplexInputStream::Serialize(
     InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
-    bool aDelayedStart, mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+    bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed,
+    mozilla::dom::nsIContentChild* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsMultiplexInputStream::Serialize(InputStreamParams& aParams,
                                        FileDescriptorArray& aFileDescriptors,
-                                       bool aDelayedStart,
+                                       bool aDelayedStart, uint32_t aMaxSize,
+                                       uint32_t* aSizeUsed,
                                        PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsMultiplexInputStream::Serialize(
     InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
-    bool aDelayedStart, mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+    bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed,
+    mozilla::dom::nsIContentParent* aManager) {
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 void nsMultiplexInputStream::Serialize(InputStreamParams& aParams,
                                        FileDescriptorArray& aFileDescriptors,
-                                       bool aDelayedStart,
+                                       bool aDelayedStart, uint32_t aMaxSize,
+                                       uint32_t* aSizeUsed,
                                        PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aManager);
+  SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+                    aSizeUsed, aManager);
 }
 
 template <typename M>
 void nsMultiplexInputStream::SerializeInternal(
     InputStreamParams& aParams, FileDescriptorArray& aFileDescriptors,
-    bool aDelayedStart, M* aManager) {
+    bool aDelayedStart, uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
   MutexAutoLock lock(mLock);
 
   MultiplexInputStreamParams params;
 
+  CheckedUint32 totalSizeUsed = 0;
+  CheckedUint32 maxSize = aMaxSize;
+
   uint32_t streamCount = mStreams.Length();
-
   if (streamCount) {
     InfallibleTArray<InputStreamParams>& streams = params.streams();
 
     streams.SetCapacity(streamCount);
     for (uint32_t index = 0; index < streamCount; index++) {
+      uint32_t sizeUsed = 0;
       InputStreamParams childStreamParams;
       InputStreamHelper::SerializeInputStream(
           mStreams[index].mStream, childStreamParams, aFileDescriptors,
-          aDelayedStart, aManager);
+          aDelayedStart, maxSize.value(), &sizeUsed, aManager);
+      streams.AppendElement(childStreamParams);
+
+      MOZ_ASSERT(maxSize.value() >= sizeUsed);
 
-      streams.AppendElement(childStreamParams);
+      maxSize -= sizeUsed;
+      MOZ_DIAGNOSTIC_ASSERT(maxSize.isValid());
+
+      totalSizeUsed += sizeUsed;
+      MOZ_DIAGNOSTIC_ASSERT(totalSizeUsed.isValid());
     }
   }
 
   params.currentStream() = mCurrentStream;
   params.status() = mStatus;
   params.startedReadingCurrent() = mStartedReadingCurrent;
 
   aParams = params;
+
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = totalSizeUsed.value();
 }
 
 bool nsMultiplexInputStream::Deserialize(
     const InputStreamParams& aParams,
     const FileDescriptorArray& aFileDescriptors) {
   if (aParams.type() != InputStreamParams::TMultiplexInputStreamParams) {
     NS_ERROR("Received unknown parameters from the other process!");
     return false;
--- a/xpcom/io/nsStorageStream.cpp
+++ b/xpcom/io/nsStorageStream.cpp
@@ -363,17 +363,17 @@ class nsStorageInputStream final : publi
     return aPosition >> mStorageStream->mSegmentSizeLog2;
   }
   uint32_t SegOffset(uint32_t aPosition) {
     return aPosition & (mSegmentSize - 1);
   }
 
   template <typename M>
   void SerializeInternal(InputStreamParams& aParams, bool aDelayedStart,
-                         M* aManager);
+                         uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager);
 };
 
 NS_IMPL_ISUPPORTS(nsStorageInputStream, nsIInputStream, nsISeekableStream,
                   nsITellableStream, nsIIPCSerializableInputStream,
                   nsICloneableInputStream)
 
 NS_IMETHODIMP
 nsStorageStream::NewInputStream(int32_t aStartingOffset,
@@ -547,54 +547,62 @@ nsresult nsStorageInputStream::Seek(uint
   uint32_t available = length - aPosition;
   mSegmentEnd = mReadCursor + XPCOM_MIN(mSegmentSize - mReadCursor, available);
   mLogicalCursor = aPosition;
   return NS_OK;
 }
 
 void nsStorageInputStream::Serialize(InputStreamParams& aParams,
                                      FileDescriptorArray&, bool aDelayedStart,
+                                     uint32_t aMaxSize, uint32_t* aSizeUsed,
                                      mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aDelayedStart, aManager);
+  SerializeInternal(aParams, aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void nsStorageInputStream::Serialize(InputStreamParams& aParams,
                                      FileDescriptorArray&, bool aDelayedStart,
+                                     uint32_t aMaxSize, uint32_t* aSizeUsed,
                                      mozilla::ipc::PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aDelayedStart, aManager);
+  SerializeInternal(aParams, aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void nsStorageInputStream::Serialize(InputStreamParams& aParams,
                                      FileDescriptorArray&, bool aDelayedStart,
+                                     uint32_t aMaxSize, uint32_t* aSizeUsed,
                                      mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aDelayedStart, aManager);
+  SerializeInternal(aParams, aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void nsStorageInputStream::Serialize(
     InputStreamParams& aParams, FileDescriptorArray&, bool aDelayedStart,
+    uint32_t aMaxSize, uint32_t* aSizeUsed,
     mozilla::ipc::PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aDelayedStart, aManager);
+  SerializeInternal(aParams, aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 template <typename M>
 void nsStorageInputStream::SerializeInternal(InputStreamParams& aParams,
-                                             bool aDelayedStart, M* aManager) {
+                                             bool aDelayedStart,
+                                             uint32_t aMaxSize,
+                                             uint32_t* aSizeUsed, M* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
+
   uint64_t remaining = 0;
   nsresult rv = Available(&remaining);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
-  // If the string is known to be larger than 1MB, prefer sending it in chunks.
-  const uint64_t kTooLargeStream = 1024 * 1024;
-
-  if (remaining > kTooLargeStream) {
+  if (remaining >= aMaxSize) {
     InputStreamHelper::SerializeInputStreamAsPipe(this, aParams, aDelayedStart,
                                                   aManager);
     return;
   }
 
+  *aSizeUsed = remaining;
+
   nsCString combined;
   int64_t offset;
   rv = Tell(&offset);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
   auto handle = combined.BulkWrite(remaining, 0, false, rv);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
 
--- a/xpcom/io/nsStringStream.cpp
+++ b/xpcom/io/nsStringStream.cpp
@@ -52,17 +52,17 @@ class nsStringInputStream final : public
 
   nsresult Init(nsCString&& aString);
 
  private:
   ~nsStringInputStream() {}
 
   template <typename M>
   void SerializeInternal(InputStreamParams& aParams, bool aDelayedStart,
-                         M* aManager);
+                         uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager);
 
   uint32_t Length() const { return mData.Length(); }
 
   uint32_t LengthRemaining() const { return Length() - mOffset; }
 
   void Clear() { mData.SetIsVoid(true); }
 
   bool Closed() { return mData.IsVoid(); }
@@ -312,54 +312,62 @@ nsStringInputStream::Tell(int64_t* aOutW
 }
 
 /////////
 // nsIIPCSerializableInputStream implementation
 /////////
 
 void nsStringInputStream::Serialize(InputStreamParams& aParams,
                                     FileDescriptorArray& /* aFDs */,
-                                    bool aDelayedStart,
+                                    bool aDelayedStart, uint32_t aMaxSize,
+                                    uint32_t* aSizeUsed,
                                     mozilla::dom::nsIContentChild* aManager) {
-  SerializeInternal(aParams, aDelayedStart, aManager);
+  SerializeInternal(aParams, aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void nsStringInputStream::Serialize(InputStreamParams& aParams,
                                     FileDescriptorArray& /* aFDs */,
-                                    bool aDelayedStart,
+                                    bool aDelayedStart, uint32_t aMaxSize,
+                                    uint32_t* aSizeUsed,
                                     PBackgroundChild* aManager) {
-  SerializeInternal(aParams, aDelayedStart, aManager);
+  SerializeInternal(aParams, aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void nsStringInputStream::Serialize(InputStreamParams& aParams,
                                     FileDescriptorArray& /* aFDs */,
-                                    bool aDelayedStart,
+                                    bool aDelayedStart, uint32_t aMaxSize,
+                                    uint32_t* aSizeUsed,
                                     mozilla::dom::nsIContentParent* aManager) {
-  SerializeInternal(aParams, aDelayedStart, aManager);
+  SerializeInternal(aParams, aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 void nsStringInputStream::Serialize(InputStreamParams& aParams,
                                     FileDescriptorArray& /* aFDs */,
-                                    bool aDelayedStart,
+                                    bool aDelayedStart, uint32_t aMaxSize,
+                                    uint32_t* aSizeUsed,
                                     PBackgroundParent* aManager) {
-  SerializeInternal(aParams, aDelayedStart, aManager);
+  SerializeInternal(aParams, aDelayedStart, aMaxSize, aSizeUsed, aManager);
 }
 
 template <typename M>
 void nsStringInputStream::SerializeInternal(InputStreamParams& aParams,
-                                            bool aDelayedStart, M* aManager) {
-  // If the string is known to be larger than 1MB, prefer sending it in chunks.
-  const uint64_t kTooLargeStream = 1024 * 1024;
+                                            bool aDelayedStart,
+                                            uint32_t aMaxSize,
+                                            uint32_t* aSizeUsed, M* aManager) {
+  MOZ_ASSERT(aSizeUsed);
+  *aSizeUsed = 0;
 
-  if (Length() > kTooLargeStream) {
+  if (Length() >= aMaxSize) {
     InputStreamHelper::SerializeInputStreamAsPipe(this, aParams, aDelayedStart,
                                                   aManager);
     return;
   }
 
+  *aSizeUsed = Length();
+
   StringInputStreamParams params;
   params.data() = PromiseFlatCString(mData);
   aParams = params;
 }
 
 bool nsStringInputStream::Deserialize(const InputStreamParams& aParams,
                                       const FileDescriptorArray& /* aFDs */) {
   if (aParams.type() != InputStreamParams::TStringInputStreamParams) {
--- a/xpcom/tests/gtest/TestNonBlockingAsyncInputStream.cpp
+++ b/xpcom/tests/gtest/TestNonBlockingAsyncInputStream.cpp
@@ -264,22 +264,26 @@ class QIInputStream final : public nsIIn
   // nsICloneableInputStream
   NS_IMETHOD GetCloneable(bool*) override { return NS_ERROR_NOT_IMPLEMENTED; }
   NS_IMETHOD Clone(nsIInputStream**) override {
     return NS_ERROR_NOT_IMPLEMENTED;
   }
 
   // nsIIPCSerializableInputStream
   void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
-                 mozilla::dom::nsIContentChild*) override {}
+                 uint32_t, uint32_t*, mozilla::dom::nsIContentChild*) override {
+  }
   void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
+                 uint32_t, uint32_t*,
                  mozilla::ipc::PBackgroundChild*) override {}
   void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
+                 uint32_t, uint32_t*,
                  mozilla::dom::nsIContentParent*) override {}
   void Serialize(mozilla::ipc::InputStreamParams&, FileDescriptorArray&, bool,
+                 uint32_t, uint32_t*,
                  mozilla::ipc::PBackgroundParent*) override {}
   bool Deserialize(const mozilla::ipc::InputStreamParams&,
                    const FileDescriptorArray&) override {
     return false;
   }
 
   // nsISeekableStream
   NS_IMETHOD Seek(int32_t, int64_t) override {