FileSystemEntry API should ignore hidden files
authorcdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Sep 2017 22:53:59 +0000 (22:53 +0000)
committercdumez@apple.com <cdumez@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Sep 2017 22:53:59 +0000 (22:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=176292
<rdar://problem/34257666>

Reviewed by Andreas Kling.

Source/WebCore:

FileSystemEntry API should ignore hidden files as the user likely does not mean
to expose those when drag'n dropping a folder.

Test: editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file.html

* Modules/entriesapi/DOMFileSystem.cpp:
(WebCore::listDirectoryWithMetadata):
(WebCore::validatePathIsExpectedType):
(WebCore::fileType):
(WebCore::DOMFileSystem::getEntry):

LayoutTests:

Add layout test coverage.

* editing/pasteboard/enties-api/datatransfer-items-drop-getAsEntry-expected.txt:
* editing/pasteboard/enties-api/datatransfer-items-drop-getAsEntry.html:
* editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file-expected.txt: Added.
* editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file.html: Added.
* fast/forms/file/entries-api/resources/testFiles/.hidden.txt: Added.
* fast/forms/file/entries-api/resources/testFiles/.hidden/hidden.txt: Added.
* platform/win/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@221639 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/editing/pasteboard/enties-api/datatransfer-items-drop-getAsEntry-expected.txt
LayoutTests/editing/pasteboard/enties-api/datatransfer-items-drop-getAsEntry.html
LayoutTests/editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file.html [new file with mode: 0644]
LayoutTests/fast/forms/file/entries-api/resources/testFiles/.hidden.txt [new file with mode: 0644]
LayoutTests/fast/forms/file/entries-api/resources/testFiles/.hidden/hidden.txt [new file with mode: 0644]
LayoutTests/platform/win/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Modules/entriesapi/DOMFileSystem.cpp

index b201727..ccdcf73 100644 (file)
@@ -1,3 +1,21 @@
+2017-09-05  Chris Dumez  <cdumez@apple.com>
+
+        FileSystemEntry API should ignore hidden files
+        https://bugs.webkit.org/show_bug.cgi?id=176292
+        <rdar://problem/34257666>
+
+        Reviewed by Andreas Kling.
+
+        Add layout test coverage.
+
+        * editing/pasteboard/enties-api/datatransfer-items-drop-getAsEntry-expected.txt:
+        * editing/pasteboard/enties-api/datatransfer-items-drop-getAsEntry.html:
+        * editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file-expected.txt: Added.
+        * editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file.html: Added.
+        * fast/forms/file/entries-api/resources/testFiles/.hidden.txt: Added.
+        * fast/forms/file/entries-api/resources/testFiles/.hidden/hidden.txt: Added.
+        * platform/win/TestExpectations:
+
 2017-09-05  Matt Lewis  <jlewis3@apple.com>
 
         Marked svg/as-image/svg-image-with-data-uri-background.html as flaky.
index 6b68de0..769ea39 100644 (file)
@@ -16,7 +16,7 @@ PASS firstEntry.fullPath is "/test.txt"
 PASS secondDataTransferItem.kind is "file"
 PASS secondDataTransferItem.type is ""
 PASS secondFile.name is "testFiles"
-PASS secondFile.size is 204
+PASS secondFile.size is 272
 PASS secondFile.type is ""
 PASS secondEntry.isDirectory is true
 PASS secondEntry.isFile is false
index 218b352..4fba698 100644 (file)
@@ -37,7 +37,7 @@ dropzone.ondrop = function(e) {
     shouldBeEqualToString("secondDataTransferItem.type", "");
     secondFile = secondDataTransferItem.getAsFile();
     shouldBeEqualToString("secondFile.name", "testFiles");
-    shouldBe("secondFile.size", "204"); // Chrome returns folder size, Firefox returns 0.
+    shouldBe("secondFile.size", "272"); // Chrome returns folder size, Firefox returns 0.
     shouldBeEqualToString("secondFile.type", "");
 
     secondEntry = secondDataTransferItem.webkitGetAsEntry();
diff --git a/LayoutTests/editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file-expected.txt b/LayoutTests/editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file-expected.txt
new file mode 100644 (file)
index 0000000..93c55ca
--- /dev/null
@@ -0,0 +1,16 @@
+Test that hidden files are not exposed via Entries API
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS dataTransfer.items.length is 1
+PASS directoryEntry.name is "testFiles"
+PASS directoryEntry.fullPath is "/testFiles"
+PASS directoryEntry.isDirectory is true
+PASS foundEntries.length is 4
+PASS ex.name is "NotFoundError"
+PASS ex.name is "NotFoundError"
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file.html b/LayoutTests/editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file.html
new file mode 100644 (file)
index 0000000..f163b6d
--- /dev/null
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+<script src="../../editing.js"></script>
+</head>
+<body>
+<div id="dropzone" style="width: 200px; height: 200px; background-color: grey;"></div>
+<script>
+description("Test that hidden files are not exposed via Entries API");
+jsTestIsAsync = true;
+
+function getFileAsPromise(dirEntry, path)
+{
+    return new Promise((resolve, reject) => {
+        dirEntry.getFile(path, {}, resolve, reject);
+    });
+}
+
+function getDirectoryAsPromise(dirEntry, path)
+{
+    return new Promise((resolve, reject) => {
+        dirEntry.getDirectory(path, {}, resolve, reject);
+    });
+}
+
+function getEntriesAsPromise(dirEntry) {
+    return new Promise((resolve, reject) => {
+        let result = [];
+        let reader = dirEntry.createReader();
+        let doBatch = () => {
+            reader.readEntries(entries => {
+            if (entries.length > 0) {
+                entries.forEach(e => result.push(e));
+                doBatch();
+            } else {
+                resolve(result);
+            }
+        }, reject);
+    };
+    doBatch();
+  });
+}
+
+function readEntriesTest()
+{
+    shouldBeEqualToString("directoryEntry.name", "testFiles");
+    shouldBeEqualToString("directoryEntry.fullPath", "/testFiles");
+    shouldBeTrue("directoryEntry.isDirectory");
+
+    return getEntriesAsPromise(directoryEntry).then(entries => {
+        foundEntries = entries;
+        shouldBe("foundEntries.length", "4");
+        for (let entry of entries) {
+            if (entry.name.startsWith(".hidden")) {
+                testFailed("Hidden file was returned by directoryEntry");
+                break;
+            }
+        }
+    }, e => {
+        testFailed("Call to readEntries() failed unexpectedly: " + e);
+        finishJSTest();
+    });
+}
+
+function getFileTest()
+{
+    return getFileAsPromise(directoryEntry, ".hidden.txt").then(fileEntry => {
+        testFailed("Hidden file was returned by getFile()");
+        finishJSTest();
+    }, e => {
+        ex = e;
+        shouldBeEqualToString("ex.name", "NotFoundError");
+    });
+}
+
+function getDirectoryTest()
+{
+    return getDirectoryAsPromise(directoryEntry, ".hidden").then(fileEntry => {
+        testFailed("Hidden directory was returned by getDirectory()");
+        finishJSTest();
+    }, e => {
+        ex = e;
+        shouldBeEqualToString("ex.name", "NotFoundError");
+    });
+}
+
+var dropzone = document.getElementById('dropzone');
+dropzone.ondrop = function(e) {
+    e.preventDefault();
+    dataTransfer = e.dataTransfer;
+
+    shouldBe("dataTransfer.items.length", "1");
+
+    directoryEntry = dataTransfer.items[0].webkitGetAsEntry();
+
+    readEntriesTest().then(getFileTest).then(getDirectoryTest).then(finishJSTest);
+};
+
+dropzone.ondragover = function(ev) {
+    ev.preventDefault();
+}
+
+onload = function() {
+    dragFilesOntoElement(dropzone, ['../../../fast/forms/file/entries-api/resources/testFiles']);
+}
+</script>
+</body>
+</html>
diff --git a/LayoutTests/fast/forms/file/entries-api/resources/testFiles/.hidden.txt b/LayoutTests/fast/forms/file/entries-api/resources/testFiles/.hidden.txt
new file mode 100644 (file)
index 0000000..136c05e
--- /dev/null
@@ -0,0 +1 @@
+hidden
diff --git a/LayoutTests/fast/forms/file/entries-api/resources/testFiles/.hidden/hidden.txt b/LayoutTests/fast/forms/file/entries-api/resources/testFiles/.hidden/hidden.txt
new file mode 100644 (file)
index 0000000..136c05e
--- /dev/null
@@ -0,0 +1 @@
+hidden
index 5ab3f36..36fa7f5 100644 (file)
@@ -581,6 +581,9 @@ crypto/workers/subtle/ [ Skip ]
 # TODO Missing WebSpeech implementation
 webkit.org/b/136224 fast/speechsynthesis [ Skip ]
 
+# Test is Posix-specific.
+editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file.html [ Skip ]
+
 # TODO Impossible to test text-only-zoom from DRT on Windows
 webkit.org/b/35013 svg/zoom/text/ [ Skip ]
 
index 2b1ae4c..9a1467b 100644 (file)
@@ -1,3 +1,22 @@
+2017-09-05  Chris Dumez  <cdumez@apple.com>
+
+        FileSystemEntry API should ignore hidden files
+        https://bugs.webkit.org/show_bug.cgi?id=176292
+        <rdar://problem/34257666>
+
+        Reviewed by Andreas Kling.
+
+        FileSystemEntry API should ignore hidden files as the user likely does not mean
+        to expose those when drag'n dropping a folder.
+
+        Test: editing/pasteboard/enties-api/datatransfer-items-drop-hidden-file.html
+
+        * Modules/entriesapi/DOMFileSystem.cpp:
+        (WebCore::listDirectoryWithMetadata):
+        (WebCore::validatePathIsExpectedType):
+        (WebCore::fileType):
+        (WebCore::DOMFileSystem::getEntry):
+
 2017-09-05  Myles C. Maxfield  <mmaxfield@apple.com>
 
         Update font selection algorithm to match latest CSS spec
index a719b5f..4a02ec3 100644 (file)
@@ -56,7 +56,7 @@ static ExceptionOr<Vector<ListedChild>> listDirectoryWithMetadata(const String&
     listedChildren.reserveInitialCapacity(childPaths.size());
     for (auto& childPath : childPaths) {
         auto metadata = fileMetadata(childPath);
-        if (!metadata)
+        if (!metadata || metadata.value().isHidden)
             continue;
         listedChildren.uncheckedAppend(ListedChild { pathGetFileName(childPath), metadata.value().type });
     }
@@ -164,7 +164,7 @@ static ExceptionOr<String> validatePathIsExpectedType(const String& fullPath, St
     ASSERT(!isMainThread());
 
     auto metadata = fileMetadata(fullPath);
-    if (!metadata)
+    if (!metadata || metadata.value().isHidden)
         return Exception { NotFoundError, ASCIILiteral("Path does not exist") };
 
     if (metadata.value().type != expectedType)
@@ -173,6 +173,14 @@ static ExceptionOr<String> validatePathIsExpectedType(const String& fullPath, St
     return WTFMove(virtualPath);
 }
 
+static std::optional<FileMetadata::Type> fileType(const String& fullPath)
+{
+    auto metadata = fileMetadata(fullPath);
+    if (!metadata || metadata.value().isHidden)
+        return std::nullopt;
+    return metadata.value().type;
+}
+
 // https://wicg.github.io/entries-api/#resolve-a-relative-path
 static String resolveRelativeVirtualPath(StringView baseVirtualPath, StringView relativeVirtualPath)
 {
@@ -297,9 +305,7 @@ void DOMFileSystem::getEntry(ScriptExecutionContext& context, FileSystemDirector
     }
 
     m_workQueue->dispatch([this, context = makeRef(context), fullPath = crossThreadCopy(fullPath), resolvedVirtualPath = crossThreadCopy(resolvedVirtualPath), completionCallback = WTFMove(completionCallback)]() mutable {
-        std::optional<FileMetadata::Type> entryType;
-        if (auto metadata = fileMetadata(fullPath))
-            entryType = metadata.value().type;
+        auto entryType = fileType(fullPath);
         callOnMainThread([this, context = WTFMove(context), resolvedVirtualPath = crossThreadCopy(resolvedVirtualPath), entryType, completionCallback = WTFMove(completionCallback)]() mutable {
             if (!entryType) {
                 completionCallback(Exception { NotFoundError, ASCIILiteral("Cannot find entry at given path") });