summaryrefslogtreecommitdiffstats
path: root/dom/filesystem/compat
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/filesystem/compat
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/filesystem/compat')
-rw-r--r--dom/filesystem/compat/CallbackRunnables.cpp306
-rw-r--r--dom/filesystem/compat/CallbackRunnables.h128
-rw-r--r--dom/filesystem/compat/FileSystem.cpp75
-rw-r--r--dom/filesystem/compat/FileSystem.h73
-rw-r--r--dom/filesystem/compat/FileSystemDirectoryEntry.cpp107
-rw-r--r--dom/filesystem/compat/FileSystemDirectoryEntry.h84
-rw-r--r--dom/filesystem/compat/FileSystemDirectoryReader.cpp188
-rw-r--r--dom/filesystem/compat/FileSystemDirectoryReader.h64
-rw-r--r--dom/filesystem/compat/FileSystemEntry.cpp89
-rw-r--r--dom/filesystem/compat/FileSystemEntry.h89
-rw-r--r--dom/filesystem/compat/FileSystemFileEntry.cpp138
-rw-r--r--dom/filesystem/compat/FileSystemFileEntry.h57
-rw-r--r--dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp146
-rw-r--r--dom/filesystem/compat/FileSystemRootDirectoryEntry.h53
-rw-r--r--dom/filesystem/compat/FileSystemRootDirectoryReader.cpp96
-rw-r--r--dom/filesystem/compat/FileSystemRootDirectoryReader.h41
-rw-r--r--dom/filesystem/compat/moz.build30
-rw-r--r--dom/filesystem/compat/tests/mochitest.ini8
-rw-r--r--dom/filesystem/compat/tests/moz.build7
-rw-r--r--dom/filesystem/compat/tests/script_entries.js47
-rw-r--r--dom/filesystem/compat/tests/test_basic.html494
-rw-r--r--dom/filesystem/compat/tests/test_formSubmission.html267
-rw-r--r--dom/filesystem/compat/tests/test_no_dnd.html85
23 files changed, 2672 insertions, 0 deletions
diff --git a/dom/filesystem/compat/CallbackRunnables.cpp b/dom/filesystem/compat/CallbackRunnables.cpp
new file mode 100644
index 000000000..efd14b03e
--- /dev/null
+++ b/dom/filesystem/compat/CallbackRunnables.cpp
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CallbackRunnables.h"
+#include "mozilla/dom/Directory.h"
+#include "mozilla/dom/DirectoryBinding.h"
+#include "mozilla/dom/DOMException.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/FileBinding.h"
+#include "mozilla/dom/FileSystemDirectoryReaderBinding.h"
+#include "mozilla/dom/FileSystemFileEntry.h"
+#include "mozilla/dom/FileSystemUtils.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/Unused.h"
+#include "nsIGlobalObject.h"
+#include "nsIFile.h"
+#include "nsPIDOMWindow.h"
+
+#include "../GetFileOrDirectoryTask.h"
+
+namespace mozilla {
+namespace dom {
+
+EntryCallbackRunnable::EntryCallbackRunnable(FileSystemEntryCallback* aCallback,
+ FileSystemEntry* aEntry)
+ : mCallback(aCallback)
+ , mEntry(aEntry)
+{
+ MOZ_ASSERT(aCallback);
+ MOZ_ASSERT(aEntry);
+}
+
+NS_IMETHODIMP
+EntryCallbackRunnable::Run()
+{
+ mCallback->HandleEvent(*mEntry);
+ return NS_OK;
+}
+
+ErrorCallbackRunnable::ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject,
+ ErrorCallback* aCallback,
+ nsresult aError)
+ : mGlobal(aGlobalObject)
+ , mCallback(aCallback)
+ , mError(aError)
+{
+ MOZ_ASSERT(aGlobalObject);
+ MOZ_ASSERT(aCallback);
+ MOZ_ASSERT(NS_FAILED(aError));
+}
+
+NS_IMETHODIMP
+ErrorCallbackRunnable::Run()
+{
+ nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
+ if (NS_WARN_IF(!window)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<DOMException> exception = DOMException::Create(mError);
+ mCallback->HandleEvent(*exception);
+ return NS_OK;
+}
+
+EmptyEntriesCallbackRunnable::EmptyEntriesCallbackRunnable(FileSystemEntriesCallback* aCallback)
+ : mCallback(aCallback)
+{
+ MOZ_ASSERT(aCallback);
+}
+
+NS_IMETHODIMP
+EmptyEntriesCallbackRunnable::Run()
+{
+ Sequence<OwningNonNull<FileSystemEntry>> sequence;
+ mCallback->HandleEvent(sequence);
+ return NS_OK;
+}
+
+GetEntryHelper::GetEntryHelper(FileSystemDirectoryEntry* aParentEntry,
+ Directory* aDirectory,
+ nsTArray<nsString>& aParts,
+ FileSystem* aFileSystem,
+ FileSystemEntryCallback* aSuccessCallback,
+ ErrorCallback* aErrorCallback,
+ FileSystemDirectoryEntry::GetInternalType aType)
+ : mParentEntry(aParentEntry)
+ , mDirectory(aDirectory)
+ , mParts(aParts)
+ , mFileSystem(aFileSystem)
+ , mSuccessCallback(aSuccessCallback)
+ , mErrorCallback(aErrorCallback)
+ , mType(aType)
+{
+ MOZ_ASSERT(aParentEntry);
+ MOZ_ASSERT(aDirectory);
+ MOZ_ASSERT(!aParts.IsEmpty());
+ MOZ_ASSERT(aFileSystem);
+ MOZ_ASSERT(aSuccessCallback || aErrorCallback);
+}
+
+GetEntryHelper::~GetEntryHelper()
+{}
+
+namespace {
+
+nsresult
+DOMPathToRealPath(Directory* aDirectory, const nsAString& aPath,
+ nsIFile** aFile)
+{
+ nsString relativePath;
+ relativePath = aPath;
+
+ // Trim white spaces.
+ static const char kWhitespace[] = "\b\t\r\n ";
+ relativePath.Trim(kWhitespace);
+
+ nsTArray<nsString> parts;
+ if (!FileSystemUtils::IsValidRelativeDOMPath(relativePath, parts)) {
+ return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
+ }
+
+ nsCOMPtr<nsIFile> file;
+ nsresult rv = aDirectory->GetInternalNsIFile()->Clone(getter_AddRefs(file));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ for (uint32_t i = 0; i < parts.Length(); ++i) {
+ rv = file->AppendRelativePath(parts[i]);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ }
+
+ file.forget(aFile);
+ return NS_OK;
+}
+
+} // anonymous
+
+void
+GetEntryHelper::Run()
+{
+ MOZ_ASSERT(!mParts.IsEmpty());
+
+ nsCOMPtr<nsIFile> realPath;
+ nsresult error = DOMPathToRealPath(mDirectory, mParts[0],
+ getter_AddRefs(realPath));
+
+ ErrorResult rv;
+ RefPtr<FileSystemBase> fs = mDirectory->GetFileSystem(rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ rv.SuppressException();
+ Error(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+
+ RefPtr<GetFileOrDirectoryTaskChild> task =
+ GetFileOrDirectoryTaskChild::Create(fs, realPath, rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ rv.SuppressException();
+ Error(NS_ERROR_DOM_INVALID_STATE_ERR);
+ return;
+ }
+
+ task->SetError(error);
+ task->Start();
+
+ RefPtr<Promise> promise = task->GetPromise();
+
+ mParts.RemoveElementAt(0);
+ promise->AppendNativeHandler(this);
+}
+
+void
+GetEntryHelper::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
+{
+ if(NS_WARN_IF(!aValue.isObject())) {
+ return;
+ }
+
+ JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
+
+ // This is not the last part of the path.
+ if (!mParts.IsEmpty()) {
+ ContinueRunning(obj);
+ return;
+ }
+
+ CompleteOperation(obj);
+}
+
+void
+GetEntryHelper::CompleteOperation(JSObject* aObj)
+{
+ MOZ_ASSERT(mParts.IsEmpty());
+
+ if (mType == FileSystemDirectoryEntry::eGetFile) {
+ RefPtr<File> file;
+ if (NS_FAILED(UNWRAP_OBJECT(File, aObj, file))) {
+ Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+ return;
+ }
+
+ RefPtr<FileSystemFileEntry> entry =
+ new FileSystemFileEntry(mParentEntry->GetParentObject(), file,
+ mParentEntry, mFileSystem);
+ mSuccessCallback->HandleEvent(*entry);
+ return;
+ }
+
+ MOZ_ASSERT(mType == FileSystemDirectoryEntry::eGetDirectory);
+
+ RefPtr<Directory> directory;
+ if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
+ Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+ return;
+ }
+
+ RefPtr<FileSystemDirectoryEntry> entry =
+ new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory,
+ mParentEntry, mFileSystem);
+ mSuccessCallback->HandleEvent(*entry);
+}
+
+void
+GetEntryHelper::ContinueRunning(JSObject* aObj)
+{
+ MOZ_ASSERT(!mParts.IsEmpty());
+
+ RefPtr<Directory> directory;
+ if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) {
+ Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+ return;
+ }
+
+ RefPtr<FileSystemDirectoryEntry> entry =
+ new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory,
+ mParentEntry, mFileSystem);
+
+ // Update the internal values.
+ mParentEntry = entry;
+ mDirectory = directory;
+
+ Run();
+}
+
+void
+GetEntryHelper::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
+{
+ Error(NS_ERROR_DOM_NOT_FOUND_ERR);
+}
+
+void
+GetEntryHelper::Error(nsresult aError)
+{
+ MOZ_ASSERT(NS_FAILED(aError));
+
+ if (mErrorCallback) {
+ RefPtr<ErrorCallbackRunnable> runnable =
+ new ErrorCallbackRunnable(mParentEntry->GetParentObject(),
+ mErrorCallback, aError);
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+ }
+}
+
+NS_IMPL_ISUPPORTS0(GetEntryHelper);
+
+/* static */ void
+FileSystemEntryCallbackHelper::Call(const Optional<OwningNonNull<FileSystemEntryCallback>>& aEntryCallback,
+ FileSystemEntry* aEntry)
+{
+ MOZ_ASSERT(aEntry);
+
+ if (aEntryCallback.WasPassed()) {
+ RefPtr<EntryCallbackRunnable> runnable =
+ new EntryCallbackRunnable(&aEntryCallback.Value(), aEntry);
+
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+ }
+}
+
+/* static */ void
+ErrorCallbackHelper::Call(nsIGlobalObject* aGlobal,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ nsresult aError)
+{
+ MOZ_ASSERT(aGlobal);
+ MOZ_ASSERT(NS_FAILED(aError));
+
+ if (aErrorCallback.WasPassed()) {
+ RefPtr<ErrorCallbackRunnable> runnable =
+ new ErrorCallbackRunnable(aGlobal, &aErrorCallback.Value(), aError);
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+ }
+}
+
+} // dom namespace
+} // mozilla namespace
+
diff --git a/dom/filesystem/compat/CallbackRunnables.h b/dom/filesystem/compat/CallbackRunnables.h
new file mode 100644
index 000000000..3ff77f1a9
--- /dev/null
+++ b/dom/filesystem/compat/CallbackRunnables.h
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_ErrorCallbackRunnable_h
+#define mozilla_dom_ErrorCallbackRunnable_h
+
+#include "FileSystemDirectoryEntry.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/PromiseNativeHandler.h"
+
+class nsIGlobalObject;
+
+namespace mozilla {
+namespace dom {
+
+class FileSystemEntriesCallback;
+
+class EntryCallbackRunnable final : public Runnable
+{
+public:
+ EntryCallbackRunnable(FileSystemEntryCallback* aCallback,
+ FileSystemEntry* aEntry);
+
+ NS_IMETHOD
+ Run() override;
+
+private:
+ RefPtr<FileSystemEntryCallback> mCallback;
+ RefPtr<FileSystemEntry> mEntry;
+};
+
+class ErrorCallbackRunnable final : public Runnable
+{
+public:
+ ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject,
+ ErrorCallback* aCallback,
+ nsresult aError);
+
+ NS_IMETHOD
+ Run() override;
+
+private:
+ nsCOMPtr<nsIGlobalObject> mGlobal;
+ RefPtr<ErrorCallback> mCallback;
+ nsresult mError;
+};
+
+class EmptyEntriesCallbackRunnable final : public Runnable
+{
+public:
+ explicit EmptyEntriesCallbackRunnable(FileSystemEntriesCallback* aCallback);
+
+ NS_IMETHOD
+ Run() override;
+
+private:
+ RefPtr<FileSystemEntriesCallback> mCallback;
+};
+
+class GetEntryHelper final : public PromiseNativeHandler
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ GetEntryHelper(FileSystemDirectoryEntry* aParentEntry,
+ Directory* aDirectory,
+ nsTArray<nsString>& aParts,
+ FileSystem* aFileSystem,
+ FileSystemEntryCallback* aSuccessCallback,
+ ErrorCallback* aErrorCallback,
+ FileSystemDirectoryEntry::GetInternalType aType);
+
+ void
+ Run();
+
+ virtual void
+ ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
+
+ virtual void
+ RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
+
+private:
+ ~GetEntryHelper();
+
+ void
+ Error(nsresult aError);
+
+ void
+ ContinueRunning(JSObject* aObj);
+
+ void
+ CompleteOperation(JSObject* aObj);
+
+ RefPtr<FileSystemDirectoryEntry> mParentEntry;
+ RefPtr<Directory> mDirectory;
+ nsTArray<nsString> mParts;
+ RefPtr<FileSystem> mFileSystem;
+
+ RefPtr<FileSystemEntryCallback> mSuccessCallback;
+ RefPtr<ErrorCallback> mErrorCallback;
+
+ FileSystemDirectoryEntry::GetInternalType mType;
+};
+
+class FileSystemEntryCallbackHelper
+{
+public:
+ static void
+ Call(const Optional<OwningNonNull<FileSystemEntryCallback>>& aEntryCallback,
+ FileSystemEntry* aEntry);
+};
+
+class ErrorCallbackHelper
+{
+public:
+ static void
+ Call(nsIGlobalObject* aGlobal,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ nsresult aError);
+};
+
+} // dom namespace
+} // mozilla namespace
+
+#endif // mozilla_dom_CallbackRunnables_h
diff --git a/dom/filesystem/compat/FileSystem.cpp b/dom/filesystem/compat/FileSystem.cpp
new file mode 100644
index 000000000..b45980fc6
--- /dev/null
+++ b/dom/filesystem/compat/FileSystem.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileSystem.h"
+#include "FileSystemRootDirectoryEntry.h"
+#include "mozilla/dom/FileSystemBinding.h"
+#include "nsContentUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileSystem, mParent, mRoot)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FileSystem)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FileSystem)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystem)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/* static */ already_AddRefed<FileSystem>
+FileSystem::Create(nsIGlobalObject* aGlobalObject)
+
+{
+ MOZ_ASSERT(aGlobalObject);
+
+
+ nsID id;
+ nsresult rv = nsContentUtils::GenerateUUIDInPlace(id);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return nullptr;
+ }
+
+ char chars[NSID_LENGTH];
+ id.ToProvidedString(chars);
+
+ // Any fileSystem has an unique ID. We use UUID, but our generator produces
+ // UUID in this format '{' + UUID + '}'. We remove them with these +1 and -2.
+ nsAutoCString name(Substring(chars + 1, chars + NSID_LENGTH - 2));
+
+ RefPtr<FileSystem> fs =
+ new FileSystem(aGlobalObject, NS_ConvertUTF8toUTF16(name));
+
+ return fs.forget();
+}
+
+FileSystem::FileSystem(nsIGlobalObject* aGlobal, const nsAString& aName)
+ : mParent(aGlobal)
+ , mName(aName)
+{
+ MOZ_ASSERT(aGlobal);
+}
+
+FileSystem::~FileSystem()
+{}
+
+JSObject*
+FileSystem::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return FileSystemBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+FileSystem::CreateRoot(const Sequence<RefPtr<FileSystemEntry>>& aEntries)
+{
+ MOZ_ASSERT(!mRoot);
+ mRoot = new FileSystemRootDirectoryEntry(mParent, aEntries, this);
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/filesystem/compat/FileSystem.h b/dom/filesystem/compat/FileSystem.h
new file mode 100644
index 000000000..43ce2ea38
--- /dev/null
+++ b/dom/filesystem/compat/FileSystem.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FileSystem_h
+#define mozilla_dom_FileSystem_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
+
+class nsIGlobalObject;
+
+namespace mozilla {
+namespace dom {
+
+class FileSystemDirectoryEntry;
+class FileSystemEntry;
+class OwningFileOrDirectory;
+
+class FileSystem final
+ : public nsISupports
+ , public nsWrapperCache
+{
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FileSystem)
+
+ static already_AddRefed<FileSystem>
+ Create(nsIGlobalObject* aGlobalObject);
+
+ nsIGlobalObject*
+ GetParentObject() const
+ {
+ return mParent;
+ }
+
+ virtual JSObject*
+ WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ void
+ GetName(nsAString& aName) const
+ {
+ aName = mName;
+ }
+
+ FileSystemDirectoryEntry*
+ Root() const
+ {
+ return mRoot;
+ }
+
+ void
+ CreateRoot(const Sequence<RefPtr<FileSystemEntry>>& aEntries);
+
+private:
+ explicit FileSystem(nsIGlobalObject* aGlobalObject,
+ const nsAString& aName);
+ ~FileSystem();
+
+ nsCOMPtr<nsIGlobalObject> mParent;
+ RefPtr<FileSystemDirectoryEntry> mRoot;
+ nsString mName;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_FileSystem_h
diff --git a/dom/filesystem/compat/FileSystemDirectoryEntry.cpp b/dom/filesystem/compat/FileSystemDirectoryEntry.cpp
new file mode 100644
index 000000000..3157ef654
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemDirectoryEntry.cpp
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileSystemDirectoryEntry.h"
+#include "CallbackRunnables.h"
+#include "FileSystemDirectoryReader.h"
+#include "mozilla/dom/Directory.h"
+#include "mozilla/dom/FileSystemDirectoryEntryBinding.h"
+#include "mozilla/dom/FileSystemUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemDirectoryEntry, FileSystemEntry,
+ mDirectory)
+
+NS_IMPL_ADDREF_INHERITED(FileSystemDirectoryEntry, FileSystemEntry)
+NS_IMPL_RELEASE_INHERITED(FileSystemDirectoryEntry, FileSystemEntry)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileSystemDirectoryEntry)
+NS_INTERFACE_MAP_END_INHERITING(FileSystemEntry)
+
+FileSystemDirectoryEntry::FileSystemDirectoryEntry(nsIGlobalObject* aGlobal,
+ Directory* aDirectory,
+ FileSystemDirectoryEntry* aParentEntry,
+ FileSystem* aFileSystem)
+ : FileSystemEntry(aGlobal, aParentEntry, aFileSystem)
+ , mDirectory(aDirectory)
+{
+ MOZ_ASSERT(aGlobal);
+}
+
+FileSystemDirectoryEntry::~FileSystemDirectoryEntry()
+{}
+
+JSObject*
+FileSystemDirectoryEntry::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto)
+{
+ return FileSystemDirectoryEntryBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+FileSystemDirectoryEntry::GetName(nsAString& aName, ErrorResult& aRv) const
+{
+ MOZ_ASSERT(mDirectory);
+ mDirectory->GetName(aName, aRv);
+}
+
+void
+FileSystemDirectoryEntry::GetFullPath(nsAString& aPath, ErrorResult& aRv) const
+{
+ MOZ_ASSERT(mDirectory);
+ mDirectory->GetPath(aPath, aRv);
+}
+
+already_AddRefed<FileSystemDirectoryReader>
+FileSystemDirectoryEntry::CreateReader()
+{
+ MOZ_ASSERT(mDirectory);
+
+ RefPtr<FileSystemDirectoryReader> reader =
+ new FileSystemDirectoryReader(this, Filesystem(), mDirectory);
+ return reader.forget();
+}
+
+void
+FileSystemDirectoryEntry::GetInternal(const nsAString& aPath,
+ const FileSystemFlags& aFlag,
+ const Optional<OwningNonNull<FileSystemEntryCallback>>& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ GetInternalType aType)
+{
+ MOZ_ASSERT(mDirectory);
+
+ if (!aSuccessCallback.WasPassed() && !aErrorCallback.WasPassed()) {
+ return;
+ }
+
+ if (aFlag.mCreate) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ NS_ERROR_DOM_SECURITY_ERR);
+ return;
+ }
+
+ nsTArray<nsString> parts;
+ if (!FileSystemUtils::IsValidRelativeDOMPath(aPath, parts)) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ NS_ERROR_DOM_NOT_FOUND_ERR);
+ return;
+ }
+
+ RefPtr<GetEntryHelper> helper =
+ new GetEntryHelper(this, mDirectory, parts, Filesystem(),
+ aSuccessCallback.WasPassed()
+ ? &aSuccessCallback.Value() : nullptr,
+ aErrorCallback.WasPassed()
+ ? &aErrorCallback.Value() : nullptr,
+ aType);
+ helper->Run();
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/filesystem/compat/FileSystemDirectoryEntry.h b/dom/filesystem/compat/FileSystemDirectoryEntry.h
new file mode 100644
index 000000000..96dc21831
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemDirectoryEntry.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FileSystemDirectoryEntry_h
+#define mozilla_dom_FileSystemDirectoryEntry_h
+
+#include "mozilla/dom/FileSystemEntry.h"
+
+namespace mozilla {
+namespace dom {
+
+class Directory;
+class FileSystemDirectoryReader;
+
+class FileSystemDirectoryEntry : public FileSystemEntry
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileSystemDirectoryEntry,
+ FileSystemEntry)
+
+ FileSystemDirectoryEntry(nsIGlobalObject* aGlobalObject,
+ Directory* aDirectory,
+ FileSystemDirectoryEntry* aParentEntry,
+ FileSystem* aFileSystem);
+
+ virtual JSObject*
+ WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ virtual bool
+ IsDirectory() const override
+ {
+ return true;
+ }
+
+ virtual void
+ GetName(nsAString& aName, ErrorResult& aRv) const override;
+
+ virtual void
+ GetFullPath(nsAString& aFullPath, ErrorResult& aRv) const override;
+
+ virtual already_AddRefed<FileSystemDirectoryReader>
+ CreateReader();
+
+ void
+ GetFile(const Optional<nsAString>& aPath, const FileSystemFlags& aFlag,
+ const Optional<OwningNonNull<FileSystemEntryCallback>>& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback)
+ {
+ GetInternal(aPath.WasPassed() ? aPath.Value() : EmptyString(),
+ aFlag, aSuccessCallback, aErrorCallback, eGetFile);
+ }
+
+ void
+ GetDirectory(const Optional<nsAString>& aPath, const FileSystemFlags& aFlag,
+ const Optional<OwningNonNull<FileSystemEntryCallback>>& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback)
+ {
+ GetInternal(aPath.WasPassed() ? aPath.Value() : EmptyString(),
+ aFlag, aSuccessCallback, aErrorCallback, eGetDirectory);
+ }
+
+ enum GetInternalType { eGetFile, eGetDirectory };
+
+ virtual void
+ GetInternal(const nsAString& aPath, const FileSystemFlags& aFlag,
+ const Optional<OwningNonNull<FileSystemEntryCallback>>& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ GetInternalType aType);
+
+protected:
+ virtual ~FileSystemDirectoryEntry();
+
+private:
+ RefPtr<Directory> mDirectory;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_FileSystemDirectoryEntry_h
diff --git a/dom/filesystem/compat/FileSystemDirectoryReader.cpp b/dom/filesystem/compat/FileSystemDirectoryReader.cpp
new file mode 100644
index 000000000..137437378
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemDirectoryReader.cpp
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileSystemDirectoryReader.h"
+#include "CallbackRunnables.h"
+#include "FileSystemFileEntry.h"
+#include "mozilla/dom/FileBinding.h"
+#include "mozilla/dom/Directory.h"
+#include "mozilla/dom/DirectoryBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/PromiseNativeHandler.h"
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+
+class PromiseHandler final : public PromiseNativeHandler
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ PromiseHandler(FileSystemDirectoryEntry* aParentEntry,
+ FileSystem* aFileSystem,
+ FileSystemEntriesCallback* aSuccessCallback,
+ ErrorCallback* aErrorCallback)
+ : mParentEntry(aParentEntry)
+ , mFileSystem(aFileSystem)
+ , mSuccessCallback(aSuccessCallback)
+ , mErrorCallback(aErrorCallback)
+ {
+ MOZ_ASSERT(aParentEntry);
+ MOZ_ASSERT(aFileSystem);
+ MOZ_ASSERT(aSuccessCallback);
+ }
+
+ virtual void
+ ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
+ {
+ if(NS_WARN_IF(!aValue.isObject())) {
+ return;
+ }
+
+ JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
+
+ uint32_t length;
+ if (NS_WARN_IF(!JS_GetArrayLength(aCx, obj, &length))) {
+ return;
+ }
+
+ Sequence<OwningNonNull<FileSystemEntry>> sequence;
+ if (NS_WARN_IF(!sequence.SetLength(length, fallible))) {
+ return;
+ }
+
+ for (uint32_t i = 0; i < length; ++i) {
+ JS::Rooted<JS::Value> value(aCx);
+ if (NS_WARN_IF(!JS_GetElement(aCx, obj, i, &value))) {
+ return;
+ }
+
+ if(NS_WARN_IF(!value.isObject())) {
+ return;
+ }
+
+ JS::Rooted<JSObject*> valueObj(aCx, &value.toObject());
+
+ RefPtr<File> file;
+ if (NS_SUCCEEDED(UNWRAP_OBJECT(File, valueObj, file))) {
+ RefPtr<FileSystemFileEntry> entry =
+ new FileSystemFileEntry(mParentEntry->GetParentObject(), file,
+ mParentEntry, mFileSystem);
+ sequence[i] = entry;
+ continue;
+ }
+
+ RefPtr<Directory> directory;
+ if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Directory, valueObj,
+ directory)))) {
+ return;
+ }
+
+ RefPtr<FileSystemDirectoryEntry> entry =
+ new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory,
+ mParentEntry, mFileSystem);
+ sequence[i] = entry;
+ }
+
+ mSuccessCallback->HandleEvent(sequence);
+ }
+
+ virtual void
+ RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
+ {
+ if (mErrorCallback) {
+ RefPtr<ErrorCallbackRunnable> runnable =
+ new ErrorCallbackRunnable(mParentEntry->GetParentObject(),
+ mErrorCallback,
+ NS_ERROR_DOM_INVALID_STATE_ERR);
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+ }
+ }
+
+private:
+ ~PromiseHandler() {}
+
+ RefPtr<FileSystemDirectoryEntry> mParentEntry;
+ RefPtr<FileSystem> mFileSystem;
+ RefPtr<FileSystemEntriesCallback> mSuccessCallback;
+ RefPtr<ErrorCallback> mErrorCallback;
+};
+
+NS_IMPL_ISUPPORTS0(PromiseHandler);
+
+} // anonymous namespace
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileSystemDirectoryReader, mParentEntry,
+ mDirectory, mFileSystem)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FileSystemDirectoryReader)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FileSystemDirectoryReader)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemDirectoryReader)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+FileSystemDirectoryReader::FileSystemDirectoryReader(FileSystemDirectoryEntry* aParentEntry,
+ FileSystem* aFileSystem,
+ Directory* aDirectory)
+ : mParentEntry(aParentEntry)
+ , mFileSystem(aFileSystem)
+ , mDirectory(aDirectory)
+ , mAlreadyRead(false)
+{
+ MOZ_ASSERT(aParentEntry);
+ MOZ_ASSERT(aFileSystem);
+}
+
+FileSystemDirectoryReader::~FileSystemDirectoryReader()
+{}
+
+JSObject*
+FileSystemDirectoryReader::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto)
+{
+ return FileSystemDirectoryReaderBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+FileSystemDirectoryReader::ReadEntries(FileSystemEntriesCallback& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ ErrorResult& aRv)
+{
+ MOZ_ASSERT(mDirectory);
+
+ if (mAlreadyRead) {
+ RefPtr<EmptyEntriesCallbackRunnable> runnable =
+ new EmptyEntriesCallbackRunnable(&aSuccessCallback);
+ aRv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed");
+ return;
+ }
+
+ // This object can be used only once.
+ mAlreadyRead = true;
+
+ ErrorResult rv;
+ RefPtr<Promise> promise = mDirectory->GetFilesAndDirectories(rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ rv.StealNSResult());
+ return;
+ }
+
+ RefPtr<PromiseHandler> handler =
+ new PromiseHandler(mParentEntry, mFileSystem, &aSuccessCallback,
+ aErrorCallback.WasPassed()
+ ? &aErrorCallback.Value() : nullptr);
+ promise->AppendNativeHandler(handler);
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/filesystem/compat/FileSystemDirectoryReader.h b/dom/filesystem/compat/FileSystemDirectoryReader.h
new file mode 100644
index 000000000..391a79329
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemDirectoryReader.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FileSystemDirectoryReader_h
+#define mozilla_dom_FileSystemDirectoryReader_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/FileSystemDirectoryEntry.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class Directory;
+class FileSystem;
+class FileSystemEntriesCallback;
+
+class FileSystemDirectoryReader
+ : public nsISupports
+ , public nsWrapperCache
+{
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FileSystemDirectoryReader)
+
+ explicit FileSystemDirectoryReader(FileSystemDirectoryEntry* aDirectoryEntry,
+ FileSystem* aFileSystem,
+ Directory* aDirectory);
+
+ nsIGlobalObject*
+ GetParentObject() const
+ {
+ return mParentEntry->GetParentObject();
+ }
+
+ virtual JSObject*
+ WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ virtual void
+ ReadEntries(FileSystemEntriesCallback& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ ErrorResult& aRv);
+
+protected:
+ virtual ~FileSystemDirectoryReader();
+
+private:
+ RefPtr<FileSystemDirectoryEntry> mParentEntry;
+ RefPtr<FileSystem> mFileSystem;
+ RefPtr<Directory> mDirectory;
+
+ bool mAlreadyRead;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_FileSystemDirectoryReader_h
diff --git a/dom/filesystem/compat/FileSystemEntry.cpp b/dom/filesystem/compat/FileSystemEntry.cpp
new file mode 100644
index 000000000..638c2c6db
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemEntry.cpp
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileSystemEntry.h"
+#include "FileSystemDirectoryEntry.h"
+#include "FileSystemFileEntry.h"
+#include "mozilla/dom/FileSystemEntryBinding.h"
+#include "mozilla/dom/UnionTypes.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileSystemEntry, mParent, mParentEntry,
+ mFileSystem)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(FileSystemEntry)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(FileSystemEntry)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemEntry)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/* static */ already_AddRefed<FileSystemEntry>
+FileSystemEntry::Create(nsIGlobalObject* aGlobalObject,
+ const OwningFileOrDirectory& aFileOrDirectory,
+ FileSystem* aFileSystem)
+{
+ MOZ_ASSERT(aGlobalObject);
+ MOZ_ASSERT(aFileSystem);
+
+ RefPtr<FileSystemEntry> entry;
+ if (aFileOrDirectory.IsFile()) {
+ entry = new FileSystemFileEntry(aGlobalObject,
+ aFileOrDirectory.GetAsFile(),
+ nullptr,
+ aFileSystem);
+ } else {
+ MOZ_ASSERT(aFileOrDirectory.IsDirectory());
+ entry = new FileSystemDirectoryEntry(aGlobalObject,
+ aFileOrDirectory.GetAsDirectory(),
+ nullptr,
+ aFileSystem);
+ }
+
+ return entry.forget();
+}
+
+FileSystemEntry::FileSystemEntry(nsIGlobalObject* aGlobal,
+ FileSystemEntry* aParentEntry,
+ FileSystem* aFileSystem)
+ : mParent(aGlobal)
+ , mParentEntry(aParentEntry)
+ , mFileSystem(aFileSystem)
+{
+ MOZ_ASSERT(aGlobal);
+ MOZ_ASSERT(aFileSystem);
+}
+
+FileSystemEntry::~FileSystemEntry()
+{}
+
+JSObject*
+FileSystemEntry::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return FileSystemEntryBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+FileSystemEntry::GetParent(const Optional<OwningNonNull<FileSystemEntryCallback>>& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback)
+{
+ if (!aSuccessCallback.WasPassed() && !aErrorCallback.WasPassed()) {
+ return;
+ }
+
+ if (mParentEntry) {
+ FileSystemEntryCallbackHelper::Call(aSuccessCallback, mParentEntry);
+ return;
+ }
+
+ FileSystemEntryCallbackHelper::Call(aSuccessCallback, this);
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/filesystem/compat/FileSystemEntry.h b/dom/filesystem/compat/FileSystemEntry.h
new file mode 100644
index 000000000..769fb8f3f
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemEntry.h
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FileSystemEntry_h
+#define mozilla_dom_FileSystemEntry_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/FileSystemBinding.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsIGlobalObject.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class FileSystem;
+class OwningFileOrDirectory;
+
+class FileSystemEntry
+ : public nsISupports
+ , public nsWrapperCache
+{
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FileSystemEntry)
+
+ static already_AddRefed<FileSystemEntry>
+ Create(nsIGlobalObject* aGlobalObject,
+ const OwningFileOrDirectory& aFileOrDirectory,
+ FileSystem* aFileSystem);
+
+ nsIGlobalObject*
+ GetParentObject() const
+ {
+ return mParent;
+ }
+
+ virtual JSObject*
+ WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ virtual bool
+ IsFile() const
+ {
+ return false;
+ }
+
+ virtual bool
+ IsDirectory() const
+ {
+ return false;
+ }
+
+ virtual void
+ GetName(nsAString& aName, ErrorResult& aRv) const = 0;
+
+ virtual void
+ GetFullPath(nsAString& aFullPath, ErrorResult& aRv) const = 0;
+
+ void
+ GetParent(const Optional<OwningNonNull<FileSystemEntryCallback>>& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback);
+
+ FileSystem*
+ Filesystem() const
+ {
+ return mFileSystem;
+ }
+
+protected:
+ FileSystemEntry(nsIGlobalObject* aGlobalObject,
+ FileSystemEntry* aParentEntry,
+ FileSystem* aFileSystem);
+ virtual ~FileSystemEntry();
+
+private:
+ nsCOMPtr<nsIGlobalObject> mParent;
+ RefPtr<FileSystemEntry> mParentEntry;
+ RefPtr<FileSystem> mFileSystem;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_FileSystemEntry_h
diff --git a/dom/filesystem/compat/FileSystemFileEntry.cpp b/dom/filesystem/compat/FileSystemFileEntry.cpp
new file mode 100644
index 000000000..6302df06d
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemFileEntry.cpp
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileSystemFileEntry.h"
+#include "CallbackRunnables.h"
+#include "mozilla/dom/File.h"
+#include "mozilla/dom/MultipartBlobImpl.h"
+#include "mozilla/dom/FileSystemFileEntryBinding.h"
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+
+class FileCallbackRunnable final : public Runnable
+{
+public:
+ FileCallbackRunnable(FileCallback* aCallback, ErrorCallback* aErrorCallback,
+ File* aFile)
+ : mCallback(aCallback)
+ , mErrorCallback(aErrorCallback)
+ , mFile(aFile)
+ {
+ MOZ_ASSERT(aCallback);
+ MOZ_ASSERT(aFile);
+ }
+
+ NS_IMETHOD
+ Run() override
+ {
+ // Here we clone the File object.
+
+ nsAutoString name;
+ mFile->GetName(name);
+
+ nsAutoString type;
+ mFile->GetType(type);
+
+ nsTArray<RefPtr<BlobImpl>> blobImpls;
+ blobImpls.AppendElement(mFile->Impl());
+
+ ErrorResult rv;
+ RefPtr<BlobImpl> blobImpl =
+ MultipartBlobImpl::Create(Move(blobImpls), name, type, rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ if (mErrorCallback) {
+ RefPtr<DOMException> exception =
+ DOMException::Create(rv.StealNSResult());
+ mErrorCallback->HandleEvent(*exception);
+ }
+
+ return NS_OK;
+ }
+
+ RefPtr<File> file = File::Create(mFile->GetParentObject(), blobImpl);
+ MOZ_ASSERT(file);
+
+ mCallback->HandleEvent(*file);
+ return NS_OK;
+ }
+
+private:
+ RefPtr<FileCallback> mCallback;
+ RefPtr<ErrorCallback> mErrorCallback;
+ RefPtr<File> mFile;
+};
+
+} // anonymous namespace
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemFileEntry, FileSystemEntry, mFile)
+
+NS_IMPL_ADDREF_INHERITED(FileSystemFileEntry, FileSystemEntry)
+NS_IMPL_RELEASE_INHERITED(FileSystemFileEntry, FileSystemEntry)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileSystemFileEntry)
+NS_INTERFACE_MAP_END_INHERITING(FileSystemEntry)
+
+FileSystemFileEntry::FileSystemFileEntry(nsIGlobalObject* aGlobal,
+ File* aFile,
+ FileSystemDirectoryEntry* aParentEntry,
+ FileSystem* aFileSystem)
+ : FileSystemEntry(aGlobal, aParentEntry, aFileSystem)
+ , mFile(aFile)
+{
+ MOZ_ASSERT(aGlobal);
+ MOZ_ASSERT(mFile);
+}
+
+FileSystemFileEntry::~FileSystemFileEntry()
+{}
+
+JSObject*
+FileSystemFileEntry::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto)
+{
+ return FileSystemFileEntryBinding::Wrap(aCx, this, aGivenProto);
+}
+
+void
+FileSystemFileEntry::GetName(nsAString& aName, ErrorResult& aRv) const
+{
+ mFile->GetName(aName);
+}
+
+void
+FileSystemFileEntry::GetFullPath(nsAString& aPath, ErrorResult& aRv) const
+{
+ mFile->Impl()->GetDOMPath(aPath);
+ if (aPath.IsEmpty()) {
+ // We're under the root directory. webkitRelativePath
+ // (implemented as GetPath) is for cases when file is selected because its
+ // ancestor directory is selected. But that is not the case here, so need to
+ // manually prepend '/'.
+ nsAutoString name;
+ mFile->GetName(name);
+ aPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+ aPath.Append(name);
+ }
+}
+
+void
+FileSystemFileEntry::GetFile(FileCallback& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback) const
+{
+ RefPtr<FileCallbackRunnable> runnable =
+ new FileCallbackRunnable(&aSuccessCallback,
+ aErrorCallback.WasPassed()
+ ? &aErrorCallback.Value() : nullptr,
+ mFile);
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/filesystem/compat/FileSystemFileEntry.h b/dom/filesystem/compat/FileSystemFileEntry.h
new file mode 100644
index 000000000..06b76e9f8
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemFileEntry.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FileSystemFileEntry_h
+#define mozilla_dom_FileSystemFileEntry_h
+
+#include "mozilla/dom/FileSystemEntry.h"
+
+namespace mozilla {
+namespace dom {
+
+class File;
+class FileCallback;
+class FileSystemDirectoryEntry;
+
+class FileSystemFileEntry final : public FileSystemEntry
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileSystemFileEntry, FileSystemEntry)
+
+ FileSystemFileEntry(nsIGlobalObject* aGlobalObject, File* aFile,
+ FileSystemDirectoryEntry* aParentEntry,
+ FileSystem* aFileSystem);
+
+ virtual JSObject*
+ WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+ virtual bool
+ IsFile() const override
+ {
+ return true;
+ }
+
+ virtual void
+ GetName(nsAString& aName, ErrorResult& aRv) const override;
+
+ virtual void
+ GetFullPath(nsAString& aFullPath, ErrorResult& aRv) const override;
+
+ void
+ GetFile(FileCallback& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback) const;
+
+private:
+ ~FileSystemFileEntry();
+
+ RefPtr<File> mFile;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_FileSystemFileEntry_h
diff --git a/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp b/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp
new file mode 100644
index 000000000..68ce62aa2
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileSystemRootDirectoryEntry.h"
+#include "FileSystemRootDirectoryReader.h"
+#include "mozilla/dom/FileSystemUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemRootDirectoryEntry,
+ FileSystemDirectoryEntry, mEntries)
+
+NS_IMPL_ADDREF_INHERITED(FileSystemRootDirectoryEntry, FileSystemDirectoryEntry)
+NS_IMPL_RELEASE_INHERITED(FileSystemRootDirectoryEntry, FileSystemDirectoryEntry)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileSystemRootDirectoryEntry)
+NS_INTERFACE_MAP_END_INHERITING(FileSystemDirectoryEntry)
+
+FileSystemRootDirectoryEntry::FileSystemRootDirectoryEntry(nsIGlobalObject* aGlobal,
+ const Sequence<RefPtr<FileSystemEntry>>& aEntries,
+ FileSystem* aFileSystem)
+ : FileSystemDirectoryEntry(aGlobal, nullptr, nullptr, aFileSystem)
+ , mEntries(aEntries)
+{
+ MOZ_ASSERT(aGlobal);
+}
+
+FileSystemRootDirectoryEntry::~FileSystemRootDirectoryEntry()
+{}
+
+void
+FileSystemRootDirectoryEntry::GetName(nsAString& aName, ErrorResult& aRv) const
+{
+ aName.Truncate();
+}
+
+void
+FileSystemRootDirectoryEntry::GetFullPath(nsAString& aPath, ErrorResult& aRv) const
+{
+ aPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+}
+
+already_AddRefed<FileSystemDirectoryReader>
+FileSystemRootDirectoryEntry::CreateReader()
+{
+ RefPtr<FileSystemDirectoryReader> reader =
+ new FileSystemRootDirectoryReader(this, Filesystem(), mEntries);
+ return reader.forget();
+}
+
+void
+FileSystemRootDirectoryEntry::GetInternal(const nsAString& aPath,
+ const FileSystemFlags& aFlag,
+ const Optional<OwningNonNull<FileSystemEntryCallback>>& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ GetInternalType aType)
+{
+ if (!aSuccessCallback.WasPassed() && !aErrorCallback.WasPassed()) {
+ return;
+ }
+
+ if (aFlag.mCreate) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ NS_ERROR_DOM_SECURITY_ERR);
+ return;
+ }
+
+ nsTArray<nsString> parts;
+ if (!FileSystemUtils::IsValidRelativeDOMPath(aPath, parts)) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ NS_ERROR_DOM_NOT_FOUND_ERR);
+ return;
+ }
+
+ MOZ_ASSERT(!parts.IsEmpty());
+
+ RefPtr<FileSystemEntry> entry;
+ for (uint32_t i = 0; i < mEntries.Length(); ++i) {
+ ErrorResult rv;
+ nsAutoString name;
+ mEntries[i]->GetName(name, rv);
+
+ if (NS_WARN_IF(rv.Failed())) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ rv.StealNSResult());
+ return;
+ }
+
+ if (name == parts[0]) {
+ entry = mEntries[i];
+ break;
+ }
+ }
+
+ // Not found.
+ if (!entry) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ NS_ERROR_DOM_NOT_FOUND_ERR);
+ return;
+ }
+
+ // No subdirectory in the path.
+ if (parts.Length() == 1) {
+ if ((entry->IsFile() && aType == eGetDirectory) ||
+ (entry->IsDirectory() && aType == eGetFile)) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ NS_ERROR_DOM_TYPE_MISMATCH_ERR);
+ return;
+ }
+
+ if (aSuccessCallback.WasPassed()) {
+ RefPtr<EntryCallbackRunnable> runnable =
+ new EntryCallbackRunnable(&aSuccessCallback.Value(), entry);
+ DebugOnly<nsresult> rv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed");
+ }
+ return;
+ }
+
+ // Subdirectories, but this is a file.
+ if (entry->IsFile()) {
+ ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback,
+ NS_ERROR_DOM_NOT_FOUND_ERR);
+ return;
+ }
+
+ // Let's recreate a path without the first directory.
+ nsAutoString path;
+ for (uint32_t i = 1, len = parts.Length(); i < len; ++i) {
+ path.Append(parts[i]);
+ if (i < len - 1) {
+ path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+ }
+ }
+
+ auto* directoryEntry = static_cast<FileSystemDirectoryEntry*>(entry.get());
+ directoryEntry->GetInternal(path, aFlag, aSuccessCallback, aErrorCallback,
+ aType);
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/filesystem/compat/FileSystemRootDirectoryEntry.h b/dom/filesystem/compat/FileSystemRootDirectoryEntry.h
new file mode 100644
index 000000000..28c151ea2
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemRootDirectoryEntry.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FileSystemRootDirectoryEntry_h
+#define mozilla_dom_FileSystemRootDirectoryEntry_h
+
+#include "mozilla/dom/FileSystemDirectoryEntry.h"
+
+namespace mozilla {
+namespace dom {
+
+class FileSystemRootDirectoryEntry final : public FileSystemDirectoryEntry
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileSystemRootDirectoryEntry, FileSystemDirectoryEntry)
+
+ FileSystemRootDirectoryEntry(nsIGlobalObject* aGlobalObject,
+ const Sequence<RefPtr<FileSystemEntry>>& aEntries,
+ FileSystem* aFileSystem);
+
+ virtual void
+ GetName(nsAString& aName, ErrorResult& aRv) const override;
+
+ virtual void
+ GetFullPath(nsAString& aFullPath, ErrorResult& aRv) const override;
+
+ virtual already_AddRefed<FileSystemDirectoryReader>
+ CreateReader() override;
+
+private:
+ ~FileSystemRootDirectoryEntry();
+
+ virtual void
+ GetInternal(const nsAString& aPath, const FileSystemFlags& aFlag,
+ const Optional<OwningNonNull<FileSystemEntryCallback>>& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ GetInternalType aType) override;
+
+ void
+ Error(const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ nsresult aError) const;
+
+ Sequence<RefPtr<FileSystemEntry>> mEntries;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_FileSystemRootDirectoryEntry_h
diff --git a/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp b/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp
new file mode 100644
index 000000000..5b4a41752
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "FileSystemRootDirectoryReader.h"
+#include "CallbackRunnables.h"
+#include "nsIGlobalObject.h"
+
+namespace mozilla {
+namespace dom {
+
+namespace {
+
+class EntriesCallbackRunnable final : public Runnable
+{
+public:
+ EntriesCallbackRunnable(FileSystemEntriesCallback* aCallback,
+ const Sequence<RefPtr<FileSystemEntry>>& aEntries)
+ : mCallback(aCallback)
+ , mEntries(aEntries)
+ {
+ MOZ_ASSERT(aCallback);
+ }
+
+ NS_IMETHOD
+ Run() override
+ {
+ Sequence<OwningNonNull<FileSystemEntry>> entries;
+ for (uint32_t i = 0; i < mEntries.Length(); ++i) {
+ if (!entries.AppendElement(mEntries[i].forget(), fallible)) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ mCallback->HandleEvent(entries);
+ return NS_OK;
+ }
+
+private:
+ RefPtr<FileSystemEntriesCallback> mCallback;
+ Sequence<RefPtr<FileSystemEntry>> mEntries;
+};
+
+} // anonymous namespace
+
+NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemRootDirectoryReader,
+ FileSystemDirectoryReader, mEntries)
+
+NS_IMPL_ADDREF_INHERITED(FileSystemRootDirectoryReader,
+ FileSystemDirectoryReader)
+NS_IMPL_RELEASE_INHERITED(FileSystemRootDirectoryReader,
+ FileSystemDirectoryReader)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FileSystemRootDirectoryReader)
+NS_INTERFACE_MAP_END_INHERITING(FileSystemDirectoryReader)
+
+FileSystemRootDirectoryReader::FileSystemRootDirectoryReader(FileSystemDirectoryEntry* aParentEntry,
+ FileSystem* aFileSystem,
+ const Sequence<RefPtr<FileSystemEntry>>& aEntries)
+ : FileSystemDirectoryReader(aParentEntry, aFileSystem, nullptr)
+ , mEntries(aEntries)
+ , mAlreadyRead(false)
+{
+ MOZ_ASSERT(aParentEntry);
+ MOZ_ASSERT(aFileSystem);
+}
+
+FileSystemRootDirectoryReader::~FileSystemRootDirectoryReader()
+{}
+
+void
+FileSystemRootDirectoryReader::ReadEntries(FileSystemEntriesCallback& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ ErrorResult& aRv)
+{
+ if (mAlreadyRead) {
+ RefPtr<EmptyEntriesCallbackRunnable> runnable =
+ new EmptyEntriesCallbackRunnable(&aSuccessCallback);
+ aRv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed");
+ return;
+ }
+
+ // This object can be used only once.
+ mAlreadyRead = true;
+
+ RefPtr<EntriesCallbackRunnable> runnable =
+ new EntriesCallbackRunnable(&aSuccessCallback, mEntries);
+ aRv = NS_DispatchToMainThread(runnable);
+ NS_WARNING_ASSERTION(!aRv.Failed(), "NS_DispatchToMainThread failed");
+}
+
+} // dom namespace
+} // mozilla namespace
diff --git a/dom/filesystem/compat/FileSystemRootDirectoryReader.h b/dom/filesystem/compat/FileSystemRootDirectoryReader.h
new file mode 100644
index 000000000..54bca7726
--- /dev/null
+++ b/dom/filesystem/compat/FileSystemRootDirectoryReader.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_FileSystemRootDirectoryReader_h
+#define mozilla_dom_FileSystemRootDirectoryReader_h
+
+#include "FileSystemDirectoryReader.h"
+
+namespace mozilla {
+namespace dom {
+
+class FileSystemRootDirectoryReader final : public FileSystemDirectoryReader
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileSystemRootDirectoryReader,
+ FileSystemDirectoryReader)
+
+ explicit FileSystemRootDirectoryReader(FileSystemDirectoryEntry* aParentEntry,
+ FileSystem* aFileSystem,
+ const Sequence<RefPtr<FileSystemEntry>>& aEntries);
+
+ virtual void
+ ReadEntries(FileSystemEntriesCallback& aSuccessCallback,
+ const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback,
+ ErrorResult& aRv) override;
+
+private:
+ ~FileSystemRootDirectoryReader();
+
+ Sequence<RefPtr<FileSystemEntry>> mEntries;
+ bool mAlreadyRead;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_FileSystemRootDirectoryReader_h
diff --git a/dom/filesystem/compat/moz.build b/dom/filesystem/compat/moz.build
new file mode 100644
index 000000000..fc3f9482f
--- /dev/null
+++ b/dom/filesystem/compat/moz.build
@@ -0,0 +1,30 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+TEST_DIRS += ['tests']
+
+EXPORTS.mozilla.dom += [
+ 'FileSystem.h',
+ 'FileSystemDirectoryEntry.h',
+ 'FileSystemDirectoryReader.h',
+ 'FileSystemEntry.h',
+ 'FileSystemFileEntry.h',
+]
+
+UNIFIED_SOURCES += [
+ 'CallbackRunnables.cpp',
+ 'FileSystem.cpp',
+ 'FileSystemDirectoryEntry.cpp',
+ 'FileSystemDirectoryReader.cpp',
+ 'FileSystemEntry.cpp',
+ 'FileSystemFileEntry.cpp',
+ 'FileSystemRootDirectoryEntry.cpp',
+ 'FileSystemRootDirectoryReader.cpp',
+]
+
+FINAL_LIBRARY = 'xul'
+
+include('/ipc/chromium/chromium-config.mozbuild')
diff --git a/dom/filesystem/compat/tests/mochitest.ini b/dom/filesystem/compat/tests/mochitest.ini
new file mode 100644
index 000000000..2b6eafb55
--- /dev/null
+++ b/dom/filesystem/compat/tests/mochitest.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+support-files =
+ script_entries.js
+ !/dom/html/test/form_submit_server.sjs
+
+[test_basic.html]
+[test_no_dnd.html]
+[test_formSubmission.html]
diff --git a/dom/filesystem/compat/tests/moz.build b/dom/filesystem/compat/tests/moz.build
new file mode 100644
index 000000000..3b13ba431
--- /dev/null
+++ b/dom/filesystem/compat/tests/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_MANIFESTS += ['mochitest.ini']
diff --git a/dom/filesystem/compat/tests/script_entries.js b/dom/filesystem/compat/tests/script_entries.js
new file mode 100644
index 000000000..8083214c9
--- /dev/null
+++ b/dom/filesystem/compat/tests/script_entries.js
@@ -0,0 +1,47 @@
+var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+Cu.importGlobalProperties(["File", "Directory"]);
+
+var tmpFile, tmpDir;
+
+addMessageListener("entries.open", function (e) {
+ tmpFile = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIDirectoryService)
+ .QueryInterface(Ci.nsIProperties)
+ .get('TmpD', Ci.nsIFile)
+ tmpFile.append('file.txt');
+ tmpFile.createUnique(Components.interfaces.nsIFile.FILE_TYPE, 0o600);
+
+ tmpDir = Cc["@mozilla.org/file/directory_service;1"]
+ .getService(Ci.nsIDirectoryService)
+ .QueryInterface(Ci.nsIProperties)
+ .get('TmpD', Ci.nsIFile)
+
+ tmpDir.append('dir-test');
+ tmpDir.createUnique(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
+
+ var file1 = tmpDir.clone();
+ file1.append('foo.txt');
+ file1.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
+
+ var dir1 = tmpDir.clone();
+ dir1.append('subdir');
+ dir1.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
+
+ var file2 = dir1.clone();
+ file2.append('bar..txt'); // Note the double ..
+ file2.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0o600);
+
+ var dir2 = dir1.clone();
+ dir2.append('subsubdir');
+ dir2.create(Components.interfaces.nsIFile.DIRECTORY_TYPE, 0o700);
+
+ sendAsyncMessage("entries.opened", {
+ data: [ new Directory(tmpDir.path), File.createFromNsIFile(tmpFile) ]
+ });
+});
+
+addMessageListener("entries.delete", function(e) {
+ tmpFile.remove(true);
+ tmpDir.remove(true);
+ sendAsyncMessage("entries.deleted");
+});
diff --git a/dom/filesystem/compat/tests/test_basic.html b/dom/filesystem/compat/tests/test_basic.html
new file mode 100644
index 000000000..85a7418d5
--- /dev/null
+++ b/dom/filesystem/compat/tests/test_basic.html
@@ -0,0 +1,494 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Blink FileSystem API - subset</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<input id="entries" type="file"></input>
+<script type="application/javascript;version=1.7">
+
+var fileEntry;
+var directoryEntry;
+var script;
+
+function setup_tests() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.webkitBlink.dirPicker.enabled", true],
+ ["dom.filesystem.pathcheck.disabled", true],
+ ["dom.webkitBlink.filesystem.enabled", true]]}, next);
+}
+
+function populate_entries() {
+ var url = SimpleTest.getTestFileURL("script_entries.js");
+ script = SpecialPowers.loadChromeScript(url);
+
+ function onOpened(message) {
+ var entries = document.getElementById('entries');
+ SpecialPowers.wrap(entries).mozSetDndFilesAndDirectories(message.data);
+ next();
+ }
+
+ script.addMessageListener("entries.opened", onOpened);
+ script.sendAsyncMessage("entries.open");
+}
+
+function test_entries() {
+ var entries = document.getElementById('entries');
+ ok("webkitEntries" in entries, "HTMLInputElement.webkitEntries");
+ is(entries.webkitEntries.length, 2, "HTMLInputElement.webkitEntries.length == 2");
+ is(entries.files.length, 1, "HTMLInputElement.files is still populated");
+
+ for (var i = 0; i < entries.webkitEntries.length; ++i) {
+ if (entries.webkitEntries[i].isFile) {
+ ok(!fileEntry, "We just want 1 fileEntry");
+ fileEntry = entries.webkitEntries[i];
+ } else {
+ ok(entries.webkitEntries[i].isDirectory, "If not a file, we have a directory.");
+ ok(!directoryEntry, "We just want 1 directoryEntry");
+ directoryEntry = entries.webkitEntries[i];
+ }
+ }
+
+ next();
+}
+
+function test_fileEntry() {
+ ok("name" in fileEntry, "We have a name.");
+ ok("fullPath" in fileEntry, "We have a fullPath.");
+ ok("filesystem" in fileEntry, "We have a filesystem.");
+
+ next();
+}
+
+function test_fileEntry_file() {
+ fileEntry.file(function(file) {
+ ok(file, "We have a file here!");
+ is(file.name, fileEntry.name, "Same file name.");
+ next();
+ }, function() {
+ ok(false, "Something when wrong!");
+ });
+}
+
+function test_fileEntry_getParent() {
+ fileEntry.getParent(function(entry) {
+ is(fileEntry.fullPath, entry.fullPath, "Top level FileEntry should return itself as parent.");
+ next();
+ }, function() {
+ ok(false, "This is wrong.");
+ });
+}
+
+function test_directoryEntry() {
+ ok("name" in directoryEntry, "We have a name.");
+ ok("fullPath" in directoryEntry, "We have a fullPath.");
+ ok("filesystem" in directoryEntry, "We have a filesystem.");
+
+ next();
+}
+
+function test_directoryEntry_createReader() {
+ var reader = directoryEntry.createReader();
+ ok(reader, "We have a DirectoryReader");
+
+ reader.readEntries(function(a) {
+ ok(Array.isArray(a), "We want an array.");
+ is(a.length, 2, "reader.readyEntries returns 2 elements.");
+
+ for (var i = 0; i < 2; ++i) {
+ ok(a[i].name == "subdir" || a[i].name == "foo.txt", "Correct names");
+ is(a[i].fullPath, directoryEntry.fullPath + "/" + a[i].name, "FullPath is correct");
+ }
+
+ // Called twice:
+ reader.readEntries(function(a) {
+ ok(Array.isArray(a), "We want an array.");
+ is(a.length, 0, "reader.readyEntries returns 0 elements.");
+ next();
+ }, function() {
+ ok(false, "Something when wrong!");
+ });
+
+ }, function() {
+ ok(false, "Something when wrong!");
+ });
+}
+
+function test_directoryEntry_getParent() {
+ directoryEntry.getParent(function(entry) {
+ is(directoryEntry.fullPath, entry.fullPath, "Top level FileEntry should return itself as parent.");
+ next();
+ }, function() {
+ ok(false, "This is wrong.");
+ });
+}
+
+function test_directoryEntry_getFile_securityError() {
+ directoryEntry.getFile("foo", { create: true },
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "SecurityError", "This must generate a SecurityError.");
+ next();
+ });
+}
+
+function test_directoryEntry_getFile_typeMismatchError() {
+ directoryEntry.getFile("subdir", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "TypeMismatchError", "This must generate a TypeMismatchError.");
+ next();
+ });
+}
+
+function test_directoryEntry_getFile_nonValidPath() {
+ directoryEntry.getFile("../../", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "NotFoundError", "This must generate a NotFoundError.");
+ next();
+ });
+}
+
+function test_directoryEntry_getFile_nonExistingPath() {
+ directoryEntry.getFile("foo_bar.txt", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "NotFoundError", "This must generate a NotFoundError.");
+ next();
+ });
+}
+
+function test_directoryEntry_getFile_simple() {
+ directoryEntry.getFile("foo.txt", {},
+ function(e) {
+ is(e.name, "foo.txt", "We have the right FileEntry.");
+ test_getParent(e, directoryEntry, /* nested */ false);
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function test_directoryEntry_getFile_deep() {
+ directoryEntry.getFile("subdir/bar..txt", {},
+ function(e) {
+ is(e.name, "bar..txt", "We have the right FileEntry.");
+ test_getParent(e, directoryEntry, /* nested */ true);
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function test_directoryEntry_getDirectory_securityError() {
+ directoryEntry.getDirectory("foo", { create: true },
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "SecurityError", "This must generate a SecurityError.");
+ next();
+ });
+}
+
+function test_directoryEntry_getDirectory_typeMismatchError() {
+ directoryEntry.getDirectory("foo.txt", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "TypeMismatchError", "This must generate a TypeMismatchError.");
+ next();
+ });
+}
+
+function test_directoryEntry_getDirectory_nonValidPath() {
+ directoryEntry.getDirectory("../../", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "NotFoundError", "This must generate a NotFoundError.");
+ next();
+ });
+}
+
+function test_directoryEntry_getDirectory_nonExistingPath() {
+ directoryEntry.getDirectory("non_existing_dir", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "NotFoundError", "This must generate a NotFoundError.");
+ next();
+ });
+}
+
+function test_directoryEntry_getDirectory_simple() {
+ directoryEntry.getDirectory("subdir", {},
+ function(e) {
+ is(e.name, "subdir", "We have the right DirectoryEntry.");
+ test_getParent(e, directoryEntry, /* nested */ false);
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function test_directoryEntry_getDirectory_deep() {
+ directoryEntry.getDirectory("subdir/subsubdir", {},
+ function(e) {
+ is(e.name, "subsubdir", "We have the right DirectoryEntry.");
+ test_getParent(e, directoryEntry, /* nested */ true);
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function test_filesystem() {
+ is(fileEntry.filesystem, directoryEntry.filesystem, "FileSystem object is shared.");
+
+ var fs = fileEntry.filesystem;
+ ok(fs.name, "FileSystem.name exists.");
+ ok(fs.root, "FileSystem has a root.");
+
+ is(fs.root.name, "", "FileSystem.root.name must be an empty string.");
+ is(fs.root.fullPath, "/", "FileSystem.root.fullPath must be '/'");
+
+ reader = fs.root.createReader();
+ reader.readEntries(function(a) {
+ ok(Array.isArray(a), "We want an array.");
+ is(a.length, 2, "reader.readyEntries returns 2 elements.");
+ next();
+ }, function() {
+ ok(false, "Something when wrong!");
+ });
+}
+
+function test_root_getFile_securityError() {
+ fileEntry.filesystem.root.getFile("foo", { create: true },
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "SecurityError", "This must generate a SecurityError.");
+ next();
+ });
+}
+
+function test_root_getFile_typeMismatchError() {
+ fileEntry.filesystem.root.getFile(directoryEntry.name, {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "TypeMismatchError", "This must generate a TypeMismatchError.");
+ next();
+ });
+}
+
+function test_root_getFile_nonValidPath() {
+ fileEntry.filesystem.root.getFile("../../", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "NotFoundError", "This must generate a NotFoundError.");
+ next();
+ });
+}
+
+function test_root_getFile_nonExistingPath() {
+ fileEntry.filesystem.root.getFile("existing.txt", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "NotFoundError", "This must generate a NotFoundError.");
+ next();
+ });
+}
+
+function test_root_getFile_simple() {
+ fileEntry.filesystem.root.getFile(fileEntry.name, {},
+ function(e) {
+ is(e.name, fileEntry.name, "We have the right FileEntry.");
+ next();
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function test_root_getFile_deep() {
+ fileEntry.filesystem.root.getFile(directoryEntry.name + "/subdir/bar..txt", {},
+ function(e) {
+ is(e.name, "bar..txt", "We have the right FileEntry.");
+ next();
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function test_root_getDirectory_securityError() {
+ fileEntry.filesystem.root.getDirectory("foo", { create: true },
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "SecurityError", "This must generate a SecurityError.");
+ next();
+ });
+}
+
+function test_root_getDirectory_typeMismatchError() {
+ fileEntry.filesystem.root.getDirectory(fileEntry.name, {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "TypeMismatchError", "This must generate a TypeMismatchError.");
+ next();
+ });
+}
+
+function test_root_getDirectory_nonValidPath() {
+ fileEntry.filesystem.root.getDirectory("../../", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "NotFoundError", "This must generate a NotFoundError.");
+ next();
+ });
+}
+
+function test_root_getDirectory_nonExistingPath() {
+ fileEntry.filesystem.root.getDirectory("404", {},
+ function() {
+ ok(false, "This should not happen.");
+ }, function(e) {
+ is(e.name, "NotFoundError", "This must generate a NotFoundError.");
+ next();
+ });
+}
+
+function test_root_getDirectory_simple() {
+ fileEntry.filesystem.root.getDirectory(directoryEntry.name, {},
+ function(e) {
+ is(e.name, directoryEntry.name, "We have the right DirectoryEntry.");
+ next();
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function test_root_getDirectory_deep() {
+ fileEntry.filesystem.root.getDirectory(directoryEntry.name + "/subdir/subsubdir", {},
+ function(e) {
+ is(e.name, "subsubdir", "We have the right DirectoryEntry.");
+ next();
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function cleanUpTestingFiles() {
+ script.addMessageListener("entries.deleted", function onDeleted() {
+ script.removeMessageListener("entries.deleted");
+ script.destroy();
+ next();
+ });
+
+ script.sendAsyncMessage("entries.delete");
+}
+
+function test_getParent(entry, parentEntry, nested) {
+ entry.getParent(function(e) {
+ ok(e, "We have a parent Entry.");
+ if (!nested) {
+ is (e, parentEntry, "Parent entry matches");
+ next();
+ } else {
+ test_getParent(e, parentEntry, false);
+ }
+ }, function(e) {
+ ok(false, "This should not happen.");
+ });
+}
+
+function test_webkitRelativePath() {
+ fileEntry.file(function(file1) {
+ ok(file1, "We have a file here!");
+ ok(!file1.webkitRelativePath, "webkitRelativePath is an empty string");
+
+ fileEntry.file(function(file2) {
+ ok(file2, "We have a file here!");
+ ok(!file2.webkitRelativePath, "webkitRelativePath is an empty string");
+ isnot(file1, file2, "The 2 files are not the same");
+
+ next();
+ }, function() {
+ ok(false, "Something when wrong!");
+ });
+ }, function() {
+ ok(false, "Something when wrong!");
+ });
+}
+
+var tests = [
+ setup_tests,
+ populate_entries,
+
+ test_entries,
+
+ test_fileEntry,
+ test_fileEntry_file,
+ test_fileEntry_getParent,
+
+ test_directoryEntry,
+ test_directoryEntry_createReader,
+ test_directoryEntry_getParent,
+
+ test_directoryEntry_getFile_securityError,
+ test_directoryEntry_getFile_typeMismatchError,
+ test_directoryEntry_getFile_nonValidPath,
+ test_directoryEntry_getFile_nonExistingPath,
+ test_directoryEntry_getFile_simple,
+ test_directoryEntry_getFile_deep,
+
+ test_directoryEntry_getDirectory_securityError,
+ test_directoryEntry_getDirectory_typeMismatchError,
+ test_directoryEntry_getDirectory_nonValidPath,
+ test_directoryEntry_getDirectory_nonExistingPath,
+ test_directoryEntry_getDirectory_simple,
+ test_directoryEntry_getDirectory_deep,
+
+ test_filesystem,
+
+ test_root_getFile_securityError,
+ test_root_getFile_typeMismatchError,
+ test_root_getFile_nonValidPath,
+ test_root_getFile_nonExistingPath,
+ test_root_getFile_simple,
+ test_root_getFile_deep,
+
+ test_root_getDirectory_securityError,
+ test_root_getDirectory_typeMismatchError,
+ test_root_getDirectory_nonValidPath,
+ test_root_getDirectory_nonExistingPath,
+ test_root_getDirectory_simple,
+ test_root_getDirectory_deep,
+
+ test_webkitRelativePath,
+
+ cleanUpTestingFiles,
+];
+
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+next();
+</script>
+</body>
+</html>
diff --git a/dom/filesystem/compat/tests/test_formSubmission.html b/dom/filesystem/compat/tests/test_formSubmission.html
new file mode 100644
index 000000000..0c04b8bf1
--- /dev/null
+++ b/dom/filesystem/compat/tests/test_formSubmission.html
@@ -0,0 +1,267 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Directory form submission</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
+</head>
+<body onload="return next();">
+
+<iframe name="target_iframe" id="target_iframe"></iframe>
+
+<form action="../../../html/test/form_submit_server.sjs" target="target_iframe" id="form"
+ method="POST" enctype="multipart/form-data">
+</form>
+
+<script class="testbody" type="text/javascript;version=1.8">
+
+var form;
+var iframe;
+var input;
+var xhr;
+
+function setup_tests() {
+ form = document.getElementById("form");
+
+ iframe = document.getElementById("target_iframe");
+ iframe.onload = function() {
+ info("Frame loaded!");
+ next();
+ }
+
+ SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true],
+ ["dom.webkitBlink.dirPicker.enabled", true],
+ ["dom.filesystem.pathcheck.disabled", true],
+ ["dom.webkitBlink.filesystem.enabled", true]]}, next);
+}
+
+function populate_entries(webkitDirectory) {
+ if (input) {
+ form.removeChild(input);
+ }
+
+ input = document.createElement('input');
+ input.setAttribute('id', 'input');
+ input.setAttribute('type', 'file');
+ input.setAttribute('name', 'input');
+
+ if (webkitDirectory) {
+ input.setAttribute('webkitdirectory', 'true');
+ }
+
+ form.appendChild(input);
+
+ var url = SimpleTest.getTestFileURL("script_entries.js");
+ var script = SpecialPowers.loadChromeScript(url);
+
+ function onOpened(message) {
+ input.addEventListener("change", function onChange() {
+ input.removeEventListener("change", onChange);
+ next();
+ });
+
+ SpecialPowers.wrap(input).mozSetDndFilesAndDirectories([message.data[0]]);
+ script.destroy();
+ }
+
+ script.addMessageListener("entries.opened", onOpened);
+ script.sendAsyncMessage("entries.open");
+}
+
+function setup_plain() {
+ info("Preparing for a plain text submission...");
+ form.action = "../../../html/test/form_submit_server.sjs?plain";
+ form.method = "POST";
+ form.enctype = "text/plain";
+ form.submit();
+}
+
+function test_plain() {
+ var content = iframe.contentDocument.documentElement.textContent;
+ var submission = JSON.parse(content);
+ input.getFilesAndDirectories().then(function(array) {
+ is(submission, array.map(function(v) {
+ return "input=" + v.name + "\r\n";
+ }).join(""), "Data match");
+
+ next();
+ });
+}
+
+function setup_urlencoded() {
+ info("Preparing for a urlencoded submission...");
+ form.action = "../../../html/test/form_submit_server.sjs?url";
+ form.method = "POST";
+ form.enctype = "application/x-www-form-urlencoded";
+ form.submit();
+}
+
+function setup_urlencoded_get() {
+ info("Preparing for a urlencoded+GET submission...");
+ form.action = "../../../html/test/form_submit_server.sjs?xxyy";
+ form.method = "GET";
+ form.enctype = "";
+ form.submit();
+}
+
+function setup_urlencoded_empty() {
+ info("Preparing for a urlencoded+default values submission...");
+ form.action = "../../../html/test/form_submit_server.sjs";
+ form.method = "";
+ form.enctype = "";
+ form.submit();
+}
+
+function test_urlencoded() {
+ var content = iframe.contentDocument.documentElement.textContent;
+ var submission = JSON.parse(content);
+ input.getFilesAndDirectories().then(function(array) {
+ is(submission, array.map(function(v) {
+ return "input=" + v.name;
+ }).join("&"), "Data match");
+
+ next();
+ });
+}
+
+function setup_formData() {
+ info("Preparing for a fromData submission...");
+
+ xhr = new XMLHttpRequest();
+ xhr.onload = next;
+ xhr.open("POST", "../../../html/test/form_submit_server.sjs");
+ xhr.send(new FormData(form));
+}
+
+function test_multipart() {
+ var submission = JSON.parse(xhr.responseText);
+ input.getFilesAndDirectories().then(function(array) {
+ is(submission.length, array.length, "Same length");
+
+ for (var i = 0; i < array.length; ++i) {
+ if (array[i] instanceof Directory) {
+ is(submission[i].headers["Content-Disposition"],
+ "form-data; name=\"input\"; filename=\"/" + array[i].name + "\"",
+ "Correct Content-Disposition");
+ is(submission[i].headers["Content-Type"], "application/octet-stream",
+ "Correct Content-Type");
+ is(submission[i].body, "", "Correct body");
+ } else {
+ ok(array[i] instanceof File);
+ is(submission[i].headers["Content-Disposition"],
+ "form-data; name=\"input\"; filename=\"" + array[i].name + "\"",
+ "Correct Content-Disposition");
+ is(submission[i].headers["Content-Type"], array[i].type,
+ "Correct Content-Type");
+ is(submission[i].body, "", "Correct body");
+ }
+ }
+ next();
+ });
+}
+
+function test_webkit_plain() {
+ var content = iframe.contentDocument.documentElement.textContent;
+ var submission = JSON.parse(content);
+
+ input.getFiles(true).then(function(array) {
+ is(submission, array.map(function(v) {
+ return "input=" + v.name + "\r\n";
+ }).join(""), "Data match");
+
+ next();
+ });
+}
+
+function test_webkit_urlencoded() {
+ var content = iframe.contentDocument.documentElement.textContent;
+ var submission = JSON.parse(content);
+ input.getFiles(true).then(function(array) {
+ is(submission, array.map(function(v) {
+ return "input=" + v.name;
+ }).join("&"), "Data match");
+
+ next();
+ });
+}
+
+function test_webkit_multipart() {
+ var submission = JSON.parse(xhr.responseText);
+ input.getFiles(true).then(function(array) {
+ is(submission.length, array.length, "Same length");
+
+ for (var i = 0; i < array.length; ++i) {
+ if (array[i] instanceof Directory) {
+ is(submission[i].headers["Content-Disposition"],
+ "form-data; name=\"input\"; filename=\"/" + array[i].name + "\"",
+ "Correct Content-Disposition");
+ is(submission[i].headers["Content-Type"], "application/octet-stream",
+ "Correct Content-Type");
+ is(submission[i].body, "", "Correct body");
+ } else {
+ ok(array[i] instanceof File);
+ is(submission[i].headers["Content-Disposition"],
+ "form-data; name=\"input\"; filename=\"" + array[i].webkitRelativePath + "\"",
+ "Correct Content-Disposition");
+ is(submission[i].headers["Content-Type"], array[i].type,
+ "Correct Content-Type");
+ is(submission[i].body, "", "Correct body");
+ }
+ }
+ next();
+ });
+}
+
+var tests = [
+ setup_tests,
+ function() { populate_entries(false); },
+
+ setup_plain,
+ test_plain,
+
+ setup_urlencoded,
+ test_urlencoded,
+
+ setup_urlencoded_get,
+ test_urlencoded,
+
+ setup_urlencoded_empty,
+ test_urlencoded,
+
+ setup_formData,
+ test_multipart,
+
+ function() { populate_entries(true); },
+
+ setup_plain,
+ test_webkit_plain,
+
+ setup_urlencoded,
+ test_webkit_urlencoded,
+
+ setup_urlencoded_get,
+ test_webkit_urlencoded,
+
+ setup_urlencoded_empty,
+ test_webkit_urlencoded,
+
+ setup_formData,
+ test_webkit_multipart,
+];
+
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+
+</script>
+</body>
+</html>
diff --git a/dom/filesystem/compat/tests/test_no_dnd.html b/dom/filesystem/compat/tests/test_no_dnd.html
new file mode 100644
index 000000000..a78ac108f
--- /dev/null
+++ b/dom/filesystem/compat/tests/test_no_dnd.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for Blink FileSystem API - no DND == no webkitEntries</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<script type="application/javascript;version=1.7">
+
+var fileEntry;
+var directoryEntry;
+var script;
+var entries;
+
+function setup_tests() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.webkitBlink.dirPicker.enabled", true],
+ ["dom.filesystem.pathcheck.disabled", true],
+ ["dom.webkitBlink.filesystem.enabled", true]]}, next);
+}
+
+function populate_entries() {
+ entries = document.createElement('input');
+ entries.setAttribute('type', 'file');
+ document.body.appendChild(entries);
+
+ var url = SimpleTest.getTestFileURL("script_entries.js");
+ script = SpecialPowers.loadChromeScript(url);
+
+ function onOpened(message) {
+ for (var i = 0 ; i < message.data.length; ++i) {
+ if (message.data[i] instanceof File) {
+ SpecialPowers.wrap(entries).mozSetFileArray([message.data[i]]);
+ next();
+ }
+ }
+ }
+
+ script.addMessageListener("entries.opened", onOpened);
+ script.sendAsyncMessage("entries.open");
+}
+
+function test_entries() {
+ ok("webkitEntries" in entries, "HTMLInputElement.webkitEntries");
+ is(entries.webkitEntries.length, 0, "HTMLInputElement.webkitEntries.length == 0");
+ is(entries.files.length, 1, "HTMLInputElement.files is still populated");
+
+ next();
+}
+
+function cleanUpTestingFiles() {
+ script.addMessageListener("entries.deleted", function onDeleted() {
+ script.removeMessageListener("entries.deleted");
+ script.destroy();
+ next();
+ });
+
+ script.sendAsyncMessage("entries.delete");
+}
+
+var tests = [
+ setup_tests,
+ populate_entries,
+
+ test_entries,
+
+ cleanUpTestingFiles,
+];
+
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+next();
+</script>
+</body>
+</html>