Title: [261412] trunk
Revision
261412
Author
[email protected]
Date
2020-05-08 13:46:10 -0700 (Fri, 08 May 2020)

Log Message

Implement web-share v2 for files
https://bugs.webkit.org/show_bug.cgi?id=209265

Reviewed by Andy Estes.

LayoutTests/imported/w3c:

Updated test expectations for new behavior.

* ios-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt :
* mac-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt :

Source/WebCore:

Modified existing tests for new behavior.

Added support for handling of files in share/canShare,
and implemented asynchronous reading of data from blobs on
disk into memory.

* WebCore.xcodeproj/project.pbxproj:
* page/Navigator.cpp:
(WebCore::Navigator::canShare):
(WebCore::Navigator::share):
(WebCore::Navigator::finishedLoad):
* page/Navigator.h:
* page/ReadShareDataAsync.cpp: Added.
(WebCore::ReadShareDataAsync::readInternal):
(WebCore::ReadShareDataAsync::ReadShareDataAsync):
(WebCore::ReadShareDataAsync::~ReadShareDataAsync):
(WebCore::ReadShareDataAsync::start):
(WebCore::ReadShareDataAsync::didFinishLoading):
(WebCore::ReadShareDataAsync::didReceiveData):
(WebCore::ReadShareDataAsync::didStartLoading):
(WebCore::ReadShareDataAsync::didFail):
* page/ReadShareDataAsync.hpp: Added.
* page/ShareData.h:

Source/WebKit:

Added support for passing file objects over IPC and
sharing of files to share sheet.

* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<Vector<RawFile>>::encode):
(IPC::ArgumentCoder<Vector<RawFile>>::decode):
(IPC::ArgumentCoder<ShareDataWithParsedURL>::encode):
(IPC::ArgumentCoder<ShareDataWithParsedURL>::decode):
* Shared/WebCoreArgumentCoders.h:
* UIProcess/Cocoa/ShareableFileWrite.h: Added.
* UIProcess/Cocoa/ShareableFileWrite.mm: Added.
(+[WKShareableFileWrite getSharingDirectoryPath]):
(+[WKShareableFileWrite getFileDirectoryForSharing]):
(+[WKShareableFileWrite removeFileDirectoryForSharing]):
(+[WKShareableFileWrite setQuarantineInformationForFilePath:]):
(+[WKShareableFileWrite applyQuarantineSandboxAndDownloadFlagsToFileAtPath:]):
(+[WKShareableFileWrite createFilename:]):
(+[WKShareableFileWrite writeFileToShareableURL:data:]):
* UIProcess/Cocoa/WKShareSheet.mm:
(-[WKShareSheet presentWithParameters:inRect:completionHandler:]):
(-[WKShareSheet _didCompleteWithSuccess:]):
* WebKit.xcodeproj/project.pbxproj:

LayoutTests:

Modified to no longer use url of image.

* fast/web-share/share-with-files.html:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (261411 => 261412)


--- trunk/LayoutTests/ChangeLog	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/LayoutTests/ChangeLog	2020-05-08 20:46:10 UTC (rev 261412)
@@ -1,3 +1,14 @@
+2020-05-08  Nikos Mouchtaris  <[email protected]>
+
+        Implement web-share v2 for files
+        https://bugs.webkit.org/show_bug.cgi?id=209265
+
+        Reviewed by Andy Estes.
+
+        Modified to no longer use url of image.
+
+        * fast/web-share/share-with-files.html:
+
 2020-05-08  Jason Lawrence  <[email protected]>
 
         REGRESSION [ iOS ] fast/forms/validationMessage.html is flaky and timing out

Modified: trunk/LayoutTests/fast/web-share/share-with-files.html (261411 => 261412)


--- trunk/LayoutTests/fast/web-share/share-with-files.html	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/LayoutTests/fast/web-share/share-with-files.html	2020-05-08 20:46:10 UTC (rev 261412)
@@ -2,6 +2,7 @@
 
 <html>
 <meta name="viewport" content="initial-scale=5, width=device-width">
+
 <head>
 
     <script src=""
@@ -16,10 +17,12 @@
 
         function runTest()
         {
-            const textFile = new File(['hello'], 'hello.txt', {type:'text/plain'});
+
+            var blob = this.response;
+            const textFile = new File(['This is a text file'], 'TextFile.txt', {type:'text/html'});
             document.getElementById("target").addEventListener("click", () => {
-                navigator.share({text: "sadf", files: [textFile]}).then((result) => {
-                    write("PASS: Share sheet invoked.");
+            navigator.share({text: "This is a text file", files: [textFile]}).then((result) => {
+                write("PASS: Share sheet invoked.");
                     testRunner.notifyDone();
                 });    
             });

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (261411 => 261412)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2020-05-08 20:46:10 UTC (rev 261412)
@@ -1,3 +1,15 @@
+2020-05-08  Nikos Mouchtaris  <[email protected]>
+
+        Implement web-share v2 for files
+        https://bugs.webkit.org/show_bug.cgi?id=209265
+
+        Reviewed by Andy Estes.
+
+        Updated test expectations for new behavior.
+
+        * ios-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt :
+        * mac-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt :
+
 2020-05-08  Ryan Haddad  <[email protected]>
 
         Unreviewed, reverting r261341 and r261392.

Modified: trunk/LayoutTests/platform/ios-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt (261411 => 261412)


--- trunk/LayoutTests/platform/ios-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/LayoutTests/platform/ios-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt	2020-05-08 20:46:10 UTC (rev 261412)
@@ -1,8 +1,8 @@
 
 PASS canShare with single file 
 PASS canShare with empty file list 
-FAIL canShare with single file list assert_equals: expected true but got false
-FAIL canShare with file list assert_equals: expected true but got false
-FAIL canShare with repeated file assert_equals: expected true but got false
+PASS canShare with single file list 
+PASS canShare with file list 
+PASS canShare with repeated file 
 PASS canShare with file list and url 
 

Modified: trunk/LayoutTests/platform/mac-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt (261411 => 261412)


--- trunk/LayoutTests/platform/mac-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/LayoutTests/platform/mac-wk2/imported/w3c/web-platform-tests/web-share/canShare-files.https-expected.txt	2020-05-08 20:46:10 UTC (rev 261412)
@@ -1,8 +1,8 @@
 
 PASS canShare with single file 
 PASS canShare with empty file list 
-FAIL canShare with single file list assert_equals: expected true but got false
-FAIL canShare with file list assert_equals: expected true but got false
-FAIL canShare with repeated file assert_equals: expected true but got false
+PASS canShare with single file list 
+PASS canShare with file list 
+PASS canShare with repeated file 
 PASS canShare with file list and url 
 

Modified: trunk/Source/WTF/wtf/PlatformEnable.h (261411 => 261412)


--- trunk/Source/WTF/wtf/PlatformEnable.h	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WTF/wtf/PlatformEnable.h	2020-05-08 20:46:10 UTC (rev 261412)
@@ -547,6 +547,10 @@
 #define ENABLE_DATA_DETECTION 0
 #endif
 
+#if !defined(ENABLE_FILE_SHARE)
+#define ENABLE_FILE_SHARE 1
+#endif
+
 /*
  * Enable this to put each IsoHeap and other allocation categories into their own malloc heaps, so that tools like vmmap can show how big each heap is.
  * Turn BENABLE_MALLOC_HEAP_BREAKDOWN on in bmalloc together when using this.

Modified: trunk/Source/WebCore/ChangeLog (261411 => 261412)


--- trunk/Source/WebCore/ChangeLog	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebCore/ChangeLog	2020-05-08 20:46:10 UTC (rev 261412)
@@ -1,3 +1,34 @@
+2020-05-08  Nikos Mouchtaris  <[email protected]>
+
+        Implement web-share v2 for files
+        https://bugs.webkit.org/show_bug.cgi?id=209265
+
+        Reviewed by Andy Estes.
+
+        Modified existing tests for new behavior.
+
+        Added support for handling of files in share/canShare,
+        and implemented asynchronous reading of data from blobs on
+        disk into memory.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * page/Navigator.cpp:
+        (WebCore::Navigator::canShare):
+        (WebCore::Navigator::share):
+        (WebCore::Navigator::finishedLoad):
+        * page/Navigator.h:
+        * page/ReadShareDataAsync.cpp: Added.
+        (WebCore::ReadShareDataAsync::readInternal):
+        (WebCore::ReadShareDataAsync::ReadShareDataAsync):
+        (WebCore::ReadShareDataAsync::~ReadShareDataAsync):
+        (WebCore::ReadShareDataAsync::start):
+        (WebCore::ReadShareDataAsync::didFinishLoading):
+        (WebCore::ReadShareDataAsync::didReceiveData):
+        (WebCore::ReadShareDataAsync::didStartLoading):
+        (WebCore::ReadShareDataAsync::didFail):
+        * page/ReadShareDataAsync.hpp: Added.
+        * page/ShareData.h:
+
 2020-05-08  Ryan Haddad  <[email protected]>
 
         Unreviewed, reverting r261341 and r261392.

Modified: trunk/Source/WebCore/Sources.txt (261411 => 261412)


--- trunk/Source/WebCore/Sources.txt	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebCore/Sources.txt	2020-05-08 20:46:10 UTC (rev 261412)
@@ -1688,6 +1688,7 @@
 page/SecurityOriginData.cpp
 page/SecurityPolicy.cpp
 page/SettingsBase.cpp
+page/ShareDataReader.cpp
 page/SocketProvider.cpp
 page/SpatialNavigation.cpp
 page/SuspendableTimer.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (261411 => 261412)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-05-08 20:46:10 UTC (rev 261412)
@@ -6175,6 +6175,8 @@
 		1A2A68220B5BEDE70002A480 /* ProgressTracker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ProgressTracker.h; sourceTree = "<group>"; };
 		1A2AAC560DC2A3B100A20D9A /* ApplicationCacheStorage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplicationCacheStorage.cpp; sourceTree = "<group>"; };
 		1A2AAC570DC2A3B100A20D9A /* ApplicationCacheStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplicationCacheStorage.h; sourceTree = "<group>"; };
+		1A2C6671242AFEF7003055EC /* ShareDataReader.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ShareDataReader.cpp; sourceTree = "<group>"; };
+		1A2C6673242AFEF8003055EC /* ShareDataReader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShareDataReader.h; sourceTree = "<group>"; };
 		1A2E6E580CC55213004A2062 /* SQLValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQLValue.h; sourceTree = "<group>"; };
 		1A2E6E780CC556D5004A2062 /* SQLiteAuthorizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SQLiteAuthorizer.cpp; sourceTree = "<group>"; };
 		1A3586DD15264C450022A659 /* RenderMultiColumnFlow.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderMultiColumnFlow.cpp; sourceTree = "<group>"; };
@@ -21167,6 +21169,8 @@
 				7C6EFEEA1F946A2E00FFAD41 /* SettingsDefaultValues.h */,
 				1DC55400211BA8C8004B780E /* ShareData.h */,
 				1DC553FF211BA841004B780E /* ShareData.idl */,
+				1A2C6671242AFEF7003055EC /* ShareDataReader.cpp */,
+				1A2C6673242AFEF8003055EC /* ShareDataReader.h */,
 				5C688AA21D38126F000B54FA /* SocketProvider.cpp */,
 				5C7C88D71D0F1F2B009D2F6D /* SocketProvider.h */,
 				626CDE0C1140424C001E5A68 /* SpatialNavigation.cpp */,

Modified: trunk/Source/WebCore/page/Navigator.cpp (261411 => 261412)


--- trunk/Source/WebCore/page/Navigator.cpp	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebCore/page/Navigator.cpp	2020-05-08 20:46:10 UTC (rev 261412)
@@ -43,6 +43,8 @@
 #include "SecurityOrigin.h"
 #include "Settings.h"
 #include "ShareData.h"
+#include "ShareDataReader.h"
+#include "SharedBuffer.h"
 #include <wtf/IsoMallocInlines.h>
 #include <wtf/Language.h>
 #include <wtf/StdLibExtras.h>
@@ -112,8 +114,13 @@
     if (!frame || !frame->page())
         return false;
     if (data.title.isNull() && data.url.isNull() && data.text.isNull()) {
-        if (!data.files.isEmpty())
+        if (!data.files.isEmpty()) {
+#if ENABLE(FILE_SHARE)
+            return true;
+#else
             return false;
+#endif
+        }
         return false;
     }
 
@@ -139,7 +146,7 @@
     
     auto* window = this->window();
     // Note that the specification does not indicate we should consume user activation. We are intentionally stricter here.
-    if (!window || !window->consumeTransientActivation()) {
+    if (!window || !window->consumeTransientActivation() || m_hasPendingShare) {
         promise->reject(NotAllowedError);
         return;
     }
@@ -147,10 +154,39 @@
     ShareDataWithParsedURL shareData = {
         data,
         url,
+        { },
     };
+#if ENABLE(FILE_SHARE)
+    if (!data.files.isEmpty()) {
+        if (m_loader)
+            m_loader->cancel();
+        
+        m_loader = ShareDataReader::create([this, promise = WTFMove(promise)] (ExceptionOr<ShareDataWithParsedURL&> readData) mutable {
+            showShareData(readData, WTFMove(promise));
+        });
+        m_loader->start(frame()->document(), WTFMove(shareData));
+        return;
+    }
+#endif
+    this->showShareData(shareData, WTFMove(promise));
+}
+
+void Navigator::showShareData(ExceptionOr<ShareDataWithParsedURL&> readData, Ref<DeferredPromise>&& promise)
+{
+    if (readData.hasException()) {
+        promise->reject(readData.releaseException());
+        return;
+    }
     
     auto* frame = this->frame();
-    frame->page()->chrome().showShareSheet(shareData, [promise = WTFMove(promise)] (bool completed) {
+    if (!frame || !frame->page())
+        return;
+    
+    m_hasPendingShare = true;
+    auto shareData = readData.returnValue();
+    
+    frame->page()->chrome().showShareSheet(shareData, [promise = WTFMove(promise), this] (bool completed) {
+        m_hasPendingShare = false;
         if (completed) {
             promise->resolve();
             return;

Modified: trunk/Source/WebCore/page/Navigator.h (261411 => 261412)


--- trunk/Source/WebCore/page/Navigator.h	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebCore/page/Navigator.h	2020-05-08 20:46:10 UTC (rev 261412)
@@ -22,15 +22,17 @@
 #include "DOMWindowProperty.h"
 #include "NavigatorBase.h"
 #include "ScriptWrappable.h"
+#include "ShareData.h"
 #include "Supplementable.h"
 #include <wtf/IsoMalloc.h>
 
 namespace WebCore {
 
+class Blob;
 class DeferredPromise;
 class DOMMimeTypeArray;
 class DOMPluginArray;
-struct ShareData;
+class ShareDataReader;
 
 class Navigator final : public NavigatorBase, public ScriptWrappable, public DOMWindowProperty, public Supplementable<Navigator> {
     WTF_MAKE_ISO_ALLOCATED(Navigator);
@@ -63,12 +65,14 @@
 #endif
 
 private:
+    void showShareData(ExceptionOr<ShareDataWithParsedURL&>, Ref<DeferredPromise>&&);
     explicit Navigator(ScriptExecutionContext*, DOMWindow&);
 
+    mutable RefPtr<ShareDataReader> m_loader;
+    mutable bool m_hasPendingShare { false };
     mutable RefPtr<DOMPluginArray> m_plugins;
     mutable RefPtr<DOMMimeTypeArray> m_mimeTypes;
     mutable String m_userAgent;
     mutable String m_platform;
 };
-
 }

Modified: trunk/Source/WebCore/page/ShareData.h (261411 => 261412)


--- trunk/Source/WebCore/page/ShareData.h	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebCore/page/ShareData.h	2020-05-08 20:46:10 UTC (rev 261412)
@@ -25,6 +25,7 @@
 
 #pragma once
 #include "File.h"
+#include "SharedBuffer.h"
 #include <wtf/URL.h>
 
 namespace WebCore {
@@ -35,10 +36,16 @@
     String url;
     Vector<RefPtr<File>> files;
 };
+
+struct RawFile {
+    String fileName;
+    RefPtr<SharedBuffer> fileData;
+};
     
 struct ShareDataWithParsedURL {
     ShareData shareData;
     Optional<URL> url;
+    Vector<RawFile> files;
 };
     
 }

Added: trunk/Source/WebCore/page/ShareDataReader.cpp (0 => 261412)


--- trunk/Source/WebCore/page/ShareDataReader.cpp	                        (rev 0)
+++ trunk/Source/WebCore/page/ShareDataReader.cpp	2020-05-08 20:46:10 UTC (rev 261412)
@@ -0,0 +1,88 @@
+/*
+* Copyright (C) 2020 Apple Inc. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+* THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+#include "ShareDataReader.h"
+
+#include "BlobLoader.h"
+#include "Document.h"
+#include "SharedBuffer.h"
+
+namespace WebCore {
+
+ShareDataReader::ShareDataReader(CompletionHandler<void(ExceptionOr<ShareDataWithParsedURL&>)>&& completionHandler)
+    : m_completionHandler(WTFMove(completionHandler))
+{
+    
+}
+
+ShareDataReader::~ShareDataReader()
+{
+    cancel();
+}
+
+void ShareDataReader::start(Document* document, ShareDataWithParsedURL&& shareData)
+{
+    m_filesReadSoFar = 0;
+    m_shareData = WTFMove(shareData);
+    int count = 0;
+    m_pendingFileLoads.reserveInitialCapacity(m_shareData.shareData.files.size());
+    for (auto& blob : m_shareData.shareData.files) {
+        m_pendingFileLoads.uncheckedAppend(makeUniqueRef<BlobLoader>(document, *blob, [this, count, fileName = blob->name()] {
+            this->didFinishLoading(count, fileName);
+        }));
+        count++;
+    }
+}
+
+void ShareDataReader::didFinishLoading(int loadIndex, const String& fileName)
+{
+    if (m_pendingFileLoads[loadIndex]->errorCode()) {
+        if (auto completionHandler = std::exchange(m_completionHandler, { }))
+            completionHandler(Exception { AbortError, "Abort due to error while reading files."_s });
+        cancel();
+        return;
+    }
+    
+    auto arrayBuffer = m_pendingFileLoads[loadIndex]->result();
+    
+    RawFile file;
+    file.fileName = fileName;
+    file.fileData = SharedBuffer::create(static_cast<const unsigned char*>(arrayBuffer->data()), arrayBuffer->byteLength());
+    m_shareData.files.append(WTFMove(file));
+    m_filesReadSoFar++;
+    
+    if (m_filesReadSoFar == static_cast<int>(m_pendingFileLoads.size())) {
+        m_pendingFileLoads.clear();
+        if (auto completionHandler = std::exchange(m_completionHandler, { }))
+            completionHandler(m_shareData);
+    }
+}
+
+void ShareDataReader::cancel()
+{
+    m_pendingFileLoads.clear();
+}
+}

Added: trunk/Source/WebCore/page/ShareDataReader.h (0 => 261412)


--- trunk/Source/WebCore/page/ShareDataReader.h	                        (rev 0)
+++ trunk/Source/WebCore/page/ShareDataReader.h	2020-05-08 20:46:10 UTC (rev 261412)
@@ -0,0 +1,56 @@
+/*
+* Copyright (C) 2020 Apple Inc. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+*    notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+*    notice, this list of conditions and the following disclaimer in the
+*    documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+* THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#include "ShareData.h"
+
+#include <wtf/CompletionHandler.h>
+
+namespace WebCore {
+
+class Blob;
+class BlobLoader;
+class Document;
+class ScriptExecutionContext;
+
+class ShareDataReader : public RefCounted<ShareDataReader> {
+public:
+    static Ref<ShareDataReader> create(CompletionHandler<void(ExceptionOr<ShareDataWithParsedURL&>)>&& completionHandler) { return adoptRef(*new ShareDataReader(WTFMove(completionHandler))); }
+    ~ShareDataReader();
+    void start(Document*, ShareDataWithParsedURL&&);
+    void cancel();
+
+private:
+    explicit ShareDataReader(CompletionHandler<void(ExceptionOr<ShareDataWithParsedURL&>)>&&);
+    void didFinishLoading(int, const String& fileName);
+
+    CompletionHandler<void(ExceptionOr<ShareDataWithParsedURL&>)> m_completionHandler;
+    ShareDataWithParsedURL m_shareData;
+    int m_filesReadSoFar;
+    Vector<UniqueRef<BlobLoader>> m_pendingFileLoads;
+};
+
+}

Modified: trunk/Source/WebKit/ChangeLog (261411 => 261412)


--- trunk/Source/WebKit/ChangeLog	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebKit/ChangeLog	2020-05-08 20:46:10 UTC (rev 261412)
@@ -1,3 +1,33 @@
+2020-05-08  Nikos Mouchtaris  <[email protected]>
+
+        Implement web-share v2 for files
+        https://bugs.webkit.org/show_bug.cgi?id=209265
+
+        Reviewed by Andy Estes.
+
+        Added support for passing file objects over IPC and
+        sharing of files to share sheet.
+
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<Vector<RawFile>>::encode):
+        (IPC::ArgumentCoder<Vector<RawFile>>::decode):
+        (IPC::ArgumentCoder<ShareDataWithParsedURL>::encode):
+        (IPC::ArgumentCoder<ShareDataWithParsedURL>::decode):
+        * Shared/WebCoreArgumentCoders.h:
+        * UIProcess/Cocoa/ShareableFileWrite.h: Added.
+        * UIProcess/Cocoa/ShareableFileWrite.mm: Added.
+        (+[WKShareableFileWrite getSharingDirectoryPath]):
+        (+[WKShareableFileWrite getFileDirectoryForSharing]):
+        (+[WKShareableFileWrite removeFileDirectoryForSharing]):
+        (+[WKShareableFileWrite setQuarantineInformationForFilePath:]):
+        (+[WKShareableFileWrite applyQuarantineSandboxAndDownloadFlagsToFileAtPath:]):
+        (+[WKShareableFileWrite createFilename:]):
+        (+[WKShareableFileWrite writeFileToShareableURL:data:]):
+        * UIProcess/Cocoa/WKShareSheet.mm:
+        (-[WKShareSheet presentWithParameters:inRect:completionHandler:]):
+        (-[WKShareSheet _didCompleteWithSuccess:]):
+        * WebKit.xcodeproj/project.pbxproj:
+
 2020-05-08  Brent Fulgham  <[email protected]>
 
         Revise sandbox to stop logging some commonly-used properties 

Modified: trunk/Source/WebKit/Platform/spi/mac/QuarantineSPI.h (261411 => 261412)


--- trunk/Source/WebKit/Platform/spi/mac/QuarantineSPI.h	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebKit/Platform/spi/mac/QuarantineSPI.h	2020-05-08 20:46:10 UTC (rev 261412)
@@ -34,6 +34,7 @@
 #else
 
 enum qtn_flags {
+    QTN_FLAG_DOWNLOAD = 0x0001,
     QTN_FLAG_SANDBOX = 0x0002,
 };
 
@@ -43,10 +44,15 @@
 #define qtn_proc_init _qtn_proc_init
 #define qtn_proc_init_with_self _qtn_proc_init_with_self
 #define qtn_proc_set_flags _qtn_proc_set_flags
-
+#define qtn_file_alloc _qtn_file_alloc
+#define qtn_file_init_with_path _qtn_file_init_with_path
+#define qtn_file_free _qtn_file_free
+#define qtn_file_apply_to_path _qtn_file_apply_to_path
+#define qtn_file_set_flags _qtn_file_set_flags
 #endif
 
 typedef struct _qtn_proc *qtn_proc_t;
+typedef struct _qtn_file *qtn_file_t;
 
 WTF_EXTERN_C_BEGIN
 
@@ -56,6 +62,11 @@
 int qtn_proc_set_flags(qtn_proc_t, uint32_t flags);
 qtn_proc_t qtn_proc_alloc();
 void qtn_proc_free(qtn_proc_t);
+qtn_file_t qtn_file_alloc(void);
+void qtn_file_free(qtn_file_t qf);
+int qtn_file_set_flags(qtn_file_t qf, uint32_t flags);
+int qtn_file_apply_to_path(qtn_file_t qf, const char *path);
+int qtn_file_init_with_path(qtn_file_t qf, const char *path);
 
 WTF_EXTERN_C_END
 

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (261411 => 261412)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2020-05-08 20:46:10 UTC (rev 261412)
@@ -46,6 +46,7 @@
 #include <WebCore/DragData.h>
 #include <WebCore/EventTrackingRegions.h>
 #include <WebCore/FetchOptions.h>
+#include <WebCore/File.h>
 #include <WebCore/FileChooser.h>
 #include <WebCore/FilterOperation.h>
 #include <WebCore/FilterOperations.h>
@@ -2019,6 +2020,21 @@
 
     return true;
 }
+
+void ArgumentCoder<RawFile>::encode(Encoder& encoder, const RawFile& file)
+{
+    encoder << file.fileName;
+    encodeSharedBuffer(encoder, file.fileData.get());
+}
+
+bool ArgumentCoder<RawFile>::decode(Decoder& decoder, RawFile& file)
+{
+    if (!decoder.decode(file.fileName))
+        return false;
+    if (!decodeSharedBuffer(decoder, file.fileData))
+        return false;
+    return true;
+}
     
 void ArgumentCoder<ShareData>::encode(Encoder& encoder, const ShareData& settings)
 {
@@ -2042,6 +2058,7 @@
 {
     encoder << settings.shareData;
     encoder << settings.url;
+    encoder << settings.files;
 }
 
 bool ArgumentCoder<ShareDataWithParsedURL>::decode(Decoder& decoder, ShareDataWithParsedURL& settings)
@@ -2050,6 +2067,8 @@
         return false;
     if (!decoder.decode(settings.url))
         return false;
+    if (!decoder.decode(settings.files))
+        return false;
     return true;
 }
 

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h (261411 => 261412)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h	2020-05-08 20:46:10 UTC (rev 261412)
@@ -81,6 +81,7 @@
 class Cursor;
 class DatabaseDetails;
 class DragData;
+class File;
 class FilterOperation;
 class FilterOperations;
 class FloatPoint;
@@ -126,6 +127,7 @@
 struct ExceptionDetails;
 struct FontAttributes;
 struct FileChooserSettings;
+struct RawFile;
 struct ShareData;
 struct ShareDataWithParsedURL;
 struct Length;
@@ -555,6 +557,11 @@
     static WARN_UNUSED_RETURN bool decode(Decoder&, WebCore::FileChooserSettings&);
 };
     
+template<> struct ArgumentCoder<WebCore::RawFile> {
+    static void encode(Encoder&, const WebCore::RawFile&);
+    static WARN_UNUSED_RETURN bool decode(Decoder&, WebCore::RawFile&);
+};
+
 template<> struct ArgumentCoder<WebCore::ShareData> {
     static void encode(Encoder&, const WebCore::ShareData&);
     static WARN_UNUSED_RETURN bool decode(Decoder&, WebCore::ShareData&);

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WKShareSheet.h (261411 => 261412)


--- trunk/Source/WebKit/UIProcess/Cocoa/WKShareSheet.h	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WKShareSheet.h	2020-05-08 20:46:10 UTC (rev 261412)
@@ -42,7 +42,6 @@
 - (void)dismiss;
 
 @property (nonatomic, weak) id <WKShareSheetDelegate> delegate;
-
 @end
 
 @protocol WKShareSheetDelegate <NSObject>

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WKShareSheet.mm (261411 => 261412)


--- trunk/Source/WebKit/UIProcess/Cocoa/WKShareSheet.mm	2020-05-08 20:43:00 UTC (rev 261411)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WKShareSheet.mm	2020-05-08 20:46:10 UTC (rev 261412)
@@ -28,10 +28,14 @@
 
 #if PLATFORM(COCOA) && !PLATFORM(WATCHOS) && !PLATFORM(APPLETV)
 
+#import "QuarantineSPI.h"
 #import "WKWebViewInternal.h"
 #import "WebPageProxy.h"
+#import <WebCore/RuntimeApplicationChecks.h>
 #import <WebCore/ShareData.h>
 #import <wtf/RetainPtr.h>
+#import <wtf/Scope.h>
+#import <wtf/UUID.h>
 #import <wtf/WeakObjCPtr.h>
 
 #if PLATFORM(IOS_FAMILY)
@@ -47,6 +51,7 @@
 #endif
 
 @implementation WKShareSheet {
+    RetainPtr<NSURL> _temporaryFileShareDirectory;
     WeakObjCPtr<WKWebView> _webView;
     WeakObjCPtr<id <WKShareSheetDelegate> > _delegate;
     WTF::CompletionHandler<void(bool)> _completionHandler;
@@ -106,10 +111,49 @@
         return;
     }
     
+    if (data.files.size()) {
+        _temporaryFileShareDirectory = [WKShareSheet createTemporarySharingDirectory];
+        
+        auto fileWriteGroup = adoptOSObject(dispatch_group_create());
+        auto queue = adoptOSObject(dispatch_queue_create("com.apple.WebKit.WKShareSheet.ShareableFileWriter", DISPATCH_QUEUE_SERIAL));
+        
+        __block bool successful = true;
+        
+        int index = 0;
+        for (auto file : data.files) {
+            dispatch_group_async(fileWriteGroup.get(), queue.get(), ^{
+                if (!successful)
+                    return;
+                NSURL *fileURL = [WKShareSheet writeFileToShareableURL:WebCore::ResourceResponseBase::sanitizeSuggestedFilename(file.fileName) data:file.fileData->createNSData().get() temporaryDirectory:_temporaryFileShareDirectory.get()];
+                if (!fileURL) {
+                    successful = false;
+                    return;
+                }
+                [shareDataArray addObject:fileURL];
+            });
+            index++;
+        }
+        
+        dispatch_group_notify(fileWriteGroup.get(), dispatch_get_main_queue(), ^{
+            if (!successful) {
+                [self _didCompleteWithSuccess:NO];
+                [self dismiss];
+                return;
+            }
+            [self presentWithShareDataArray:shareDataArray.get() inRect:rect];
+        });
+        return;
+    }
+    
+    [self presentWithShareDataArray:shareDataArray.get() inRect:rect];
+}
+
+- (void)presentWithShareDataArray:(NSArray *)sharingItems inRect:(WTF::Optional<WebCore::FloatRect>)rect
+{
     WKWebView *webView = _webView.getAutoreleased();
     
 #if PLATFORM(MAC)
-    _sharingServicePicker = adoptNS([[NSSharingServicePicker alloc] initWithItems:shareDataArray.get()]);
+    _sharingServicePicker = adoptNS([[NSSharingServicePicker alloc] initWithItems:sharingItems]);
     _sharingServicePicker.get().delegate = self;
     
     // WKShareSheet can be released under NSSharingServicePicker delegate callbacks.
@@ -126,7 +170,7 @@
     }
     [_sharingServicePicker showRelativeToRect:presentationRect ofView:webView preferredEdge:NSMinYEdge];
 #else
-    _shareSheetViewController = adoptNS([[UIActivityViewController alloc] initWithActivityItems:shareDataArray.get() applicationActivities:nil]);
+    _shareSheetViewController = adoptNS([[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil]);
     [_shareSheetViewController setCompletionWithItemsHandler:^(NSString *, BOOL completed, NSArray *, NSError *) {
         [self _didCompleteWithSuccess:completed];
         [self dispatchDidDismiss];
@@ -183,6 +227,18 @@
     auto completionHandler = WTFMove(_completionHandler);
     if (completionHandler)
         completionHandler(success);
+    
+    if (success) {
+        // <rdar://problem/63030288>: didShareItems callback for NSSharingServiceDelegate currently is called
+        // before the temporary files are copied, so we can't delete them here. UIActivityViewController doesn't
+        // have this problem, so we can delete immediately for iOS.
+#if PLATFORM(IOS_FAMILY)
+        [[NSFileManager defaultManager] removeItemAtURL:_temporaryFileShareDirectory.get() error:nil];
+#endif
+    } else
+        [[NSFileManager defaultManager] removeItemAtURL:_temporaryFileShareDirectory.get() error:nil];
+
+    _temporaryFileShareDirectory = nullptr;
 }
 
 - (void)dismiss
@@ -215,6 +271,86 @@
         [_delegate shareSheetDidDismiss:self];
 }
 
+#if PLATFORM(MAC)
++ (BOOL)setQuarantineInformationForFilePath:(NSURL *)fileURL
+{
+    auto quarantineProperties = @{
+        (__bridge NSString *)kLSQuarantineTypeKey: (__bridge NSString *)kLSQuarantineTypeWebDownload,
+        (__bridge NSString *)kLSQuarantineAgentBundleIdentifierKey: WebCore::applicationBundleIdentifier()
+    };
+
+    if (![fileURL setResourceValue:quarantineProperties forKey:NSURLQuarantinePropertiesKey error:nil])
+        return NO;
+
+    // Whether the file was downloaded by sandboxed WebProcess or not, LSSetItemAttribute resets the flags to 0 (advisory QTN_FLAG_DOWNLOAD,
+    // which can be then removed by WebProcess). Replace the flags with sandbox quarantine ones, which cannot be removed by sandboxed processes.
+    return [WKShareSheet applyQuarantineSandboxAndDownloadFlagsToFileAtPath:fileURL];
+}
+
++ (BOOL)applyQuarantineSandboxAndDownloadFlagsToFileAtPath:(NSURL *)fileURL
+{
+    qtn_file_t fq = qtn_file_alloc();
+    auto scopeExit = WTF::makeScopeExit([&] {
+        qtn_file_free(fq);
+    });
+    
+    int quarantineError = qtn_file_init_with_path(fq, fileURL.fileSystemRepresentation);
+    if (quarantineError)
+        return NO;
+
+    quarantineError = qtn_file_set_flags(fq, QTN_FLAG_SANDBOX | QTN_FLAG_DOWNLOAD);
+    if (quarantineError)
+        return NO;
+
+    quarantineError = qtn_file_apply_to_path(fq, fileURL.fileSystemRepresentation);
+    
+    return YES;
+}
+#endif
+
++ (NSURL *)createTemporarySharingDirectory
+{
+    NSString *temporaryDirectory = FileSystem::createTemporaryDirectory(@"WKFileShare");
+    
+    if (![temporaryDirectory length])
+        return nil;
+
+    return [NSURL fileURLWithPath:temporaryDirectory isDirectory:YES];
+}
+
++ (NSURL *)createRandomSharingDirectoryForFile:(NSURL *)temporaryDirectory
+{
+    NSString *randomDirectory = createCanonicalUUIDString();
+    if (![randomDirectory length] || !temporaryDirectory)
+        return nil;
+    NSURL *dataPath = [temporaryDirectory URLByAppendingPathComponent:randomDirectory];
+    
+    if (![[NSFileManager defaultManager] createDirectoryAtURL:dataPath withIntermediateDirectories:NO attributes:nil error:nil])
+        return nil;
+    return dataPath;
+}
+
++ (NSURL *)writeFileToShareableURL:(NSString *)fileName data:(NSData *)fileData temporaryDirectory:(NSURL *)temporaryDirectory
+{
+    ASSERT(!RunLoop::isMain());
+    if (!temporaryDirectory || ![fileName length] || !fileData)
+        return nil;
+    
+    NSURL *temporaryDirectoryForFile = [WKShareSheet createRandomSharingDirectoryForFile:temporaryDirectory];
+    if (!temporaryDirectoryForFile)
+        return nil;
+    
+    NSURL *fileURL = [temporaryDirectoryForFile URLByAppendingPathComponent:fileName];
+
+    if (![fileData writeToURL:fileURL options:NSDataWritingAtomic error:nil])
+        return nil;
+#if PLATFORM(MAC)
+    if (![WKShareSheet setQuarantineInformationForFilePath:fileURL])
+        return nil;
+#endif
+    return fileURL;
+}
+
 @end
 
 #endif // PLATFORM(COCOA) && !PLATFORM(WATCHOS) && !PLATFORM(APPLETV)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to