On ToT, event.dataTransfer.getData("text/uri-list") returns an empty string when...
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Oct 2017 07:59:39 +0000 (07:59 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Oct 2017 07:59:39 +0000 (07:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178301
<rdar://problem/34990050>

Reviewed by Darin Adler.

Source/WebCore:

After r222656, we consider images on the pasteboard to be files. This causes DataTransfer.getData to return the
empty string for all types, which brings back https://bugs.webkit.org/show_bug.cgi?id=170637. To allow pages to
access the URL part of a dragged image, we exempt "text/uri-list" from our heurstics to hide pasteboard data
which may contain files, and return the URL as long as its protocol is either HTTP or HTTPS.

Tweaked an existing layout test to cover this scenario, as well as the scenario in which the dragged image links
to a file URL (in which case we should avoid exposing the data).

Test: editing/pasteboard/drag-drop-href-as-url.html
      DataInteractionTests.DataTransferGetDataWhenDroppingImageWithHTTPURL

* dom/DataTransfer.cpp:
(WebCore::DataTransfer::getDataForItem const):

When the pasteboard contains files, allow data for "text/uri-list" to be returned, as long as the URL string has
a white-listed protocol (currently, this is just http and https).

(WebCore::DataTransfer::shouldSuppressGetAndSetDataToAvoidExposingFilePaths const):
(WebCore::DataTransfer::setData):
(WebCore::DataTransfer::types const):

When the pasteboard contains files, allow "text/uri-list" to be added, alongside the "Files" type, if it would
have been exposed in the list of safe DOM types.

* dom/DataTransfer.h:
* platform/Pasteboard.cpp:
(WebCore::Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles):

Add a new helper method to determine whether it is safe to expose an URL string as "text/uri-list" to bindings,
if the pasteboard contains files. While this currently checks whether or not the URL is in the HTTP family, we
may want to consider tweaking this to blacklist the "file" protocol instead, and allow all other valid URLs by
default.

* platform/Pasteboard.h:
* platform/PlatformPasteboard.h:
* platform/ios/PlatformPasteboardIOS.mm:
(WebCore::pasteboardMayContainFilePaths):
(WebCore::PlatformPasteboard::stringForType const):

Mark stringForType as const, and also teach stringForType to return the null string for the platform URL type if
the pasteboard might contain file paths.

(WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const):

Before coercing a platform type to "text/uri-list" when building the list of DOM-safe types, check that the
stringForType is not the empty string, in which case we don't expose the type to the DOM at all. This ensures
that in cases where the URL might reveal a file path, we don't advertise "text/uri-list" as a type. We adopt a
similar strategy on iOS.

(WebCore::PlatformPasteboard::stringForType): Deleted.
* platform/mac/PlatformPasteboardMac.mm:
(WebCore::pasteboardMayContainFilePaths):
(WebCore::PlatformPasteboard::stringForType const):
(WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const):
(WebCore::PlatformPasteboard::stringForType): Deleted.

Tools:

Fixes issues in DumpRenderTree's LocalPasteboard to ensure that drag-drop-href-as-url.html exposes files, and
also adds a new iOS drag and drop API test.

* DumpRenderTree/mac/DumpRenderTreePasteboard.mm:
(-[LocalPasteboard addTypes:owner:]):
(-[LocalPasteboard setData:forType:]):

Fixes LocalPasteboard's implementation of changeCount to incremement when the pasteboard owner changes, rather
than every time data is changed. This is consistent with NSPasteboard behavior.

* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(TestWebKitAPI::TEST):

Adds a new API test to verify that an image and HTTP URL written by the platform is correctly web exposed.

LayoutTests:

Fixes an existing test to account for asynchronous image decoding, and also rebaselines results to expect that
only the URL can be read, and not text.

* TestExpectations:
* editing/pasteboard/data-transfer-item-list-add-file-multiple-times-expected.txt:
* editing/pasteboard/drag-drop-href-as-text-data-expected.txt: Removed.
* editing/pasteboard/drag-drop-href-as-text-data.html: Removed.
* editing/pasteboard/drag-drop-href-as-url-expected.txt: Added.
* editing/pasteboard/drag-drop-href-as-url.html: Added.

Tweaks an existing drag and drop test to verify that an URL can be read back when dragging an image, but not
when if the URL is a file URL.

* editing/pasteboard/files-during-page-drags-expected.txt:
* editing/pasteboard/files-during-page-drags.html:

Fixes this test by decoding the dragged image element before starting the drag and drop simulation.

* platform/mac-wk1/TestExpectations:

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

21 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/editing/pasteboard/data-transfer-item-list-add-file-multiple-times-expected.txt
LayoutTests/editing/pasteboard/drag-drop-href-as-text-data-expected.txt [deleted file]
LayoutTests/editing/pasteboard/drag-drop-href-as-text-data.html [deleted file]
LayoutTests/editing/pasteboard/drag-drop-href-as-url-expected.txt [new file with mode: 0644]
LayoutTests/editing/pasteboard/drag-drop-href-as-url.html [new file with mode: 0644]
LayoutTests/editing/pasteboard/files-during-page-drags-expected.txt
LayoutTests/editing/pasteboard/files-during-page-drags.html
LayoutTests/platform/mac-wk1/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/dom/DataTransfer.cpp
Source/WebCore/dom/DataTransfer.h
Source/WebCore/platform/Pasteboard.cpp
Source/WebCore/platform/Pasteboard.h
Source/WebCore/platform/PlatformPasteboard.h
Source/WebCore/platform/ios/PlatformPasteboardIOS.mm
Source/WebCore/platform/mac/PlatformPasteboardMac.mm
Tools/ChangeLog
Tools/DumpRenderTree/mac/DumpRenderTreePasteboard.mm
Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm

index 238b87f..d44b5c6 100644 (file)
@@ -1,3 +1,31 @@
+2017-10-16  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        On ToT, event.dataTransfer.getData("text/uri-list") returns an empty string when dragging an image
+        https://bugs.webkit.org/show_bug.cgi?id=178301
+        <rdar://problem/34990050>
+
+        Reviewed by Darin Adler.
+
+        Fixes an existing test to account for asynchronous image decoding, and also rebaselines results to expect that
+        only the URL can be read, and not text.
+
+        * TestExpectations:
+        * editing/pasteboard/data-transfer-item-list-add-file-multiple-times-expected.txt:
+        * editing/pasteboard/drag-drop-href-as-text-data-expected.txt: Removed.
+        * editing/pasteboard/drag-drop-href-as-text-data.html: Removed.
+        * editing/pasteboard/drag-drop-href-as-url-expected.txt: Added.
+        * editing/pasteboard/drag-drop-href-as-url.html: Added.
+
+        Tweaks an existing drag and drop test to verify that an URL can be read back when dragging an image, but not
+        when if the URL is a file URL.
+
+        * editing/pasteboard/files-during-page-drags-expected.txt:
+        * editing/pasteboard/files-during-page-drags.html:
+
+        Fixes this test by decoding the dragged image element before starting the drag and drop simulation.
+
+        * platform/mac-wk1/TestExpectations:
+
 2017-10-15  Nikita Vasilyev  <nvasilyev@apple.com>
 
         Web Inspector: Modify CSS number values with up key and down key
index 8387a7c..2edaa20 100644 (file)
@@ -71,7 +71,7 @@ fast/events/autoscroll-when-zoomed.html [ Skip ]
 fast/events/autoscroll-main-document.html [ Skip ]
 
 # Drag and drop via EventSender is only supported on Mac WK1
-editing/pasteboard/drag-drop-href-as-text-data.html [ Skip ]
+editing/pasteboard/drag-drop-href-as-url.html [ Skip ]
 editing/pasteboard/data-transfer-get-data-on-drop-custom.html [ Skip ]
 editing/pasteboard/data-transfer-get-data-on-drop-plain-text.html [ Skip ]
 editing/pasteboard/data-transfer-get-data-on-drop-rich-text.html [ Skip ]
index d801606..1f80c59 100644 (file)
@@ -9,7 +9,8 @@ operation performed at each step.
 1. After adding all items
 {
     "data": {
-        "Files": ""
+        "Files": "",
+        "text/uri-list": "https://webkit.org"
     },
     "items": [
         {
@@ -86,7 +87,8 @@ operation performed at each step.
 2. After removing at index 4
 {
     "data": {
-        "Files": ""
+        "Files": "",
+        "text/uri-list": "https://webkit.org"
     },
     "items": [
         {
@@ -150,7 +152,8 @@ removedItem.getAsFile() should be null: null
 3. After removing at index 1
 {
     "data": {
-        "Files": ""
+        "Files": "",
+        "text/uri-list": "https://webkit.org"
     },
     "items": [
         {
@@ -200,7 +203,8 @@ removedItem.getAsFile() should be null: null
 4. After removing at index 3
 {
     "data": {
-        "Files": ""
+        "Files": "",
+        "text/uri-list": "https://webkit.org"
     },
     "items": [
         {
diff --git a/LayoutTests/editing/pasteboard/drag-drop-href-as-text-data-expected.txt b/LayoutTests/editing/pasteboard/drag-drop-href-as-text-data-expected.txt
deleted file mode 100644 (file)
index f0b68e4..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-
-text: "https://www.webkit.org/"
-url: "https://www.webkit.org/"
-text/plain: "https://www.webkit.org/"
-text/uri-list: "https://www.webkit.org/"
diff --git a/LayoutTests/editing/pasteboard/drag-drop-href-as-text-data.html b/LayoutTests/editing/pasteboard/drag-drop-href-as-text-data.html
deleted file mode 100644 (file)
index cee73e5..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-<!DOCTYPE html>
-<html>
-<style>
-body {
-    margin: 0;
-}
-#source {
-    width: 300px;
-    height: 300px;
-}
-#target {
-    border: 1px blue dashed;
-    font-family: monospace;
-    overflow: scroll;
-    white-space: nowrap;
-    width: 100%;
-    height: 300px;
-}
-</style>
-
-<a id="link" href="https://www.webkit.org/"><img id="source" src="../resources/abe.png"></img></a>
-<div id="target"></div>
-
-<script>
-function append(text) {
-    let div = document.createElement("div");
-    div.textContent = text;
-    target.appendChild(div);
-}
-
-if (window.testRunner)
-    testRunner.dumpAsText();
-
-target.addEventListener("dragenter", event => event.preventDefault());
-target.addEventListener("dragover", event => event.preventDefault());
-target.addEventListener("drop", event => {
-    for (let type of ["text", "url", "text/plain", "text/uri-list"])
-        append(`${type}: "${event.dataTransfer.getData(type)}"`);
-    event.preventDefault();
-});
-
-if (window.eventSender) {
-    let x = source.offsetLeft + source.offsetWidth / 2;
-    let y = source.offsetTop + source.offsetHeight / 2;
-    eventSender.mouseMoveTo(x, y);
-    eventSender.mouseDown();
-    eventSender.leapForward(500);
-    eventSender.mouseMoveTo(x, y + 300);
-    eventSender.mouseUp();
-}
-</script>
-</html>
\ No newline at end of file
diff --git a/LayoutTests/editing/pasteboard/drag-drop-href-as-url-expected.txt b/LayoutTests/editing/pasteboard/drag-drop-href-as-url-expected.txt
new file mode 100644 (file)
index 0000000..36e1c86
--- /dev/null
@@ -0,0 +1,11 @@
+
+1. link.href = "https://www.webkit.org/"
+URL: "https://www.webkit.org/"
+url: "https://www.webkit.org/"
+text/uri-list: "https://www.webkit.org/"
+Found file of type image/png
+2. link.href = "file:///foo/bar/baz"
+URL: ""
+url: ""
+text/uri-list: ""
+Found file of type image/png
diff --git a/LayoutTests/editing/pasteboard/drag-drop-href-as-url.html b/LayoutTests/editing/pasteboard/drag-drop-href-as-url.html
new file mode 100644 (file)
index 0000000..621c0a3
--- /dev/null
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html>
+<style>
+body {
+    margin: 0;
+}
+#source {
+    width: 300px;
+    height: 300px;
+}
+#target {
+    border: 1px blue dashed;
+    font-family: monospace;
+    overflow: scroll;
+    white-space: nowrap;
+    width: 100%;
+    height: 300px;
+}
+</style>
+
+<body onload=setup()>
+<a id="link" href="https://www.webkit.org/"><img id="source" src="../resources/abe.png"></img></a>
+<div id="target"></div>
+</body>
+
+<script>
+function append(text) {
+    let div = document.createElement("div");
+    div.textContent = text;
+    target.appendChild(div);
+}
+
+async function setup() {
+    target.addEventListener("dragenter", event => event.preventDefault());
+    target.addEventListener("dragover", event => event.preventDefault());
+    target.addEventListener("drop", event => {
+        for (const type of ["URL", "url", "text/uri-list"])
+            append(`${type}: "${event.dataTransfer.getData(type)}"`);
+        for (const file of event.dataTransfer.files)
+            append(`Found file of type ${file.type}`);
+        event.preventDefault();
+    });
+
+    if (!window.testRunner || !window.eventSender || !window.internals)
+        return;
+
+    internals.settings.setCustomPasteboardDataEnabled(true);
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+
+    await source.decode();
+    let x = source.offsetLeft + source.offsetWidth / 2;
+    let y = source.offsetTop + source.offsetHeight / 2;
+
+    append(`1. link.href = "${link.href}"`);
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.leapForward(500);
+    eventSender.mouseMoveTo(x, y + 300);
+    eventSender.mouseUp();
+
+    link.href = "file:///foo/bar/baz";
+    append(`2. link.href = "${link.href}"`);
+    eventSender.mouseMoveTo(x, y);
+    eventSender.mouseDown();
+    eventSender.leapForward(500);
+    eventSender.mouseMoveTo(x, y + 300);
+    eventSender.mouseUp();
+
+    testRunner.notifyDone();
+}
+</script>
+</html>
\ No newline at end of file
index d0573ff..2e1a926 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS Drag of A resulted in empty files array.
-PASS Drag of IMG resulted in empty files array.
+PASS Drag of IMG resulted in files array of size 1
 PASS successfullyParsed is true
 
 TEST COMPLETE
index f79a97b..4c404a0 100644 (file)
@@ -3,12 +3,14 @@
 <head>
 <script src="../../resources/js-test-pre.js"></script>
 </head>
-<body>
+<body onload=runTest()>
 <p id="description"></p>
 <div id="console"></div>
 <script>
 description("Make sure that .files arrays are always empty for non-file drags.");
 
+jsTestIsAsync = true;
+
 var testContainer = document.createElement('div');
 // Put dragables at the top so that logging does not cause them to move off screen (where we can't drag).
 document.body.insertBefore(testContainer, document.body.firstChild);
@@ -69,23 +71,25 @@ function testDrag(source)
         testFailed("Drop of " + source.tagName + " never occured!");
     else if (droppedFiles.length == 0)
         testPassed("Drag of " + source.tagName + " resulted in empty files array.");
+    else if (source == image)
+        testPassed(`Drag of ${source.tagName} resulted in files array of size ${droppedFiles.length}`);
     else
         testFailed("Drag of " + source.tagName + " resulted in non-empty files array! (files: " + droppedFiles.length + ")");
     droppedFiles = null;
 }
 
-function runTest()
+async function runTest()
 {
+    if (!window.eventSender || !window.testRunner) {
+        testFailed("This test is not interactive, please run using DumpRenderTree");
+        return;
+    }
+
+    await image.decode();
     testDrag(link);
     testDrag(image);
-}
-
-if (window.eventSender) {
-    runTest();
-    // Clean up after ourselves
     document.body.removeChild(testContainer);
-} else {
-    testFailed("This test is not interactive, please run using DumpRenderTree");
+    finishJSTest();
 }
 
 var successfullyParsed = true;
index 5478bb7..efa86e2 100644 (file)
@@ -6,7 +6,7 @@
 #//////////////////////////////////////////////////////////////////////////////////////////
 
 fast/forms/attributed-strings.html [ Pass ]
-editing/pasteboard/drag-drop-href-as-text-data.html [ Pass ]
+editing/pasteboard/drag-drop-href-as-url.html [ Pass ]
 editing/pasteboard/data-transfer-get-data-on-drop-custom.html [ Pass ]
 editing/pasteboard/data-transfer-get-data-on-drop-plain-text.html [ Pass ]
 editing/pasteboard/data-transfer-get-data-on-drop-rich-text.html [ Pass ]
index ae62207..6ad11d2 100644 (file)
@@ -1,3 +1,67 @@
+2017-10-16  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        On ToT, event.dataTransfer.getData("text/uri-list") returns an empty string when dragging an image
+        https://bugs.webkit.org/show_bug.cgi?id=178301
+        <rdar://problem/34990050>
+
+        Reviewed by Darin Adler.
+
+        After r222656, we consider images on the pasteboard to be files. This causes DataTransfer.getData to return the
+        empty string for all types, which brings back https://bugs.webkit.org/show_bug.cgi?id=170637. To allow pages to
+        access the URL part of a dragged image, we exempt "text/uri-list" from our heurstics to hide pasteboard data
+        which may contain files, and return the URL as long as its protocol is either HTTP or HTTPS.
+
+        Tweaked an existing layout test to cover this scenario, as well as the scenario in which the dragged image links
+        to a file URL (in which case we should avoid exposing the data).
+
+        Test: editing/pasteboard/drag-drop-href-as-url.html
+              DataInteractionTests.DataTransferGetDataWhenDroppingImageWithHTTPURL
+
+        * dom/DataTransfer.cpp:
+        (WebCore::DataTransfer::getDataForItem const):
+
+        When the pasteboard contains files, allow data for "text/uri-list" to be returned, as long as the URL string has
+        a white-listed protocol (currently, this is just http and https).
+
+        (WebCore::DataTransfer::shouldSuppressGetAndSetDataToAvoidExposingFilePaths const):
+        (WebCore::DataTransfer::setData):
+        (WebCore::DataTransfer::types const):
+
+        When the pasteboard contains files, allow "text/uri-list" to be added, alongside the "Files" type, if it would
+        have been exposed in the list of safe DOM types.
+
+        * dom/DataTransfer.h:
+        * platform/Pasteboard.cpp:
+        (WebCore::Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles):
+
+        Add a new helper method to determine whether it is safe to expose an URL string as "text/uri-list" to bindings,
+        if the pasteboard contains files. While this currently checks whether or not the URL is in the HTTP family, we
+        may want to consider tweaking this to blacklist the "file" protocol instead, and allow all other valid URLs by
+        default.
+
+        * platform/Pasteboard.h:
+        * platform/PlatformPasteboard.h:
+        * platform/ios/PlatformPasteboardIOS.mm:
+        (WebCore::pasteboardMayContainFilePaths):
+        (WebCore::PlatformPasteboard::stringForType const):
+
+        Mark stringForType as const, and also teach stringForType to return the null string for the platform URL type if
+        the pasteboard might contain file paths.
+
+        (WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const):
+
+        Before coercing a platform type to "text/uri-list" when building the list of DOM-safe types, check that the
+        stringForType is not the empty string, in which case we don't expose the type to the DOM at all. This ensures
+        that in cases where the URL might reveal a file path, we don't advertise "text/uri-list" as a type. We adopt a
+        similar strategy on iOS.
+
+        (WebCore::PlatformPasteboard::stringForType): Deleted.
+        * platform/mac/PlatformPasteboardMac.mm:
+        (WebCore::pasteboardMayContainFilePaths):
+        (WebCore::PlatformPasteboard::stringForType const):
+        (WebCore::PlatformPasteboard::typesSafeForDOMToReadAndWrite const):
+        (WebCore::PlatformPasteboard::stringForType): Deleted.
+
 2017-10-16  Frederic Wang  <fwang@igalia.com>
 
         Use auto/nullptr in scrolling code
index b37ac92..7d79cc2 100644 (file)
@@ -149,12 +149,18 @@ void DataTransfer::clearData(const String& type)
 String DataTransfer::getDataForItem(const String& type) const
 {
     if (!canReadData())
-        return String();
-
-    if ((forFileDrag() || Settings::customPasteboardDataEnabled()) && m_pasteboard->containsFiles())
         return { };
 
     auto lowercaseType = stripLeadingAndTrailingHTMLSpaces(type).convertToASCIILowercase();
+    if (shouldSuppressGetAndSetDataToAvoidExposingFilePaths()) {
+        if (lowercaseType == "text/uri-list") {
+            auto urlString = m_pasteboard->readString(lowercaseType);
+            if (Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles(urlString))
+                return urlString;
+        }
+        return { };
+    }
+
     if (!Settings::customPasteboardDataEnabled())
         return m_pasteboard->readString(lowercaseType);
 
@@ -184,12 +190,19 @@ String DataTransfer::getData(const String& type) const
     return getDataForItem(normalizeType(type));
 }
 
+bool DataTransfer::shouldSuppressGetAndSetDataToAvoidExposingFilePaths() const
+{
+    if (!forFileDrag() && !Settings::customPasteboardDataEnabled())
+        return false;
+    return m_pasteboard->containsFiles();
+}
+
 void DataTransfer::setData(const String& type, const String& data)
 {
     if (!canWriteData())
         return;
 
-    if ((forFileDrag() || Settings::customPasteboardDataEnabled()) && m_pasteboard->containsFiles())
+    if (shouldSuppressGetAndSetDataToAvoidExposingFilePaths())
         return;
 
     auto normalizedType = normalizeType(type);
@@ -271,17 +284,22 @@ Vector<String> DataTransfer::types(AddFilesType addFilesType) const
         return types;
     }
 
-    if (m_itemList && m_itemList->hasItems() && m_itemList->items().findMatching([] (const auto& item) { return item->isFile(); }) != notFound)
-        return addFilesType == AddFilesType::Yes ? Vector<String> { ASCIILiteral("Files") } : Vector<String> { };
-
-    if (m_pasteboard->containsFiles()) {
-        ASSERT(!m_pasteboard->typesSafeForBindings(m_originIdentifier).contains("Files"));
-        return addFilesType == AddFilesType::Yes ? Vector<String> { ASCIILiteral("Files") } : Vector<String> { };
+    auto safeTypes = m_pasteboard->typesSafeForBindings(m_originIdentifier);
+    bool hasFileBackedItem = m_itemList && m_itemList->hasItems() && notFound != m_itemList->items().findMatching([] (const auto& item) {
+        return item->isFile();
+    });
+
+    if (hasFileBackedItem || m_pasteboard->containsFiles()) {
+        Vector<String> types;
+        if (addFilesType == AddFilesType::Yes)
+            types.append(ASCIILiteral("Files"));
+        if (safeTypes.contains("text/uri-list"))
+            types.append(ASCIILiteral("text/uri-list"));
+        return types;
     }
 
-    auto types = m_pasteboard->typesSafeForBindings(m_originIdentifier);
-    ASSERT(!types.contains("Files"));
-    return types;
+    ASSERT(!safeTypes.contains("Files"));
+    return safeTypes;
 }
 
 Vector<Ref<File>> DataTransfer::filesFromPasteboardAndItemList() const
index 0f3f209..65b4bc6 100644 (file)
@@ -121,6 +121,8 @@ private:
     bool forFileDrag() const { return false; }
 #endif
 
+    bool shouldSuppressGetAndSetDataToAvoidExposingFilePaths() const;
+
     enum class AddFilesType { No, Yes };
     Vector<String> types(AddFilesType) const;
     Vector<Ref<File>> filesFromPasteboardAndItemList() const;
index d74ff47..f2c5106 100644 (file)
@@ -30,6 +30,7 @@
 #include "PlatformStrategies.h"
 #include "Settings.h"
 #include "SharedBuffer.h"
+#include "URLParser.h"
 #include <wtf/persistence/PersistentCoders.h>
 #include <wtf/text/StringHash.h>
 
@@ -44,6 +45,11 @@ bool Pasteboard::isSafeTypeForDOMToReadAndWrite(const String& type)
     return type == "text/plain" || type == "text/html" || type == "text/uri-list";
 }
 
+bool Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles(const String& urlString)
+{
+    return URLParser { urlString }.result().protocolIsInHTTPFamily();
+}
+
 Ref<SharedBuffer> PasteboardCustomData::createSharedBuffer() const
 {
     const static unsigned currentCustomDataSerializationVersion = 1;
index 620a504..473f264 100644 (file)
@@ -189,6 +189,7 @@ public:
     WEBCORE_EXPORT static std::unique_ptr<Pasteboard> createForCopyAndPaste();
 
     static bool isSafeTypeForDOMToReadAndWrite(const String&);
+    static bool canExposeURLToDOMWhenPasteboardContainsFiles(const String&);
 
     virtual bool isStatic() const { return false; }
 
index 4f4ab0a..d8d7c94 100644 (file)
@@ -70,7 +70,7 @@ public:
     WEBCORE_EXPORT void getTypes(Vector<String>& types);
     WEBCORE_EXPORT RefPtr<SharedBuffer> bufferForType(const String& pasteboardType);
     WEBCORE_EXPORT void getPathnamesForType(Vector<String>& pathnames, const String& pasteboardType) const;
-    WEBCORE_EXPORT String stringForType(const String& pasteboardType);
+    WEBCORE_EXPORT String stringForType(const String& pasteboardType) const;
     WEBCORE_EXPORT long changeCount() const;
     WEBCORE_EXPORT Color color();
     WEBCORE_EXPORT URL url();
index 895f8c1..c337719 100644 (file)
@@ -111,20 +111,37 @@ Vector<String> PlatformPasteboard::filenamesForDataInteraction()
     return filenames;
 }
 
-String PlatformPasteboard::stringForType(const String& type)
+static bool pasteboardMayContainFilePaths(id<AbstractPasteboard> pasteboard)
 {
-    NSArray *values = [m_pasteboard valuesForPasteboardType:type inItemSet:[NSIndexSet indexSetWithIndex:0]];
-    for (id value in values) {
-        if ([value isKindOfClass:[NSURL class]])
-            return [(NSURL *)value absoluteString];
+    if ([pasteboard isKindOfClass:[WebItemProviderPasteboard class]])
+        return false;
 
-        if ([value isKindOfClass:[NSAttributedString class]])
-            return [(NSAttributedString *)value string];
+    for (NSString *type in pasteboard.pasteboardTypes) {
+        if (Pasteboard::shouldTreatCocoaTypeAsFile(type))
+            return true;
+    }
+    return false;
+}
 
-        if ([value isKindOfClass:[NSString class]])
-            return (NSString *)value;
+String PlatformPasteboard::stringForType(const String& type) const
+{
+    auto value = retainPtr([m_pasteboard valuesForPasteboardType:type inItemSet:[NSIndexSet indexSetWithIndex:0]].firstObject);
+    String result;
+    if ([value isKindOfClass:[NSURL class]])
+        result = [(NSURL *)value absoluteString];
+
+    else if ([value isKindOfClass:[NSAttributedString class]])
+        result = [(NSAttributedString *)value string];
+
+    else if ([value isKindOfClass:[NSString class]])
+        result = (NSString *)value;
+
+    if (pasteboardMayContainFilePaths(m_pasteboard.get()) && type == String { kUTTypeURL }) {
+        if (!Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles(result))
+            result = { };
     }
-    return String();
+
+    return result;
 }
 
 Color PlatformPasteboard::color()
@@ -388,8 +405,15 @@ Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String& o
             continue;
         }
 
-        if (auto* coercedType = safeTypeForDOMToReadAndWriteForPlatformType(type))
-            domPasteboardTypes.add(String::fromUTF8(coercedType));
+        if (auto* coercedType = safeTypeForDOMToReadAndWriteForPlatformType(type)) {
+            auto domTypeAsString = String::fromUTF8(coercedType);
+            if (domTypeAsString == "text/uri-list") {
+                BOOL ableToDetermineProtocolOfPasteboardURL = ![m_pasteboard isKindOfClass:[WebItemProviderPasteboard class]];
+                if (ableToDetermineProtocolOfPasteboardURL && stringForType(kUTTypeURL).isEmpty())
+                    continue;
+            }
+            domPasteboardTypes.add(WTFMove(domTypeAsString));
+        }
     }
 
     return copyToVector(domPasteboardTypes);
index c293ea2..22ab2cb 100644 (file)
@@ -78,16 +78,22 @@ void PlatformPasteboard::getPathnamesForType(Vector<String>& pathnames, const St
         pathnames.append([paths objectAtIndex:i]);
 }
 
-String PlatformPasteboard::stringForType(const String& pasteboardType)
+static bool pasteboardMayContainFilePaths(NSPasteboard *pasteboard)
 {
-    if (pasteboardType == String(NSURLPboardType)) {
-        if (NSURL *urlFromPasteboard = [NSURL URLFromPasteboard:m_pasteboard.get()])
-            return urlFromPasteboard.absoluteString;
+    for (NSString *type in pasteboard.types) {
+        if ([type isEqualToString:(NSString *)NSFilenamesPboardType] || [type isEqualToString:(NSString *)NSFilesPromisePboardType] || Pasteboard::shouldTreatCocoaTypeAsFile(type))
+            return true;
+    }
+    return false;
+}
 
-        URL url([NSURL URLWithString:[m_pasteboard stringForType:NSURLPboardType]]);
-        if (!url.isValid())
+String PlatformPasteboard::stringForType(const String& pasteboardType) const
+{
+    if (pasteboardType == String { NSURLPboardType }) {
+        String urlString = ([NSURL URLFromPasteboard:m_pasteboard.get()] ?: [NSURL URLWithString:[m_pasteboard stringForType:NSURLPboardType]]).absoluteString;
+        if (pasteboardMayContainFilePaths(m_pasteboard.get()) && !Pasteboard::canExposeURLToDOMWhenPasteboardContainsFiles(urlString))
             return { };
-        return url.string();
+        return urlString;
     }
 
     return [m_pasteboard stringForType:pasteboardType];
@@ -125,8 +131,12 @@ Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String& o
 
         if (Pasteboard::isSafeTypeForDOMToReadAndWrite(type))
             domPasteboardTypes.add(type);
-        else if (auto* domType = safeTypeForDOMToReadAndWriteForPlatformType(type))
-            domPasteboardTypes.add(String::fromUTF8(domType));
+        else if (auto* domType = safeTypeForDOMToReadAndWriteForPlatformType(type)) {
+            auto domTypeAsString = String::fromUTF8(domType);
+            if (domTypeAsString == "text/uri-list" && stringForType(NSURLPboardType).isEmpty())
+                continue;
+            domPasteboardTypes.add(WTFMove(domTypeAsString));
+        }
     }
 
     return copyToVector(domPasteboardTypes);
index 2ec4f47..07e7374 100644 (file)
@@ -1,3 +1,26 @@
+2017-10-16  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        On ToT, event.dataTransfer.getData("text/uri-list") returns an empty string when dragging an image
+        https://bugs.webkit.org/show_bug.cgi?id=178301
+        <rdar://problem/34990050>
+
+        Reviewed by Darin Adler.
+
+        Fixes issues in DumpRenderTree's LocalPasteboard to ensure that drag-drop-href-as-url.html exposes files, and
+        also adds a new iOS drag and drop API test.
+
+        * DumpRenderTree/mac/DumpRenderTreePasteboard.mm:
+        (-[LocalPasteboard addTypes:owner:]):
+        (-[LocalPasteboard setData:forType:]):
+
+        Fixes LocalPasteboard's implementation of changeCount to incremement when the pasteboard owner changes, rather
+        than every time data is changed. This is consistent with NSPasteboard behavior.
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (TestWebKitAPI::TEST):
+
+        Adds a new API test to verify that an image and HTTP URL written by the platform is correctly web exposed.
+
 2017-10-15  Darin Adler  <darin@apple.com>
 
         UTF-8 decoding produces one replacement character per byte; Encoding standard requires one replacement character per illegal sequence instead
index e79bd87..cb897ae 100644 (file)
@@ -141,11 +141,15 @@ static RetainPtr<NSString> toUTI(NSString *type)
 
 - (NSInteger)addTypes:(NSArray *)newTypes owner:(id)newOwner
 {
-    _owner = newOwner;
+    if (_owner != newOwner) {
+        _owner = newOwner;
+        ++_changeCount;
+    }
+
     for (NSString *type in newTypes)
         _types.add(toUTI(type));
 
-    return ++_changeCount;
+    return _changeCount;
 }
 
 - (NSInteger)changeCount
@@ -186,7 +190,6 @@ static RetainPtr<NSString> toUTI(NSString *type)
         return NO;
 
     _data.set(WTFMove(uti), data ? data : [NSData data]);
-    ++_changeCount;
     return YES;
 }
 
index 4c9dc0f..548f387 100644 (file)
@@ -1560,8 +1560,30 @@ TEST(DataInteractionTests, DataTransferGetDataWhenDroppingImageWithFileURL)
 
     // File URLs should never be exposed directly to web content, so DataTransfer.getData should return an empty string here.
     checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
-        @"dragover": @{ @"Files": @"" },
-        @"drop": @{ @"Files": @"" }
+        @"dragover": @{ @"Files": @"", @"text/uri-list": @"" },
+        @"drop": @{ @"Files": @"", @"text/uri-list": @"" }
+    });
+}
+
+TEST(DataInteractionTests, DataTransferGetDataWhenDroppingImageWithHTTPURL)
+{
+    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
+    [webView synchronouslyLoadTestPageNamed:@"dump-datatransfer-types"];
+    auto simulator = adoptNS([[DataInteractionSimulator alloc] initWithWebView:webView.get()]);
+
+    auto itemProvider = adoptNS([[UIItemProvider alloc] init]);
+    [itemProvider registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeJPEG visibility:NSItemProviderRepresentationVisibilityAll loadHandler:^NSProgress *(DataLoadCompletionBlock completionHandler)
+    {
+        completionHandler(UIImageJPEGRepresentation(testIconImage(), 0.5), nil);
+        return nil;
+    }];
+    [itemProvider registerObject:[NSURL URLWithString:@"http://webkit.org"] visibility:UIItemProviderRepresentationOptionsVisibilityAll];
+    [simulator setExternalItemProviders:@[ itemProvider.get() ]];
+
+    [simulator runFrom:CGPointMake(300, 375) to:CGPointMake(50, 375)];
+    checkJSONWithLogging([webView stringByEvaluatingJavaScript:@"output.value"], @{
+        @"dragover": @{ @"Files": @"", @"text/uri-list": @"" },
+        @"drop": @{ @"Files": @"", @"text/uri-list": @"http://webkit.org/" }
     });
 }