From ae1df2b2a201d9bc0da6c0846fad17ac4e02b658 Mon Sep 17 00:00:00 2001
From: Andrea Marchesini <amarchesini@mozilla.com>
Date: Fri, 4 Dec 2015 21:15:46 +0000
Subject: [PATCH] Bug 1230509 - BlobImplFile should return false in
 IsDateUnknown and IsSizeUnknown, r=bz

---
 dom/base/BlobSet.h                 |  3 +-
 dom/base/File.cpp                  | 33 ++++++++++----
 dom/base/File.h                    |  7 ++-
 dom/base/MultipartBlobImpl.cpp     | 67 ++++++++++++++++++++++------
 dom/base/MultipartBlobImpl.h       | 47 ++++++++++++--------
 dom/base/StructuredCloneHolder.cpp | 70 +++++++++++++++++++++++++-----
 dom/base/nsFormData.cpp            | 52 +++++++++++++++++-----
 dom/base/nsFormData.h              | 12 +++--
 dom/base/nsXMLHttpRequest.cpp      | 17 +++++---
 dom/base/nsXMLHttpRequest.h        |  2 +-
 dom/fetch/FetchUtil.cpp            | 14 ++++--
 dom/ipc/Blob.cpp                   | 12 +++--
 dom/webidl/FormData.webidl         |  4 ++
 13 files changed, 255 insertions(+), 85 deletions(-)

diff --git a/dom/base/BlobSet.h b/dom/base/BlobSet.h
index 8e5aa0af6204..7b2151aeed3f 100644
--- a/dom/base/BlobSet.h
+++ b/dom/base/BlobSet.h
@@ -32,7 +32,8 @@ public:
   nsTArray<RefPtr<BlobImpl>>& GetBlobImpls() { Flush(); return mBlobImpls; }
 
   already_AddRefed<Blob> GetBlobInternal(nsISupports* aParent,
-                                         const nsACString& aContentType);
+                                         const nsACString& aContentType,
+                                         ErrorResult& aRv);
 
 protected:
   bool ExpandBufferSize(uint64_t aSize)
diff --git a/dom/base/File.cpp b/dom/base/File.cpp
index e3df761998a9..5cc20a76e46e 100644
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -257,7 +257,7 @@ Blob::ToFile()
 }
 
 already_AddRefed<File>
-Blob::ToFile(const nsAString& aName) const
+Blob::ToFile(const nsAString& aName, ErrorResult& aRv) const
 {
   nsAutoTArray<RefPtr<BlobImpl>, 1> blobImpls;
   blobImpls.AppendElement(mImpl);
@@ -266,7 +266,10 @@ Blob::ToFile(const nsAString& aName) const
   mImpl->GetType(contentType);
 
   RefPtr<MultipartBlobImpl> impl =
-    new MultipartBlobImpl(blobImpls, aName, contentType);
+    MultipartBlobImpl::Create(blobImpls, aName, contentType, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
 
   RefPtr<File> file = new File(mParent, impl);
   return file.forget();
@@ -347,7 +350,11 @@ Blob::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
 {
   RefPtr<MultipartBlobImpl> impl = new MultipartBlobImpl();
 
-  impl->InitializeBlob();
+  impl->InitializeBlob(aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
   MOZ_ASSERT(!impl->IsFile());
 
   RefPtr<Blob> blob = Blob::Create(aGlobal.GetAsSupports(), impl);
@@ -851,7 +858,7 @@ BlobImplFile::GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv) con
 uint64_t
 BlobImplFile::GetSize(ErrorResult& aRv)
 {
-  if (IsSizeUnknown()) {
+  if (BlobImplBase::IsSizeUnknown()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy size when using the whole file");
     int64_t fileSize;
@@ -902,7 +909,7 @@ int64_t
 BlobImplFile::GetLastModified(ErrorResult& aRv)
 {
   NS_ASSERTION(mIsFile, "Should only be called on files");
-  if (IsDateUnknown()) {
+  if (BlobImplBase::IsDateUnknown()) {
     PRTime msecs;
     aRv = mFile->GetLastModifiedTime(&msecs);
     if (NS_WARN_IF(aRv.Failed())) {
@@ -1121,11 +1128,19 @@ BlobImplTemporaryBlob::GetInternalStream(nsIInputStream** aStream,
 // BlobSet implementation
 
 already_AddRefed<Blob>
-BlobSet::GetBlobInternal(nsISupports* aParent, const nsACString& aContentType)
+BlobSet::GetBlobInternal(nsISupports* aParent,
+                         const nsACString& aContentType,
+                         ErrorResult& aRv)
 {
-  RefPtr<Blob> blob = Blob::Create(aParent,
-    new MultipartBlobImpl(GetBlobImpls(),
-                          NS_ConvertASCIItoUTF16(aContentType)));
+  RefPtr<BlobImpl> blobImpl =
+    MultipartBlobImpl::Create(GetBlobImpls(),
+                              NS_ConvertASCIItoUTF16(aContentType),
+                              aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  RefPtr<Blob> blob = Blob::Create(aParent, blobImpl);
   return blob.forget();
 }
 
diff --git a/dom/base/File.h b/dom/base/File.h
index 8264a9bc679b..43c2ed3b0b3a 100644
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -118,7 +118,8 @@ public:
 
   // This method creates a new File object with the given name and the same
   // BlobImpl.
-  already_AddRefed<File> ToFile(const nsAString& aName) const;
+  already_AddRefed<File> ToFile(const nsAString& aName,
+                                ErrorResult& aRv) const;
 
   already_AddRefed<Blob>
   CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType,
@@ -798,6 +799,10 @@ public:
 
   virtual void LookupAndCacheIsDirectory() override;
 
+  // We always have size and date for this kind of blob.
+  virtual bool IsSizeUnknown() const override { return false; }
+  virtual bool IsDateUnknown() const override { return false; }
+
 protected:
   virtual ~BlobImplFile() {
     if (mFile && mIsTemporary) {
diff --git a/dom/base/MultipartBlobImpl.cpp b/dom/base/MultipartBlobImpl.cpp
index 4d2c309c2fe5..98671429edad 100644
--- a/dom/base/MultipartBlobImpl.cpp
+++ b/dom/base/MultipartBlobImpl.cpp
@@ -25,6 +25,37 @@ using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS_INHERITED0(MultipartBlobImpl, BlobImpl)
 
+/* static */ already_AddRefed<MultipartBlobImpl>
+MultipartBlobImpl::Create(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
+                          const nsAString& aName,
+                          const nsAString& aContentType,
+                          ErrorResult& aRv)
+{
+  RefPtr<MultipartBlobImpl> blobImpl =
+    new MultipartBlobImpl(aBlobImpls, aName, aContentType);
+  blobImpl->SetLengthAndModifiedDate(aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  return blobImpl.forget();
+}
+
+/* static */ already_AddRefed<MultipartBlobImpl>
+MultipartBlobImpl::Create(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
+                          const nsAString& aContentType,
+                          ErrorResult& aRv)
+{
+  RefPtr<MultipartBlobImpl> blobImpl =
+    new MultipartBlobImpl(aBlobImpls, aContentType);
+  blobImpl->SetLengthAndModifiedDate(aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  return blobImpl.forget();
+}
+
 void
 MultipartBlobImpl::GetInternalStream(nsIInputStream** aStream,
                                      ErrorResult& aRv)
@@ -125,15 +156,19 @@ MultipartBlobImpl::CreateSlice(uint64_t aStart, uint64_t aLength,
   }
 
   // we can create our blob now
-  RefPtr<BlobImpl> impl =
-    new MultipartBlobImpl(blobImpls, aContentType);
+  RefPtr<BlobImpl> impl = Create(blobImpls, aContentType, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
   return impl.forget();
 }
 
 void
-MultipartBlobImpl::InitializeBlob()
+MultipartBlobImpl::InitializeBlob(ErrorResult& aRv)
 {
-  SetLengthAndModifiedDate();
+  SetLengthAndModifiedDate(aRv);
+  NS_WARN_IF(aRv.Failed());
 }
 
 void
@@ -187,11 +222,12 @@ MultipartBlobImpl::InitializeBlob(
 
 
   mBlobImpls = blobSet.GetBlobImpls();
-  SetLengthAndModifiedDate();
+  SetLengthAndModifiedDate(aRv);
+  NS_WARN_IF(aRv.Failed());
 }
 
 void
-MultipartBlobImpl::SetLengthAndModifiedDate()
+MultipartBlobImpl::SetLengthAndModifiedDate(ErrorResult& aRv)
 {
   MOZ_ASSERT(mLength == UINT64_MAX);
   MOZ_ASSERT(mLastModificationDate == INT64_MAX);
@@ -208,16 +244,19 @@ MultipartBlobImpl::SetLengthAndModifiedDate()
     MOZ_ASSERT(!blob->IsDateUnknown());
 #endif
 
-    ErrorResult error;
-    uint64_t subBlobLength = blob->GetSize(error);
-    MOZ_ALWAYS_TRUE(!error.Failed());
+    uint64_t subBlobLength = blob->GetSize(aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return;
+    }
 
     MOZ_ASSERT(UINT64_MAX - subBlobLength >= totalLength);
     totalLength += subBlobLength;
 
     if (blob->IsFile()) {
-      int64_t partLastModified = blob->GetLastModified(error);
-      MOZ_ALWAYS_TRUE(!error.Failed());
+      int64_t partLastModified = blob->GetLastModified(aRv);
+      if (NS_WARN_IF(aRv.Failed())) {
+        return;
+      }
 
       if (lastModified < partLastModified) {
         lastModified = partLastModified;
@@ -314,7 +353,8 @@ MultipartBlobImpl::InitializeChromeFile(Blob& aBlob,
   blobSet.AppendBlobImpl(aBlob.Impl());
   mBlobImpls = blobSet.GetBlobImpls();
 
-  SetLengthAndModifiedDate();
+  SetLengthAndModifiedDate(aRv);
+  NS_WARN_IF(aRv.Failed());
 }
 
 void
@@ -385,7 +425,8 @@ MultipartBlobImpl::InitializeChromeFile(nsPIDOMWindow* aWindow,
   blobSet.AppendBlobImpl(static_cast<File*>(blob.get())->Impl());
   mBlobImpls = blobSet.GetBlobImpls();
 
-  SetLengthAndModifiedDate();
+  SetLengthAndModifiedDate(aRv);
+  NS_WARN_IF(aRv.Failed());
 }
 
 void
diff --git a/dom/base/MultipartBlobImpl.h b/dom/base/MultipartBlobImpl.h
index 2a0778be28cc..2239a4936ed3 100644
--- a/dom/base/MultipartBlobImpl.h
+++ b/dom/base/MultipartBlobImpl.h
@@ -25,25 +25,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
 
   // Create as a file
-  MultipartBlobImpl(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
-                    const nsAString& aName,
-                    const nsAString& aContentType)
-    : BlobImplBase(aName, aContentType, UINT64_MAX),
-      mBlobImpls(aBlobImpls),
-      mIsFromNsIFile(false)
-  {
-    SetLengthAndModifiedDate();
-  }
+  static already_AddRefed<MultipartBlobImpl>
+  Create(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
+         const nsAString& aName,
+         const nsAString& aContentType,
+         ErrorResult& aRv);
 
   // Create as a blob
-  MultipartBlobImpl(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
-                    const nsAString& aContentType)
-    : BlobImplBase(aContentType, UINT64_MAX),
-      mBlobImpls(aBlobImpls),
-      mIsFromNsIFile(false)
-  {
-    SetLengthAndModifiedDate();
-  }
+  static already_AddRefed<MultipartBlobImpl>
+  Create(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
+         const nsAString& aContentType,
+         ErrorResult& aRv);
 
   // Create as a file to be later initialized
   explicit MultipartBlobImpl(const nsAString& aName)
@@ -59,7 +51,7 @@ public:
   {
   }
 
-  void InitializeBlob();
+  void InitializeBlob(ErrorResult& aRv);
 
   void InitializeBlob(
        JSContext* aCx,
@@ -120,9 +112,26 @@ public:
   virtual bool MayBeClonedToOtherThreads() const override;
 
 protected:
+  MultipartBlobImpl(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
+                    const nsAString& aName,
+                    const nsAString& aContentType)
+    : BlobImplBase(aName, aContentType, UINT64_MAX),
+      mBlobImpls(aBlobImpls),
+      mIsFromNsIFile(false)
+  {
+  }
+
+  MultipartBlobImpl(const nsTArray<RefPtr<BlobImpl>>& aBlobImpls,
+                    const nsAString& aContentType)
+    : BlobImplBase(aContentType, UINT64_MAX),
+      mBlobImpls(aBlobImpls),
+      mIsFromNsIFile(false)
+  {
+  }
+
   virtual ~MultipartBlobImpl() {}
 
-  void SetLengthAndModifiedDate();
+  void SetLengthAndModifiedDate(ErrorResult& aRv);
 
   nsTArray<RefPtr<BlobImpl>> mBlobImpls;
   bool mIsFromNsIFile;
diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp
index b069f7d7b1f7..d6932d376dd7 100644
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -555,7 +555,8 @@ namespace {
 // Recursive!
 already_AddRefed<BlobImpl>
 EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
-                               PBackgroundChild* aManager = nullptr)
+                               PBackgroundChild* aManager,
+                               ErrorResult& aRv)
 {
   MOZ_ASSERT(aBlobImpl);
   RefPtr<BlobImpl> blobImpl = aBlobImpl;
@@ -604,7 +605,11 @@ EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
 
     RefPtr<BlobImpl>& newSubBlobImpl = newSubBlobImpls[index];
 
-    newSubBlobImpl = EnsureBlobForBackgroundManager(subBlobImpl, aManager);
+    newSubBlobImpl = EnsureBlobForBackgroundManager(subBlobImpl, aManager, aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
+    }
+
     MOZ_ASSERT(newSubBlobImpl);
 
     if (subBlobImpl != newSubBlobImpl) {
@@ -620,9 +625,14 @@ EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl,
       nsString name;
       blobImpl->GetName(name);
 
-      blobImpl = new MultipartBlobImpl(newSubBlobImpls, name, contentType);
+      blobImpl = MultipartBlobImpl::Create(newSubBlobImpls, name,
+                                           contentType, aRv);
     } else {
-      blobImpl = new MultipartBlobImpl(newSubBlobImpls, contentType);
+      blobImpl = MultipartBlobImpl::Create(newSubBlobImpls, contentType, aRv);
+    }
+
+    if (NS_WARN_IF(aRv.Failed())) {
+      return nullptr;
     }
 
     MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
@@ -640,7 +650,13 @@ ReadBlob(JSContext* aCx,
   MOZ_ASSERT(aIndex < aHolder->BlobImpls().Length());
   RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[aIndex];
 
-  blobImpl = EnsureBlobForBackgroundManager(blobImpl);
+  ErrorResult rv;
+  blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    rv.SuppressException();
+    return nullptr;
+  }
+
   MOZ_ASSERT(blobImpl);
 
   // RefPtr<File> needs to go out of scope before toObjectOrNull() is
@@ -668,7 +684,14 @@ WriteBlob(JSStructuredCloneWriter* aWriter,
   MOZ_ASSERT(aBlob);
   MOZ_ASSERT(aHolder);
 
-  RefPtr<BlobImpl> blobImpl = EnsureBlobForBackgroundManager(aBlob->Impl());
+  ErrorResult rv;
+  RefPtr<BlobImpl> blobImpl =
+    EnsureBlobForBackgroundManager(aBlob->Impl(), nullptr, rv);
+  if (NS_WARN_IF(rv.Failed())) {
+    rv.SuppressException();
+    return false;
+  }
+
   MOZ_ASSERT(blobImpl);
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
@@ -714,7 +737,13 @@ ReadFileList(JSContext* aCx,
       RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[index];
       MOZ_ASSERT(blobImpl->IsFile());
 
-      blobImpl = EnsureBlobForBackgroundManager(blobImpl);
+      ErrorResult rv;
+      blobImpl = EnsureBlobForBackgroundManager(blobImpl, nullptr, rv);
+      if (NS_WARN_IF(rv.Failed())) {
+        rv.SuppressException();
+        return nullptr;
+      }
+
       MOZ_ASSERT(blobImpl);
 
       RefPtr<File> file = File::Create(aHolder->ParentDuringRead(), blobImpl);
@@ -753,14 +782,22 @@ WriteFileList(JSStructuredCloneWriter* aWriter,
     return false;
   }
 
+  ErrorResult rv;
+  nsTArray<RefPtr<BlobImpl>> blobImpls;
+
   for (uint32_t i = 0; i < aFileList->Length(); ++i) {
     RefPtr<BlobImpl> blobImpl =
-      EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl());
-    MOZ_ASSERT(blobImpl);
+      EnsureBlobForBackgroundManager(aFileList->Item(i)->Impl(), nullptr, rv);
+    if (NS_WARN_IF(rv.Failed())) {
+      rv.SuppressException();
+      return false;
+    }
 
-    aHolder->BlobImpls().AppendElement(blobImpl);
+    MOZ_ASSERT(blobImpl);
+    blobImpls.AppendElement(blobImpl);
   }
 
+  aHolder->BlobImpls().AppendElements(blobImpls);
   return true;
 }
 
@@ -804,7 +841,12 @@ ReadFormData(JSContext* aCx,
           File::Create(aHolder->ParentDuringRead(), blobImpl);
         MOZ_ASSERT(file);
 
-        formData->Append(name, *file, thirdArg);
+        ErrorResult rv;
+        formData->Append(name, *file, thirdArg, rv);
+        if (NS_WARN_IF(rv.Failed())) {
+          return nullptr;
+        }
+
       } else {
         MOZ_ASSERT(tag == 0);
 
@@ -816,7 +858,11 @@ ReadFormData(JSContext* aCx,
           return nullptr;
         }
 
-        formData->Append(name, value);
+        ErrorResult rv;
+        formData->Append(name, value, rv);
+        if (NS_WARN_IF(rv.Failed())) {
+          return nullptr;
+        }
       }
     }
 
diff --git a/dom/base/nsFormData.cpp b/dom/base/nsFormData.cpp
index 97f83ff36a7d..c47f7a0bdb49 100644
--- a/dom/base/nsFormData.cpp
+++ b/dom/base/nsFormData.cpp
@@ -25,7 +25,8 @@ namespace {
 
 // Implements steps 3 and 4 of the "create an entry" algorithm of FormData.
 already_AddRefed<File>
-CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename)
+CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename,
+                      ErrorResult& aRv)
 {
   // Step 3 "If value is a Blob object and not a File object, set value to
   // a new File object, representing the same bytes, whose name attribute value
@@ -47,7 +48,12 @@ CreateNewFileInstance(Blob& aBlob, const Optional<nsAString>& aFilename)
     filename = NS_LITERAL_STRING("blob");
   }
 
-  return aBlob.ToFile(filename);
+  RefPtr<File> file = aBlob.ToFile(filename, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  return file.forget();
 }
 
 } // namespace
@@ -101,16 +107,22 @@ nsFormData::GetEncodedSubmission(nsIURI* aURI,
 }
 
 void
-nsFormData::Append(const nsAString& aName, const nsAString& aValue)
+nsFormData::Append(const nsAString& aName, const nsAString& aValue,
+                   ErrorResult& aRv)
 {
   AddNameValuePair(aName, aValue);
 }
 
 void
 nsFormData::Append(const nsAString& aName, Blob& aBlob,
-                   const Optional<nsAString>& aFilename)
+                   const Optional<nsAString>& aFilename,
+                   ErrorResult& aRv)
 {
-  RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
+  RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return;
+  }
+
   AddNameFilePair(aName, file);
 }
 
@@ -196,25 +208,31 @@ nsFormData::RemoveAllOthersAndGetFirstFormDataTuple(const nsAString& aName)
 
 void
 nsFormData::Set(const nsAString& aName, Blob& aBlob,
-                const Optional<nsAString>& aFilename)
+                const Optional<nsAString>& aFilename,
+                ErrorResult& aRv)
 {
   FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
   if (tuple) {
-    RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename);
+    RefPtr<File> file = CreateNewFileInstance(aBlob, aFilename, aRv);
+    if (NS_WARN_IF(aRv.Failed())) {
+      return;
+    }
+
     SetNameFilePair(tuple, aName, file);
   } else {
-    Append(aName, aBlob, aFilename);
+    Append(aName, aBlob, aFilename, aRv);
   }
 }
 
 void
-nsFormData::Set(const nsAString& aName, const nsAString& aValue)
+nsFormData::Set(const nsAString& aName, const nsAString& aValue,
+                ErrorResult& aRv)
 {
   FormDataTuple* tuple = RemoveAllOthersAndGetFirstFormDataTuple(aName);
   if (tuple) {
     SetNameValuePair(tuple, aName, aValue);
   } else {
-    Append(aName, aValue);
+    Append(aName, aValue, aRv);
   }
 }
 
@@ -261,7 +279,12 @@ nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
     RefPtr<Blob> blob = static_cast<Blob*>(domBlob.get());
     if (domBlob) {
       Optional<nsAString> temp;
-      Append(aName, *blob, temp);
+      ErrorResult rv;
+      Append(aName, *blob, temp, rv);
+      if (NS_WARN_IF(rv.Failed())) {
+        return rv.StealNSResult();
+      }
+
       return NS_OK;
     }
   }
@@ -274,7 +297,12 @@ nsFormData::Append(const nsAString& aName, nsIVariant* aValue)
   nsString valAsString;
   valAsString.Adopt(stringData, stringLen);
 
-  Append(aName, valAsString);
+  ErrorResult error;
+  Append(aName, valAsString, error);
+  if (NS_WARN_IF(error.Failed())) {
+    return error.StealNSResult();
+  }
+
   return NS_OK;
 }
 
diff --git a/dom/base/nsFormData.h b/dom/base/nsFormData.h
index 1b428f7d7ea9..d6e06b05e52a 100644
--- a/dom/base/nsFormData.h
+++ b/dom/base/nsFormData.h
@@ -93,16 +93,20 @@ public:
   Constructor(const mozilla::dom::GlobalObject& aGlobal,
               const mozilla::dom::Optional<mozilla::dom::NonNull<mozilla::dom::HTMLFormElement> >& aFormElement,
               mozilla::ErrorResult& aRv);
-  void Append(const nsAString& aName, const nsAString& aValue);
+  void Append(const nsAString& aName, const nsAString& aValue,
+              mozilla::ErrorResult& aRv);
   void Append(const nsAString& aName, Blob& aBlob,
-              const mozilla::dom::Optional<nsAString>& aFilename);
+              const mozilla::dom::Optional<nsAString>& aFilename,
+              mozilla::ErrorResult& aRv);
   void Delete(const nsAString& aName);
   void Get(const nsAString& aName, mozilla::dom::Nullable<OwningFileOrUSVString>& aOutValue);
   void GetAll(const nsAString& aName, nsTArray<OwningFileOrUSVString>& aValues);
   bool Has(const nsAString& aName);
   void Set(const nsAString& aName, Blob& aBlob,
-           const mozilla::dom::Optional<nsAString>& aFilename);
-  void Set(const nsAString& aName, const nsAString& aValue);
+           const mozilla::dom::Optional<nsAString>& aFilename,
+           mozilla::ErrorResult& aRv);
+  void Set(const nsAString& aName, const nsAString& aValue,
+           mozilla::ErrorResult& aRv);
 
   uint32_t GetIterableLength() const;
   const nsAString& GetKeyAtIndex(uint32_t aIndex) const;
diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp
index 95b2b4165cf4..5747dc5cf4c2 100644
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -798,7 +798,7 @@ nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
 }
 
 void
-nsXMLHttpRequest::CreatePartialBlob()
+nsXMLHttpRequest::CreatePartialBlob(ErrorResult& aRv)
 {
   if (mDOMBlob) {
     // Use progress info to determine whether load is complete, but use
@@ -807,9 +807,8 @@ nsXMLHttpRequest::CreatePartialBlob()
     if (mLoadTotal == mLoadTransferred) {
       mResponseBlob = mDOMBlob;
     } else {
-      ErrorResult rv;
       mResponseBlob = mDOMBlob->CreateSlice(0, mDataAvailable,
-                                            EmptyString(), rv);
+                                            EmptyString(), aRv);
     }
     return;
   }
@@ -824,7 +823,7 @@ nsXMLHttpRequest::CreatePartialBlob()
     mChannel->GetContentType(contentType);
   }
 
-  mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType);
+  mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType, aRv);
 }
 
 NS_IMETHODIMP nsXMLHttpRequest::GetResponseType(nsAString& aResponseType)
@@ -1018,7 +1017,7 @@ nsXMLHttpRequest::GetResponse(JSContext* aCx,
       }
 
       if (!mResponseBlob) {
-        CreatePartialBlob();
+        CreatePartialBlob(aRv);
       }
     }
 
@@ -2211,8 +2210,14 @@ nsXMLHttpRequest::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult
       // Also, no-store response cannot be written in persistent cache.
       nsAutoCString contentType;
       mChannel->GetContentType(contentType);
-      mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType);
+
+      ErrorResult rv;
+      mResponseBlob = mBlobSet->GetBlobInternal(GetOwner(), contentType, rv);
       mBlobSet = nullptr;
+
+      if (NS_WARN_IF(rv.Failed())) {
+        return rv.StealNSResult();
+      }
     }
     NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
     NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
diff --git a/dom/base/nsXMLHttpRequest.h b/dom/base/nsXMLHttpRequest.h
index a317fcfe4952..cc2697590c49 100644
--- a/dom/base/nsXMLHttpRequest.h
+++ b/dom/base/nsXMLHttpRequest.h
@@ -605,7 +605,7 @@ protected:
                 uint32_t count,
                 uint32_t *writeCount);
   nsresult CreateResponseParsedJSON(JSContext* aCx);
-  void CreatePartialBlob();
+  void CreatePartialBlob(ErrorResult& aRv);
   bool CreateDOMBlob(nsIRequest *request);
   // Change the state of the object with this. The broadcast argument
   // determines if the onreadystatechange listener should be called.
diff --git a/dom/fetch/FetchUtil.cpp b/dom/fetch/FetchUtil.cpp
index 94f4dd99c5a5..943e63707b8d 100644
--- a/dom/fetch/FetchUtil.cpp
+++ b/dom/fetch/FetchUtil.cpp
@@ -203,7 +203,9 @@ public:
   bool URLParamsIterator(const nsString& aName,
                          const nsString& aValue) override
   {
-    mFormData->Append(aName, aValue);
+    ErrorResult rv;
+    mFormData->Append(aName, aValue, rv);
+    MOZ_ASSERT(!rv.Failed());
     return true;
   }
 
@@ -392,7 +394,9 @@ private:
     NS_ConvertUTF8toUTF16 name(mName);
 
     if (mFilename.IsVoid()) {
-      mFormData->Append(name, NS_ConvertUTF8toUTF16(body));
+      ErrorResult rv;
+      mFormData->Append(name, NS_ConvertUTF8toUTF16(body), rv);
+      MOZ_ASSERT(!rv.Failed());
     } else {
       // Unfortunately we've to copy the data first since all our strings are
       // going to free it. We also need fallible alloc, so we can't just use
@@ -417,7 +421,11 @@ private:
                                NS_ConvertUTF8toUTF16(mFilename),
                                NS_ConvertUTF8toUTF16(mContentType), /* aLastModifiedDate */ 0);
       Optional<nsAString> dummy;
-      mFormData->Append(name, *file, dummy);
+      ErrorResult rv;
+      mFormData->Append(name, *file, dummy, rv);
+      if (NS_WARN_IF(rv.Failed())) {
+        return false;
+      }
     }
 
     return true;
diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp
index b3653cf08ff6..cee6625e7907 100644
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -904,13 +904,17 @@ CreateBlobImpl(const nsTArray<BlobData>& aBlobDatas,
     MOZ_ASSERT(!isMutable);
   }
 
+  ErrorResult rv;
   RefPtr<BlobImpl> blobImpl;
   if (!hasRecursed && aMetadata.IsFile()) {
-    blobImpl =
-      new MultipartBlobImpl(blobImpls, aMetadata.mName, aMetadata.mContentType);
+    blobImpl = MultipartBlobImpl::Create(blobImpls, aMetadata.mName,
+                                         aMetadata.mContentType, rv);
   } else {
-    blobImpl =
-      new MultipartBlobImpl(blobImpls, aMetadata.mContentType);
+    blobImpl = MultipartBlobImpl::Create(blobImpls, aMetadata.mContentType, rv);
+  }
+
+  if (NS_WARN_IF(rv.Failed())) {
+    return nullptr;
   }
 
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(blobImpl->SetMutable(false)));
diff --git a/dom/webidl/FormData.webidl b/dom/webidl/FormData.webidl
index f5902c4efe00..455ea505da9d 100644
--- a/dom/webidl/FormData.webidl
+++ b/dom/webidl/FormData.webidl
@@ -12,13 +12,17 @@ typedef (File or USVString) FormDataEntryValue;
 [Constructor(optional HTMLFormElement form),
  Exposed=(Window,Worker)]
 interface FormData {
+  [Throws]
   void append(USVString name, Blob value, optional USVString filename);
+  [Throws]
   void append(USVString name, USVString value);
   void delete(USVString name);
   FormDataEntryValue? get(USVString name);
   sequence<FormDataEntryValue> getAll(USVString name);
   boolean has(USVString name);
+  [Throws]
   void set(USVString name, Blob value, optional USVString filename);
+  [Throws]
   void set(USVString name, USVString value);
   iterable<USVString, FormDataEntryValue>;
 };