Bug 860731 - Part e: Additional cleanup and fixes; r=bent
authorJan Varga <jan.varga@gmail.com>
Mon, 07 Apr 2014 15:03:35 +0200
changeset 195795 6d797ac4d78ee633b29f5cc609290a6560489e04
parent 195794 daf5df0306b2f314992d551ad19c5c720c2c2408
child 195796 79db871959fdd3ca1dcfecf1f1cfdc4eb855a0ca
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs860731
milestone31.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 860731 - Part e: Additional cleanup and fixes; r=bent
dom/file/FileHandle.h
dom/file/FileRequest.h
dom/file/LockedFile.cpp
dom/file/LockedFile.h
--- a/dom/file/FileHandle.h
+++ b/dom/file/FileHandle.h
@@ -12,17 +12,16 @@
 #include "nsIFile.h"
 #include "nsIFileStorage.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/FileModeBinding.h"
 
 class nsIDOMFile;
-class nsIDOMLockedFile;
 class nsIFileStorage;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 class DOMRequest;
 namespace indexedDB {
 class FileInfo;
--- a/dom/file/FileRequest.h
+++ b/dom/file/FileRequest.h
@@ -7,18 +7,16 @@
 #ifndef mozilla_dom_file_filerequest_h__
 #define mozilla_dom_file_filerequest_h__
 
 #include "mozilla/Attributes.h"
 #include "FileCommon.h"
 
 #include "DOMRequest.h"
 
-class nsIDOMLockedFile;
-
 namespace mozilla {
 class EventChainPreVisitor;
 } // namespace mozilla
 
 BEGIN_FILE_NAMESPACE
 
 class FileHelper;
 class LockedFile;
--- a/dom/file/LockedFile.cpp
+++ b/dom/file/LockedFile.cpp
@@ -2,33 +2,33 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "LockedFile.h"
 
 #include "AsyncHelper.h"
-#include "nsIDOMEvent.h"
 #include "FileHandle.h"
 #include "FileHelper.h"
 #include "FileRequest.h"
 #include "FileService.h"
 #include "FileStreamWrappers.h"
 #include "MemoryStreams.h"
 #include "MetadataHelper.h"
 #include "mozilla/dom/DOMRequest.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/LockedFileBinding.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/dom/UnionTypes.h"
 #include "mozilla/EventDispatcher.h"
 #include "nsContentUtils.h"
 #include "nsError.h"
 #include "nsIAppShell.h"
+#include "nsIDOMEvent.h"
 #include "nsIDOMFile.h"
 #include "nsIFileStorage.h"
 #include "nsISeekableStream.h"
 #include "nsNetUtil.h"
 #include "nsStringStream.h"
 #include "nsWidgetsCID.h"
 
 #define STREAM_COPY_BLOCK_SIZE 32768
@@ -239,64 +239,16 @@ LockedFile::Create(FileHandle* aFileHand
   NS_ENSURE_TRUE(service, nullptr);
 
   rv = service->Enqueue(lockedFile, nullptr);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   return lockedFile.forget();
 }
 
-/* static */ already_AddRefed<nsIInputStream>
-LockedFile::GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
-                           ErrorResult& aRv)
-{
-  const char* data = reinterpret_cast<const char*>(aValue.Data());
-  uint32_t length = aValue.Length();
-
-  nsCOMPtr<nsIInputStream> stream;
-  aRv = NS_NewByteInputStream(getter_AddRefs(stream), data, length,
-                              NS_ASSIGNMENT_COPY);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  *aInputLength = length;
-  return stream.forget();
-}
-
-/* static */ already_AddRefed<nsIInputStream>
-LockedFile::GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength,
-                           ErrorResult& aRv)
-{
-  aRv = aValue->GetSize(aInputLength);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  nsCOMPtr<nsIInputStream> stream;
-  aRv = aValue->GetInternalStream(getter_AddRefs(stream));
-  return stream.forget();
-}
-
-/* static */ already_AddRefed<nsIInputStream>
-LockedFile::GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
-                           ErrorResult& aRv)
-{
-  NS_ConvertUTF16toUTF8 cstr(aValue);
-
-  nsCOMPtr<nsIInputStream> stream;
-  aRv = NS_NewCStringInputStream(getter_AddRefs(stream), cstr);
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  *aInputLength = cstr.Length();
-  return stream.forget();
-}
-
 LockedFile::LockedFile()
 : mReadyState(INITIAL),
   mMode(FileMode::Readonly),
   mRequestMode(NORMAL),
   mLocation(0),
   mPendingRequests(0),
   mAborted(false),
   mCreating(false)
@@ -432,24 +384,31 @@ LockedFile::IsOpen() const
     if (FileHelper::GetCurrentLockedFile() == this) {
       return true;
     }
   }
 
   return false;
 }
 
+// virtual
+JSObject*
+LockedFile::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return LockedFileBinding::Wrap(aCx, aScope, this);
+}
+
 already_AddRefed<FileRequest>
 LockedFile::GetMetadata(const DOMFileMetadataParameters& aParameters,
                         ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (!IsOpen()) {
-    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_LOCKEDFILE_INACTIVE_ERR);
+  // Common state checking
+  if (!CheckState(aRv)) {
     return nullptr;
   }
 
   // Do nothing if the window is closed
   if (!GetOwner()) {
     return nullptr;
   }
 
@@ -460,185 +419,167 @@ LockedFile::GetMetadata(const DOMFileMet
     return nullptr;
   }
 
   nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<MetadataHelper> helper =
     new MetadataHelper(this, fileRequest, params);
 
-  if (NS_FAILED(helper->Enqueue())) {
+  if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   return fileRequest.forget();
 }
 
-bool
-LockedFile::CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv)
-{
-  if (!IsOpen()) {
-    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_LOCKEDFILE_INACTIVE_ERR);
-    return false;
-  }
-
-  if (mLocation == UINT64_MAX) {
-    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
-    return false;
-  }
-
-  if (!aSize) {
-    aRv.ThrowTypeError(MSG_INVALID_READ_SIZE);
-    return false;
-  }
-
-  // Do nothing if the window is closed
-  if (!GetOwner()) {
-    return false;
-  }
-
-  return true;
-}
-
 already_AddRefed<FileRequest>
 LockedFile::ReadAsArrayBuffer(uint64_t aSize, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  // State and argument checking for read
   if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
     return nullptr;
   }
 
+  // Do nothing if the window is closed
+  if (!GetOwner()) {
+    return nullptr;
+  }
+
   nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<ReadHelper> helper =
     new ReadHelper(this, fileRequest, mLocation, aSize);
 
-  if (NS_FAILED(helper->Init()) || NS_FAILED(helper->Enqueue())) {
+  if (NS_WARN_IF(NS_FAILED(helper->Init())) ||
+      NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   mLocation += aSize;
 
   return fileRequest.forget();
 }
 
 already_AddRefed<FileRequest>
 LockedFile::ReadAsText(uint64_t aSize, const nsAString& aEncoding,
                        ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  // State and argument checking for read
   if (!CheckStateAndArgumentsForRead(aSize, aRv)) {
     return nullptr;
   }
 
+  // Do nothing if the window is closed
+  if (!GetOwner()) {
+    return nullptr;
+  }
+
   nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<ReadTextHelper> helper =
     new ReadTextHelper(this, fileRequest, mLocation, aSize, aEncoding);
 
-  if (NS_FAILED(helper->Init()) || NS_FAILED(helper->Enqueue())) {
+  if (NS_WARN_IF(NS_FAILED(helper->Init())) ||
+      NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   mLocation += aSize;
 
   return fileRequest.forget();
 }
 
-bool
-LockedFile::CheckStateForWrite(ErrorResult& aRv)
-{
-  if (!IsOpen()) {
-    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_LOCKEDFILE_INACTIVE_ERR);
-    return false;
-  }
-
-  if (mMode != FileMode::Readwrite) {
-    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR);
-    return false;
-  }
-
-  // Do nothing if the window is closed
-  if (!GetOwner()) {
-    return false;
-  }
-
-  return true;
-}
-
 already_AddRefed<FileRequest>
 LockedFile::Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  // State checking for write
+  if (!CheckStateForWrite(aRv)) {
+    return nullptr;
+  }
+
+  // Getting location and additional state checking for truncate
   uint64_t location;
   if (aSize.WasPassed()) {
     // Just in case someone calls us from C++
     NS_ASSERTION(aSize.Value() != UINT64_MAX, "Passed wrong size!");
     location = aSize.Value();
   } else {
     if (mLocation == UINT64_MAX) {
       aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
       return nullptr;
     }
     location = mLocation;
   }
 
-  if (!CheckStateForWrite(aRv)) {
+  // Do nothing if the window is closed
+  if (!GetOwner()) {
     return nullptr;
   }
 
   nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<TruncateHelper> helper =
     new TruncateHelper(this, fileRequest, location);
 
-  if (NS_FAILED(helper->Enqueue())) {
+  if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   if (aSize.WasPassed()) {
     mLocation = aSize.Value();
   }
 
   return fileRequest.forget();
 }
 
 already_AddRefed<FileRequest>
 LockedFile::Flush(ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  // State checking for write
   if (!CheckStateForWrite(aRv)) {
     return nullptr;
   }
 
+  // Do nothing if the window is closed
+  if (!GetOwner()) {
+    return nullptr;
+  }
+
   nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   nsRefPtr<FlushHelper> helper = new FlushHelper(this, fileRequest);
 
-  if (NS_FAILED(helper->Enqueue())) {
+  if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   return fileRequest.forget();
 }
 
 void
 LockedFile::Abort(ErrorResult& aRv)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  // This method is special enough for not using generic state checking methods.
+
   // We can't use IsOpen here since we need it to be possible to call Abort()
   // even from outside of transaction callbacks.
   if (mReadyState != LockedFile::INITIAL &&
       mReadyState != LockedFile::LOADING) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
     return;
   }
 
@@ -677,18 +618,20 @@ LockedFile::Run()
 nsresult
 LockedFile::OpenInputStream(bool aWholeFile, uint64_t aStart, uint64_t aLength,
                             nsIInputStream** aResult)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mRequestMode == PARALLEL,
                "Don't call me in other than parallel mode!");
 
-  if (!IsOpen()) {
-    return NS_ERROR_DOM_FILEHANDLE_LOCKEDFILE_INACTIVE_ERR;
+  // Common state checking
+  ErrorResult error;
+  if (!CheckState(error)) {
+    return error.ErrorCode();
   }
 
   // Do nothing if the window is closed
   if (!GetOwner()) {
     return NS_OK;
   }
 
   nsRefPtr<OpenStreamHelper> helper =
@@ -699,43 +642,88 @@ LockedFile::OpenInputStream(bool aWholeF
 
   nsCOMPtr<nsIInputStream>& result = helper->Result();
   NS_ENSURE_TRUE(result, NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
 
   result.forget(aResult);
   return NS_OK;
 }
 
+bool
+LockedFile::CheckState(ErrorResult& aRv)
+{
+  if (!IsOpen()) {
+    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_LOCKEDFILE_INACTIVE_ERR);
+    return false;
+  }
+
+  return true;
+}
+
+bool
+LockedFile::CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv)
+{
+  // Common state checking
+  if (!CheckState(aRv)) {
+    return false;
+  }
+
+  // Additional state checking for read
+  if (mLocation == UINT64_MAX) {
+    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
+    return false;
+  }
+
+  // Argument checking for read
+  if (!aSize) {
+    aRv.ThrowTypeError(MSG_INVALID_READ_SIZE);
+    return false;
+  }
+
+  return true;
+}
+
+bool
+LockedFile::CheckStateForWrite(ErrorResult& aRv)
+{
+  // Common state checking
+  if (!CheckState(aRv)) {
+    return false;
+  }
+
+  // Additional state checking for write
+  if (mMode != FileMode::Readwrite) {
+    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_READ_ONLY_ERR);
+    return false;
+  }
+
+  return true;
+}
+
 already_AddRefed<FileRequest>
-LockedFile::WriteOrAppend(nsIInputStream* aInputStream, uint64_t aInputLength,
+LockedFile::WriteInternal(nsIInputStream* aInputStream, uint64_t aInputLength,
                           bool aAppend, ErrorResult& aRv)
 {
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  if (!aAppend && mLocation == UINT64_MAX) {
-    aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
-    return nullptr;
-  }
+  MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
 
-  if (!CheckStateForWrite(aRv)) {
-    return nullptr;
-  }
-
-  if (!aInputLength) {
-    return nullptr;
-  }
+  DebugOnly<ErrorResult> error;
+  MOZ_ASSERT(CheckStateForWrite(error));
+  MOZ_ASSERT_IF(!aAppend, mLocation != UINT64_MAX);
+  MOZ_ASSERT(aInputStream);
+  MOZ_ASSERT(aInputLength);
+  MOZ_ASSERT(GetOwner());
 
   nsRefPtr<FileRequest> fileRequest = GenerateFileRequest();
 
   uint64_t location = aAppend ? UINT64_MAX : mLocation;
 
   nsRefPtr<WriteHelper> helper =
     new WriteHelper(this, fileRequest, location, aInputStream, aInputLength);
 
-  if (NS_FAILED(helper->Enqueue())) {
+  if (NS_WARN_IF(NS_FAILED(helper->Enqueue()))) {
     aRv.Throw(NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR);
     return nullptr;
   }
 
   if (aAppend) {
     mLocation = UINT64_MAX;
   }
   else {
@@ -758,22 +746,72 @@ LockedFile::Finish()
   nsIEventTarget* target = service->StreamTransportTarget();
 
   nsresult rv = target->Dispatch(helper, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-/* virtual */ JSObject*
-LockedFile::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+// static
+already_AddRefed<nsIInputStream>
+LockedFile::GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
+                           ErrorResult& aRv)
 {
-  return LockedFileBinding::Wrap(aCx, aScope, this);
+  const char* data = reinterpret_cast<const char*>(aValue.Data());
+  uint32_t length = aValue.Length();
+
+  nsCOMPtr<nsIInputStream> stream;
+  aRv = NS_NewByteInputStream(getter_AddRefs(stream), data, length,
+                              NS_ASSIGNMENT_COPY);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  *aInputLength = length;
+  return stream.forget();
 }
 
+// static
+already_AddRefed<nsIInputStream>
+LockedFile::GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength,
+                           ErrorResult& aRv)
+{
+  uint64_t length;
+  aRv = aValue->GetSize(&length);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIInputStream> stream;
+  aRv = aValue->GetInternalStream(getter_AddRefs(stream));
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  *aInputLength = length;
+  return stream.forget();
+}
+
+// static
+already_AddRefed<nsIInputStream>
+LockedFile::GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
+                           ErrorResult& aRv)
+{
+  NS_ConvertUTF16toUTF8 cstr(aValue);
+
+  nsCOMPtr<nsIInputStream> stream;
+  aRv = NS_NewCStringInputStream(getter_AddRefs(stream), cstr);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  *aInputLength = cstr.Length();
+  return stream.forget();
+}
 
 FinishHelper::FinishHelper(LockedFile* aLockedFile)
 : mLockedFile(aLockedFile),
   mAborted(aLockedFile->mAborted)
 {
   mParallelStreams.SwapElements(aLockedFile->mParallelStreams);
   mStream.swap(aLockedFile->mStream);
 }
--- a/dom/file/LockedFile.h
+++ b/dom/file/LockedFile.h
@@ -90,50 +90,67 @@ public:
     return mFileHandle;
   }
 
   nsresult
   OpenInputStream(bool aWholeFile, uint64_t aStart, uint64_t aLength,
                   nsIInputStream** aResult);
 
   // WrapperCache
-  nsPIDOMWindow* GetParentObject() const
-  {
-    return GetOwner();
-  }
-
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
 
   // WebIDL
-  FileHandle* GetFileHandle() const
+  nsPIDOMWindow*
+  GetParentObject() const
   {
+    return GetOwner();
+  }
+
+  FileHandle*
+  GetFileHandle() const
+  {
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
     return Handle();
   }
 
-  FileMode Mode() const
+  FileMode
+  Mode() const
   {
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
     return mMode;
   }
 
-  bool Active() const
+  bool
+  Active() const
   {
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
     return IsOpen();
   }
 
-  Nullable<uint64_t> GetLocation() const
+  Nullable<uint64_t>
+  GetLocation() const
   {
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
     if (mLocation == UINT64_MAX) {
       return Nullable<uint64_t>();
     }
+
     return Nullable<uint64_t>(mLocation);
   }
 
-  void SetLocation(const Nullable<uint64_t>& aLocation)
+  void
+  SetLocation(const Nullable<uint64_t>& aLocation)
   {
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
     // Null means the end-of-file.
     if (aLocation.IsNull()) {
       mLocation = UINT64_MAX;
     } else {
       mLocation = aLocation.Value();
     }
   }
 
@@ -145,88 +162,114 @@ public:
 
   already_AddRefed<FileRequest>
   ReadAsText(uint64_t aSize, const nsAString& aEncoding, ErrorResult& aRv);
 
   template<class T>
   already_AddRefed<FileRequest>
   Write(const T& aValue, ErrorResult& aRv)
   {
-    uint64_t length;
-    nsCOMPtr<nsIInputStream> stream = GetInputStream(aValue, &length, aRv);
-    if (aRv.Failed()) {
-      return nullptr;
-    }
-    return Write(stream, length, aRv);
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+    return WriteOrAppend(aValue, false, aRv);
   }
 
   template<class T>
   already_AddRefed<FileRequest>
   Append(const T& aValue, ErrorResult& aRv)
   {
-    uint64_t length;
-    nsCOMPtr<nsIInputStream> stream = GetInputStream(aValue, &length, aRv);
-    if (aRv.Failed()) {
-      return nullptr;
-    }
-    return Append(stream, length, aRv);
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+    return WriteOrAppend(aValue, true, aRv);
   }
 
   already_AddRefed<FileRequest>
   Truncate(const Optional<uint64_t>& aSize, ErrorResult& aRv);
 
   already_AddRefed<FileRequest>
   Flush(ErrorResult& aRv);
 
-  void Abort(ErrorResult& aRv);
+  void
+  Abort(ErrorResult& aRv);
 
   IMPL_EVENT_HANDLER(complete)
   IMPL_EVENT_HANDLER(abort)
   IMPL_EVENT_HANDLER(error)
 
 private:
   LockedFile();
   ~LockedFile();
 
   void
   OnNewRequest();
 
   void
   OnRequestFinished();
 
-  bool CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv);
-  bool CheckStateForWrite(ErrorResult& aRv);
+  bool
+  CheckState(ErrorResult& aRv);
+
+  bool
+  CheckStateAndArgumentsForRead(uint64_t aSize, ErrorResult& aRv);
+
+  bool
+  CheckStateForWrite(ErrorResult& aRv);
 
   already_AddRefed<FileRequest>
   GenerateFileRequest();
 
+  template<class T>
   already_AddRefed<FileRequest>
-  Write(nsIInputStream* aInputStream, uint64_t aInputLength, ErrorResult& aRv)
+  WriteOrAppend(const T& aValue, bool aAppend, ErrorResult& aRv)
   {
-    return WriteOrAppend(aInputStream, aInputLength, false, aRv);
+    MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
+
+    // State checking for write
+    if (!CheckStateForWrite(aRv)) {
+      return nullptr;
+    }
+
+    // Additional state checking for write
+    if (!aAppend && mLocation == UINT64_MAX) {
+      aRv.Throw(NS_ERROR_DOM_FILEHANDLE_NOT_ALLOWED_ERR);
+      return nullptr;
+    }
+
+    uint64_t length;
+    nsCOMPtr<nsIInputStream> stream = GetInputStream(aValue, &length, aRv);
+    if (aRv.Failed()) {
+      return nullptr;
+    }
+
+    if (!length) {
+      return nullptr;
+    }
+
+    // Do nothing if the window is closed
+    if (!GetOwner()) {
+      return nullptr;
+    }
+
+    return WriteInternal(stream, length, aAppend, aRv);
   }
 
   already_AddRefed<FileRequest>
-  Append(nsIInputStream* aInputStream, uint64_t aInputLength, ErrorResult& aRv)
-  {
-    return WriteOrAppend(aInputStream, aInputLength, true, aRv);
-  }
-
-  already_AddRefed<FileRequest>
-  WriteOrAppend(nsIInputStream* aInputStream, uint64_t aInputLength,
+  WriteInternal(nsIInputStream* aInputStream, uint64_t aInputLength,
                 bool aAppend, ErrorResult& aRv);
 
   nsresult
   Finish();
 
   static already_AddRefed<nsIInputStream>
   GetInputStream(const ArrayBuffer& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
+
   static already_AddRefed<nsIInputStream>
   GetInputStream(nsIDOMBlob* aValue, uint64_t* aInputLength, ErrorResult& aRv);
+
   static already_AddRefed<nsIInputStream>
   GetInputStream(const nsAString& aValue, uint64_t* aInputLength,
                  ErrorResult& aRv);
 
   nsRefPtr<FileHandle> mFileHandle;
   ReadyState mReadyState;
   FileMode mMode;
   RequestMode mRequestMode;