Bug 1336091 - File.relativeWebkitPath should not start with '/', r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Mon, 06 Feb 2017 11:07:54 +0100
changeset 340871 4ef7edd52783b92a265d79de5889b5508543fff1
parent 340870 a5fc021fd3f57e941469c8d92387e880dbbfb771
child 340872 b7f8236613d805aafb25c083b0af3efaa5fdf6aa
push id86578
push useramarchesini@mozilla.com
push dateMon, 06 Feb 2017 10:08:06 +0000
treeherdermozilla-inbound@4ef7edd52783 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1336091
milestone54.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 1336091 - File.relativeWebkitPath should not start with '/', r=smaug
dom/file/File.cpp
dom/file/File.h
dom/file/ipc/Blob.cpp
dom/file/moz.build
dom/filesystem/GetDirectoryListingTask.cpp
dom/filesystem/GetFilesHelper.cpp
dom/filesystem/compat/FileSystemFileEntry.cpp
dom/filesystem/compat/tests/test_basic.html
dom/filesystem/tests/filesystem_commons.js
dom/html/HTMLFormSubmission.cpp
dom/indexedDB/FileSnapshot.h
dom/webidl/File.webidl
--- a/dom/file/File.cpp
+++ b/dom/file/File.cpp
@@ -31,16 +31,17 @@
 #include "nsPrintfCString.h"
 #include "mozilla/SHA1.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/FileBinding.h"
+#include "mozilla/dom/FileSystemUtils.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRunnable.h"
 #include "nsThreadUtils.h"
 #include "nsStreamUtils.h"
 #include "SlicedInputStream.h"
 
 namespace mozilla {
 namespace dom {
@@ -465,25 +466,28 @@ File::WrapObject(JSContext* aCx, JS::Han
 
 void
 File::GetName(nsAString& aFileName) const
 {
   mImpl->GetName(aFileName);
 }
 
 void
-File::GetPath(nsAString& aPath) const
+File::GetRelativePath(nsAString& aPath) const
 {
-  mImpl->GetPath(aPath);
-}
+  aPath.Truncate();
 
-void
-File::SetPath(const nsAString& aPath)
-{
-  mImpl->SetPath(aPath);
+  nsAutoString path;
+  mImpl->GetDOMPath(path);
+
+  // WebkitRelativePath doesn't start with '/'
+  if (!path.IsEmpty()) {
+    MOZ_ASSERT(path[0] == FILESYSTEM_DOM_PATH_SEPARATOR_CHAR);
+    aPath.Assign(Substring(path, 1));
+  }
 }
 
 Date
 File::GetLastModifiedDate(ErrorResult& aRv)
 {
   int64_t value = GetLastModified(aRv);
   if (aRv.Failed()) {
     return Date();
@@ -665,24 +669,24 @@ NS_IMPL_ISUPPORTS_INHERITED0(BlobImplFil
 void
 BlobImplBase::GetName(nsAString& aName) const
 {
   MOZ_ASSERT(mIsFile, "Should only be called on files");
   aName = mName;
 }
 
 void
-BlobImplBase::GetPath(nsAString& aPath) const
+BlobImplBase::GetDOMPath(nsAString& aPath) const
 {
   MOZ_ASSERT(mIsFile, "Should only be called on files");
   aPath = mPath;
 }
 
 void
-BlobImplBase::SetPath(const nsAString& aPath)
+BlobImplBase::SetDOMPath(const nsAString& aPath)
 {
   MOZ_ASSERT(mIsFile, "Should only be called on files");
   mPath = aPath;
 }
 
 void
 BlobImplBase::GetMozFullPath(nsAString& aFileName,
                              SystemCallerGuarantee /* unused */,
--- a/dom/file/File.h
+++ b/dom/file/File.h
@@ -220,23 +220,17 @@ public:
                     ErrorResult& aRv);
 
   void GetName(nsAString& aName) const;
 
   int64_t GetLastModified(ErrorResult& aRv);
 
   Date GetLastModifiedDate(ErrorResult& aRv);
 
-  // GetPath and SetPath are currently used only for the webkitRelativePath
-  // attribute and they are only used when this File object is created from a
-  // Directory, generated by a Directory Picker.
-
-  void GetPath(nsAString& aName) const;
-
-  void SetPath(const nsAString& aName);
+  void GetRelativePath(nsAString& aPath) const;
 
   void GetMozFullPath(nsAString& aFilename, SystemCallerGuarantee aGuarantee,
                       ErrorResult& aRv) const;
 
   void GetMozFullPathInternal(nsAString& aName, ErrorResult& aRv) const;
 
 protected:
   virtual bool HasFileInterface() const override { return true; }
@@ -255,19 +249,19 @@ class BlobImpl : public nsISupports
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(BLOBIMPL_IID)
   NS_DECL_THREADSAFE_ISUPPORTS
 
   BlobImpl() {}
 
   virtual void GetName(nsAString& aName) const = 0;
 
-  virtual void GetPath(nsAString& aName) const = 0;
+  virtual void GetDOMPath(nsAString& aName) const = 0;
 
-  virtual void SetPath(const nsAString& aName) = 0;
+  virtual void SetDOMPath(const nsAString& aName) = 0;
 
   virtual int64_t GetLastModified(ErrorResult& aRv) = 0;
 
   virtual void SetLastModified(int64_t aLastModified) = 0;
 
   virtual void GetMozFullPath(nsAString& aName,
                               SystemCallerGuarantee /* unused */,
                               ErrorResult& aRv) const = 0;
@@ -401,19 +395,19 @@ public:
   {
     MOZ_ASSERT(aLength != UINT64_MAX, "Must know length when creating slice");
     // Ensure non-null mContentType by default
     mContentType.SetIsVoid(false);
   }
 
   virtual void GetName(nsAString& aName) const override;
 
-  virtual void GetPath(nsAString& aName) const override;
+  virtual void GetDOMPath(nsAString& aName) const override;
 
-  virtual void SetPath(const nsAString& aName) override;
+  virtual void SetDOMPath(const nsAString& aName) override;
 
   virtual int64_t GetLastModified(ErrorResult& aRv) override;
 
   virtual void SetLastModified(int64_t aLastModified) override;
 
   virtual void GetMozFullPath(nsAString& aName,
                               SystemCallerGuarantee /* unused */,
                               ErrorResult& aRv) const override;
--- a/dom/file/ipc/Blob.cpp
+++ b/dom/file/ipc/Blob.cpp
@@ -2066,20 +2066,20 @@ public:
   NoteDyingActor();
 
   NS_DECL_ISUPPORTS_INHERITED
 
   void
   GetName(nsAString& aName) const override;
 
   void
-  GetPath(nsAString& aPath) const override;
+  GetDOMPath(nsAString& aPath) const override;
 
   void
-  SetPath(const nsAString& aPath) override;
+  SetDOMPath(const nsAString& aPath) override;
 
   int64_t
   GetLastModified(ErrorResult& aRv) override;
 
   void
   SetLastModified(int64_t aLastModified) override;
 
   void
@@ -2170,27 +2170,27 @@ private:
  * BlobChild::RemoteBlobImpl
  ******************************************************************************/
 
 BlobChild::
 RemoteBlobImpl::RemoteBlobImpl(BlobChild* aActor,
                                BlobImpl* aRemoteBlobImpl,
                                const nsAString& aName,
                                const nsAString& aContentType,
-                               const nsAString& aPath,
+                               const nsAString& aDOMPath,
                                uint64_t aLength,
                                int64_t aModDate,
                                BlobImplIsDirectory aIsDirectory,
                                bool aIsSameProcessBlob)
   : BlobImplBase(aName, aContentType, aLength, aModDate)
   , mWorkerPrivate(nullptr)
   , mMutex("BlobChild::RemoteBlobImpl::mMutex")
   , mIsSlice(false), mIsDirectory(aIsDirectory == eDirectory)
 {
-  SetPath(aPath);
+  SetDOMPath(aDOMPath);
 
   if (aIsSameProcessBlob) {
     MOZ_ASSERT(aRemoteBlobImpl);
     mSameProcessBlobImpl = aRemoteBlobImpl;
     MOZ_ASSERT(gProcessType == GeckoProcessType_Default);
   } else {
     mDifferentProcessBlobImpl = aRemoteBlobImpl;
   }
@@ -2838,26 +2838,26 @@ void
 BlobParent::
 RemoteBlobImpl::GetName(nsAString& aName) const
 {
   mBlobImpl->GetName(aName);
 }
 
 void
 BlobParent::
-RemoteBlobImpl::GetPath(nsAString& aPath) const
+RemoteBlobImpl::GetDOMPath(nsAString& aPath) const
 {
-  mBlobImpl->GetPath(aPath);
+  mBlobImpl->GetDOMPath(aPath);
 }
 
 void
 BlobParent::
-RemoteBlobImpl::SetPath(const nsAString& aPath)
+RemoteBlobImpl::SetDOMPath(const nsAString& aPath)
 {
-  mBlobImpl->SetPath(aPath);
+  mBlobImpl->SetDOMPath(aPath);
 }
 
 int64_t
 BlobParent::
 RemoteBlobImpl::GetLastModified(ErrorResult& aRv)
 {
   return mBlobImpl->GetLastModified(aRv);
 }
@@ -3191,28 +3191,28 @@ BlobChild::CommonInit(BlobChild* aOther,
   uint64_t length = otherImpl->GetSize(rv);
   MOZ_ASSERT(!rv.Failed());
 
   RemoteBlobImpl* remoteBlob = nullptr;
   if (otherImpl->IsFile()) {
     nsAutoString name;
     otherImpl->GetName(name);
 
-    nsAutoString path;
-    otherImpl->GetPath(path);
+    nsAutoString domPath;
+    otherImpl->GetDOMPath(domPath);
 
     int64_t modDate = otherImpl->GetLastModified(rv);
     MOZ_ASSERT(!rv.Failed());
 
     RemoteBlobImpl::BlobImplIsDirectory directory = otherImpl->IsDirectory() ?
       RemoteBlobImpl::BlobImplIsDirectory::eDirectory :
       RemoteBlobImpl::BlobImplIsDirectory::eNotDirectory;
 
     remoteBlob =
-      new RemoteBlobImpl(this, otherImpl, name, contentType, path,
+      new RemoteBlobImpl(this, otherImpl, name, contentType, domPath,
                          length, modDate, directory,
                          false /* SameProcessBlobImpl */);
   } else {
     remoteBlob = new RemoteBlobImpl(this, otherImpl, contentType, length,
                                     false /* SameProcessBlobImpl */);
   }
 
   // This RemoteBlob must be kept alive untill RecvCreatedFromKnownBlob is
@@ -3286,33 +3286,33 @@ BlobChild::CommonInit(const ChildBlobCon
 
       nsString contentType;
       blobImpl->GetType(contentType);
 
       if (blobImpl->IsFile()) {
         nsAutoString name;
         blobImpl->GetName(name);
 
-        nsAutoString path;
-        blobImpl->GetPath(path);
+        nsAutoString domPath;
+        blobImpl->GetDOMPath(domPath);
 
         int64_t lastModifiedDate = blobImpl->GetLastModified(rv);
         MOZ_ASSERT(!rv.Failed());
 
         RemoteBlobImpl::BlobImplIsDirectory directory =
           blobImpl->IsDirectory() ?
             RemoteBlobImpl::BlobImplIsDirectory::eDirectory :
             RemoteBlobImpl::BlobImplIsDirectory::eNotDirectory;
 
         remoteBlob =
           new RemoteBlobImpl(this,
                              blobImpl,
                              name,
                              contentType,
-                             path,
+                             domPath,
                              size,
                              lastModifiedDate,
                              directory,
                              true /* SameProcessBlobImpl */);
       } else {
         remoteBlob = new RemoteBlobImpl(this, blobImpl, contentType, size,
                                         true /* SameProcessBlobImpl */);
       }
@@ -3485,24 +3485,24 @@ BlobChild::GetOrCreateFromImpl(ChildMana
     ErrorResult rv;
     uint64_t length = aBlobImpl->GetSize(rv);
     MOZ_ASSERT(!rv.Failed());
 
     if (aBlobImpl->IsFile()) {
       nsAutoString name;
       aBlobImpl->GetName(name);
 
-      nsAutoString path;
-      aBlobImpl->GetPath(path);
+      nsAutoString domPath;
+      aBlobImpl->GetDOMPath(domPath);
 
       int64_t modDate = aBlobImpl->GetLastModified(rv);
       MOZ_ASSERT(!rv.Failed());
 
       blobParams =
-        FileBlobConstructorParams(name, contentType, path, length, modDate,
+        FileBlobConstructorParams(name, contentType, domPath, length, modDate,
                                   aBlobImpl->IsDirectory(), blobData);
     } else {
       blobParams = NormalBlobConstructorParams(contentType, length, blobData);
     }
   }
 
   auto* actor = new BlobChild(aManager, aBlobImpl);
 
@@ -4038,24 +4038,24 @@ BlobParent::GetOrCreateFromImpl(ParentMa
       ErrorResult rv;
       uint64_t length = aBlobImpl->GetSize(rv);
       MOZ_ASSERT(!rv.Failed());
 
       if (aBlobImpl->IsFile()) {
         nsAutoString name;
         aBlobImpl->GetName(name);
 
-        nsAutoString path;
-        aBlobImpl->GetPath(path);
+        nsAutoString domPath;
+        aBlobImpl->GetDOMPath(domPath);
 
         int64_t modDate = aBlobImpl->GetLastModified(rv);
         MOZ_ASSERT(!rv.Failed());
 
         blobParams =
-          FileBlobConstructorParams(name, contentType, path, length, modDate,
+          FileBlobConstructorParams(name, contentType, domPath, length, modDate,
                                     aBlobImpl->IsDirectory(), void_t());
       } else {
         blobParams = NormalBlobConstructorParams(contentType, length, void_t());
       }
     }
   }
 
   nsID id;
--- a/dom/file/moz.build
+++ b/dom/file/moz.build
@@ -18,16 +18,17 @@ EXPORTS += [
     'nsHostObjectURI.h',
 ]
 
 EXPORTS.mozilla.dom += [
     'BlobSet.h',
     'File.h',
     'FileList.h',
     'FileReader.h',
+    'MultipartBlobImpl.h',
     'MutableBlobStorage.h',
     'MutableBlobStreamListener.h',
 ]
 
 UNIFIED_SOURCES += [
     'BlobSet.cpp',
     'File.cpp',
     'FileList.cpp',
--- a/dom/filesystem/GetDirectoryListingTask.cpp
+++ b/dom/filesystem/GetDirectoryListingTask.cpp
@@ -247,17 +247,17 @@ GetDirectoryListingTaskParent::GetSucces
       // This is specific for unix root filesystem.
       if (!mDOMPath.EqualsLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL)) {
         filePath.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
       }
 
       nsAutoString name;
       blobImpl->GetName(name);
       filePath.Append(name);
-      blobImpl->SetPath(filePath);
+      blobImpl->SetDOMPath(filePath);
 
       fileData.blobParent() =
         BlobParent::GetOrCreate(mRequestParent->Manager(), blobImpl);
       inputs.AppendElement(fileData);
     } else {
       MOZ_ASSERT(mTargetData[i].mType == FileOrDirectoryPath::eDirectoryPath);
       FileSystemDirectoryListingResponseDirectory directoryData;
       directoryData.directoryRealPath() = mTargetData[i].mPath;
--- a/dom/filesystem/GetFilesHelper.cpp
+++ b/dom/filesystem/GetFilesHelper.cpp
@@ -272,27 +272,27 @@ GetFilesHelper::RunIO()
   MOZ_ASSERT(!mListingCompleted);
 
   nsCOMPtr<nsIFile> file;
   mErrorResult = NS_NewLocalFile(mDirectoryPath, true, getter_AddRefs(file));
   if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
     return;
   }
 
-  nsAutoString path;
-  mErrorResult = file->GetLeafName(path);
+  nsAutoString leafName;
+  mErrorResult = file->GetLeafName(leafName);
   if (NS_WARN_IF(NS_FAILED(mErrorResult))) {
     return;
   }
 
-  if (path.IsEmpty()) {
-    path.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
-  }
+  nsAutoString domPath;
+  domPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
+  domPath.Append(leafName);
 
-  mErrorResult = ExploreDirectory(path, file);
+  mErrorResult = ExploreDirectory(domPath, file);
 }
 
 void
 GetFilesHelper::RunMainThread()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mDirectoryPath.IsEmpty());
   MOZ_ASSERT(!mListingCompleted);
@@ -379,17 +379,17 @@ GetFilesHelperBase::ExploreDirectory(con
     nsAutoString leafName;
     if (NS_WARN_IF(NS_FAILED(currFile->GetLeafName(leafName)))) {
       continue;
     }
     domPath.Append(leafName);
 
     if (isFile) {
       RefPtr<BlobImpl> blobImpl = new BlobImplFile(currFile);
-      blobImpl->SetPath(domPath);
+      blobImpl->SetDOMPath(domPath);
 
       if (!mTargetBlobImplArray.AppendElement(blobImpl, fallible)) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
 
       continue;
     }
 
--- a/dom/filesystem/compat/FileSystemFileEntry.cpp
+++ b/dom/filesystem/compat/FileSystemFileEntry.cpp
@@ -2,43 +2,74 @@
 /* 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, File* aFile)
+  FileCallbackRunnable(FileCallback* aCallback, ErrorCallback* aErrorCallback,
+                       File* aFile)
     : mCallback(aCallback)
+    , mErrorCallback(aErrorCallback)
     , mFile(aFile)
   {
     MOZ_ASSERT(aCallback);
     MOZ_ASSERT(aFile);
   }
 
   NS_IMETHOD
   Run() override
   {
-    mCallback->HandleEvent(*mFile);
+    // 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)
@@ -72,17 +103,17 @@ void
 FileSystemFileEntry::GetName(nsAString& aName, ErrorResult& aRv) const
 {
   mFile->GetName(aName);
 }
 
 void
 FileSystemFileEntry::GetFullPath(nsAString& aPath, ErrorResult& aRv) const
 {
-  mFile->GetPath(aPath);
+  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);
@@ -90,15 +121,18 @@ FileSystemFileEntry::GetFullPath(nsAStri
   }
 }
 
 void
 FileSystemFileEntry::GetFile(FileCallback& aSuccessCallback,
                              const Optional<OwningNonNull<ErrorCallback>>& aErrorCallback) const
 {
   RefPtr<FileCallbackRunnable> runnable =
-    new FileCallbackRunnable(&aSuccessCallback, mFile);
+    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
--- a/dom/filesystem/compat/tests/test_basic.html
+++ b/dom/filesystem/compat/tests/test_basic.html
@@ -403,16 +403,35 @@ function test_getParent(entry, parentEnt
     } 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,
@@ -447,16 +466,18 @@ var tests = [
 
   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;
   }
--- a/dom/filesystem/tests/filesystem_commons.js
+++ b/dom/filesystem/tests/filesystem_commons.js
@@ -1,12 +1,18 @@
 function createPath(parentDir, dirOrFile) {
   return parentDir.path + (parentDir.path == '/' ? '' : '/') + dirOrFile.name;
 }
 
+function createRelativePath(parentDir, dirOrFile) {
+  let path = createPath(parentDir, dirOrFile);
+  is(path[0], "/", "The full path should start with '/'");
+  return path.substring(1);
+}
+
 function setup_tests(aNext) {
   SimpleTest.requestLongerTimeout(2);
   SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true],
                                      ["dom.webkitBlink.dirPicker.enabled", true]]}, aNext);
 }
 
 function test_basic(aDirectory, aNext) {
   ok(aDirectory, "Directory exists.");
@@ -24,17 +30,17 @@ function test_getFilesAndDirectories(aDi
           if (data[i] instanceof Directory) {
             isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
             isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
             isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
             is(data[i].path, createPath(dir, data[i]), "Subdirectory path should be called parentdir.path + '/' + leafname: " + data[i].path);
           }
 
           if (data[i] instanceof File) {
-            is(data[i].webkitRelativePath, createPath(dir, data[i]), "File.webkitRelativePath should be called: parentdir.path + '/' + file.name: " + data[i].webkitRelativePath);
+            is(data[i].webkitRelativePath, createRelativePath(dir, data[i]), "File.webkitRelativePath should be called: parentdir.path + '/' + file.name: " + data[i].webkitRelativePath);
           }
         }
       }
     );
   }
 
   aDirectory.getFilesAndDirectories().then(
     function(data) {
@@ -46,34 +52,35 @@ function test_getFilesAndDirectories(aDi
           isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
           is(data[i].path, createPath(aDirectory, data[i]), "Subdirectory path should be called parentdir.path + '/' + leafname: " + data[i].path);
           if (aRecursive) {
             promises.push(checkSubDir(data[i]));
           }
         }
 
         if (data[i] instanceof File) {
-          is(data[i].webkitRelativePath, createPath(aDirectory, data[i]), "File.webkitRelativePath should be called '/' + file.name: " + data[i].webkitRelativePath);
+          is(data[i].webkitRelativePath, createRelativePath(aDirectory, data[i]), "File.webkitRelativePath should be called file.name: " + data[i].webkitRelativePath);
         }
       }
 
       return Promise.all(promises);
     },
     function() {
       ok(false, "Something when wrong");
     }
   ).then(aNext);
 }
 
 function test_getFiles(aDirectory, aRecursive, aNext) {
   aDirectory.getFiles(aRecursive).then(
     function(data) {
       for (var i = 0; i < data.length; ++i) {
         ok(data[i] instanceof File, "File: " + data[i].name);
-        ok(data[i].webkitRelativePath.indexOf(aDirectory.path) == 0 &&
+        is(aDirectory.path[0], '/', "Directory path must start with '/'");
+        ok(data[i].webkitRelativePath.indexOf(aDirectory.path.substring(1)) == 0 &&
            data[i].webkitRelativePath.indexOf('/' + data[i].name) + ('/' + data[i].name).length == data[i].webkitRelativePath.length,
            "File.webkitRelativePath should be called dir.path + '/' + file.name: " + data[i].webkitRelativePath);
       }
     },
     function() {
       ok(false, "Something when wrong");
     }
   ).then(aNext);
--- a/dom/html/HTMLFormSubmission.cpp
+++ b/dom/html/HTMLFormSubmission.cpp
@@ -506,21 +506,21 @@ FSMultipartFormData::AddNameBlobOrNullPa
   nsAutoCString contentType;
   nsCOMPtr<nsIInputStream> fileStream;
 
   if (aBlob) {
     nsAutoString filename16;
 
     RefPtr<File> file = aBlob->ToFile();
     if (file) {
-      nsAutoString path;
-      file->GetPath(path);
+      nsAutoString relativePath;
+      file->GetRelativePath(relativePath);
       if (Directory::WebkitBlinkDirectoryPickerEnabled(nullptr, nullptr) &&
-          !path.IsEmpty()) {
-        filename16 = path;
+          !relativePath.IsEmpty()) {
+        filename16 = relativePath;
       }
 
       if (filename16.IsEmpty()) {
         RetrieveFileName(aBlob, filename16);
       }
     }
 
     rv = EncodeVal(filename16, filename, true);
--- a/dom/indexedDB/FileSnapshot.h
+++ b/dom/indexedDB/FileSnapshot.h
@@ -55,25 +55,25 @@ private:
   // BlobImpl
   virtual void
   GetName(nsAString& aName) const override
   {
     mBlobImpl->GetName(aName);
   }
 
   virtual void
-  GetPath(nsAString& aPath) const override
+  GetDOMPath(nsAString& aPath) const override
   {
-    mBlobImpl->GetPath(aPath);
+    mBlobImpl->GetDOMPath(aPath);
   }
 
   virtual void
-  SetPath(const nsAString& aPath) override
+  SetDOMPath(const nsAString& aPath) override
   {
-    mBlobImpl->SetPath(aPath);
+    mBlobImpl->SetDOMPath(aPath);
   }
 
   virtual int64_t
   GetLastModified(ErrorResult& aRv) override
   {
     return mBlobImpl->GetLastModified(aRv);
   }
 
--- a/dom/webidl/File.webidl
+++ b/dom/webidl/File.webidl
@@ -28,17 +28,17 @@ dictionary ChromeFilePropertyBag : FileP
   DOMString name = "";
 };
 
 // Mozilla extensions
 partial interface File {
   [GetterThrows, Deprecated="FileLastModifiedDate"]
   readonly attribute Date lastModifiedDate;
 
-  [BinaryName="path", Func="mozilla::dom::Directory::WebkitBlinkDirectoryPickerEnabled"]
+  [BinaryName="relativePath", Func="mozilla::dom::Directory::WebkitBlinkDirectoryPickerEnabled"]
   readonly attribute USVString webkitRelativePath;
 
   [GetterThrows, ChromeOnly, NeedsCallerType]
   readonly attribute DOMString mozFullPath;
 
   [ChromeOnly, Throws, NeedsCallerType]
   static File createFromNsIFile(nsIFile file,
                                 optional ChromeFilePropertyBag options);