[Attachment Support] Add a way to write blob data to a file URL from the UI process
authorwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Jan 2018 23:48:35 +0000 (23:48 +0000)
committerwenson_hsieh@apple.com <wenson_hsieh@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 5 Jan 2018 23:48:35 +0000 (23:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181236

Reviewed by Brady Eidson.

Source/WebCore:

Add support for writing a blob to a designated file path. See comments below for more detail. No new tests, as
there change in behavior yet. See part 2: https://bugs.webkit.org/show_bug.cgi?id=181199.

* page/DragController.cpp:
(WebCore::DragController::dragAttachmentElement):
* platform/PromisedBlobInfo.h:

Remove PromisedBlobData entirely. This was added with the premise of having the web process deliver blob data to
the UI process. However, the new approach I'm taking just has the UI process tell the network process to write
a blob to a given location, so a data structure to deliver blob data over IPC is no longer necessary.

(WebCore::PromisedBlobData::hasData const): Deleted.
(WebCore::PromisedBlobData::hasFile const): Deleted.
(WebCore::PromisedBlobData::operator bool const): Deleted.
(WebCore::PromisedBlobData::fulfills const): Deleted.
* platform/network/BlobRegistryImpl.cpp:
(WebCore::BlobRegistryImpl::populateBlobsForFileWriting):

Introduce a new helper to build a list of blob data for file writing.

(WebCore::writeFilePathsOrDataBuffersToFile):

Introduce a new static helper to write blob data (a list of file paths and data buffers) to a given file handle.
Automatically closes the given file handle upon exit.

(WebCore::BlobRegistryImpl::writeBlobsToTemporaryFiles):
(WebCore::BlobRegistryImpl::writeBlobToFilePath):

Pull out common logic in writeBlobsToTemporaryFiles and writeBlobToFilePath into helper methods (see above), and
refactor both methods to use the helpers.

* platform/network/BlobRegistryImpl.h:

Source/WebKit:

Add support for writing a blob to a designated file path. In WebKit, this is mainly plumbing writeBlobToFilePath
through WebPageProxy to the network process.

* NetworkProcess/FileAPI/NetworkBlobRegistry.cpp:
(WebKit::NetworkBlobRegistry::writeBlobToFilePath):

Call out to the BlobRegistryImpl to write blobs to the file path. Additionally grant sandbox extensions for any
file-backed blob parts corresponding to the given blob URL.

(WebKit::NetworkBlobRegistry::filesInBlob):

Introduce a version of filesInBlob that doesn't check against the NetworkConnectionToWebProcess. This is used
when the UI process is the driver for writing a blob.

* NetworkProcess/FileAPI/NetworkBlobRegistry.h:
* NetworkProcess/NetworkProcess.cpp:
(WebKit::NetworkProcess::writeBlobToFilePath):

Temporarily grant sandbox access to the given file path.

* NetworkProcess/NetworkProcess.h:
* NetworkProcess/NetworkProcess.messages.in:
* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<PromisedBlobInfo>::encode):
(IPC::ArgumentCoder<PromisedBlobInfo>::decode):
(IPC::ArgumentCoder<PromisedBlobData>::encode): Deleted.
(IPC::ArgumentCoder<PromisedBlobData>::decode): Deleted.

Remove PromisedBlobData (see WebCore/ChangeLog for more information).

* Shared/WebCoreArgumentCoders.h:
* UIProcess/Network/NetworkProcessProxy.cpp:
(WebKit::NetworkProcessProxy::didClose):

If the network process is terminated, flush any pending callbacks in m_writeBlobToFilePathCallbackMap, passing
in a failure result (success := false) and clearing the callback map.

(WebKit::NetworkProcessProxy::writeBlobToFilePath):
(WebKit::NetworkProcessProxy::didWriteBlobToFilePath):
* UIProcess/Network/NetworkProcessProxy.h:
* UIProcess/Network/NetworkProcessProxy.messages.in:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::writeBlobToFilePath):
* UIProcess/WebPageProxy.h:

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

18 files changed:
Source/WebCore/ChangeLog
Source/WebCore/page/DragController.cpp
Source/WebCore/platform/PromisedBlobInfo.h
Source/WebCore/platform/network/BlobRegistryImpl.cpp
Source/WebCore/platform/network/BlobRegistryImpl.h
Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/FileAPI/NetworkBlobRegistry.cpp
Source/WebKit/NetworkProcess/FileAPI/NetworkBlobRegistry.h
Source/WebKit/NetworkProcess/NetworkProcess.cpp
Source/WebKit/NetworkProcess/NetworkProcess.h
Source/WebKit/NetworkProcess/NetworkProcess.messages.in
Source/WebKit/Shared/WebCoreArgumentCoders.cpp
Source/WebKit/Shared/WebCoreArgumentCoders.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp
Source/WebKit/UIProcess/Network/NetworkProcessProxy.h
Source/WebKit/UIProcess/Network/NetworkProcessProxy.messages.in
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h

index 5ca6e54..5d666eb 100644 (file)
@@ -1,3 +1,43 @@
+2018-01-05  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Attachment Support] Add a way to write blob data to a file URL from the UI process
+        https://bugs.webkit.org/show_bug.cgi?id=181236
+
+        Reviewed by Brady Eidson.
+
+        Add support for writing a blob to a designated file path. See comments below for more detail. No new tests, as
+        there change in behavior yet. See part 2: https://bugs.webkit.org/show_bug.cgi?id=181199.
+
+        * page/DragController.cpp:
+        (WebCore::DragController::dragAttachmentElement):
+        * platform/PromisedBlobInfo.h:
+
+        Remove PromisedBlobData entirely. This was added with the premise of having the web process deliver blob data to
+        the UI process. However, the new approach I'm taking just has the UI process tell the network process to write
+        a blob to a given location, so a data structure to deliver blob data over IPC is no longer necessary.
+
+        (WebCore::PromisedBlobData::hasData const): Deleted.
+        (WebCore::PromisedBlobData::hasFile const): Deleted.
+        (WebCore::PromisedBlobData::operator bool const): Deleted.
+        (WebCore::PromisedBlobData::fulfills const): Deleted.
+        * platform/network/BlobRegistryImpl.cpp:
+        (WebCore::BlobRegistryImpl::populateBlobsForFileWriting):
+
+        Introduce a new helper to build a list of blob data for file writing.
+
+        (WebCore::writeFilePathsOrDataBuffersToFile):
+
+        Introduce a new static helper to write blob data (a list of file paths and data buffers) to a given file handle.
+        Automatically closes the given file handle upon exit.
+
+        (WebCore::BlobRegistryImpl::writeBlobsToTemporaryFiles):
+        (WebCore::BlobRegistryImpl::writeBlobToFilePath):
+
+        Pull out common logic in writeBlobsToTemporaryFiles and writeBlobToFilePath into helper methods (see above), and
+        refactor both methods to use the helpers.
+
+        * platform/network/BlobRegistryImpl.h:
+
 2018-01-05  Alex Christensen  <achristensen@webkit.org>
 
         Forbid < and > in URL hosts
index b6ce6a2..55beecb 100644 (file)
@@ -1289,10 +1289,7 @@ bool DragController::dragAttachmentElement(Frame& frame, HTMLAttachmentElement&
 #endif
 
     auto& file = *attachment.file();
-    auto blobURL = file.url().string();
-    bool isFileBacked = !file.path().isEmpty();
-    auto blobType = isFileBacked ? PromisedBlobType::FileBacked : PromisedBlobType::DataBacked;
-    m_client.prepareToDragPromisedBlob({ blobURL, file.type(), file.name(), blobType, additionalTypes, additionalData });
+    m_client.prepareToDragPromisedBlob({ file.url(), file.type(), file.name(), additionalTypes, additionalData });
 
     return true;
 }
index ae846fc..8629ed1 100644 (file)
 
 #pragma once
 
-#include "SharedBuffer.h"
-
 namespace WebCore {
 
-enum class PromisedBlobType { DataBacked, FileBacked };
+class SharedBuffer;
+class URL;
 
 struct PromisedBlobInfo {
-    String blobURL;
+    URL blobURL;
     String contentType;
     String filename;
-    PromisedBlobType blobType;
 
     Vector<String> additionalTypes;
     Vector<RefPtr<SharedBuffer>> additionalData;
@@ -43,29 +41,5 @@ struct PromisedBlobInfo {
     operator bool() const { return !blobURL.isEmpty(); }
 };
 
-struct PromisedBlobData {
-    String blobURL;
-    String filePath;
-    RefPtr<SharedBuffer> data;
-
-    bool hasData() const { return data; }
-    bool hasFile() const { return !filePath.isEmpty(); }
-    operator bool() const { return !blobURL.isEmpty(); }
-    bool fulfills(const PromisedBlobInfo& info) const { return *this && blobURL == info.blobURL; }
-};
-
 } // namespace WebCore
 
-namespace WTF {
-
-template<typename> struct EnumTraits;
-template<typename E, E...> struct EnumValues;
-
-template<> struct EnumTraits<WebCore::PromisedBlobType> {
-    using values = EnumValues<WebCore::PromisedBlobType,
-    WebCore::PromisedBlobType::DataBacked,
-    WebCore::PromisedBlobType::FileBacked
-    >;
-};
-
-} // namespace WTF
index 197eb29..7f79fd1 100644 (file)
@@ -245,24 +245,15 @@ static WorkQueue& blobUtilityQueue()
     return queue;
 }
 
-struct BlobForFileWriting {
-    String blobURL;
-    Vector<std::pair<String, ThreadSafeDataBuffer>> filePathsOrDataBuffers;
-};
-
-void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void (const Vector<String>& filePaths)>&& completionHandler)
+bool BlobRegistryImpl::populateBlobsForFileWriting(const Vector<String>& blobURLs, Vector<BlobForFileWriting>& blobsForWriting)
 {
-    Vector<BlobForFileWriting> blobsForWriting;
     for (auto& url : blobURLs) {
         blobsForWriting.append({ });
         blobsForWriting.last().blobURL = url.isolatedCopy();
 
         auto* blobData = getBlobDataFromURL({ ParsedURLString, url });
-        if (!blobData) {
-            Vector<String> filePaths;
-            completionHandler(filePaths);
-            return;
-        }
+        if (!blobData)
+            return false;
 
         for (auto& item : blobData->items()) {
             switch (item.type()) {
@@ -277,48 +268,57 @@ void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs
             }
         }
     }
+    return true;
+}
 
-    blobUtilityQueue().dispatch([blobsForWriting = WTFMove(blobsForWriting), completionHandler = WTFMove(completionHandler)]() mutable {
-        Vector<String> filePaths;
+static bool writeFilePathsOrDataBuffersToFile(const Vector<std::pair<String, ThreadSafeDataBuffer>>& filePathsOrDataBuffers, FileSystem::PlatformFileHandle file, const String& path)
+{
+    auto fileCloser = WTF::makeScopeExit([file]() mutable {
+        FileSystem::closeFile(file);
+    });
 
-        auto performWriting = [blobsForWriting = WTFMove(blobsForWriting), &filePaths]() {
-            for (auto& blob : blobsForWriting) {
-                FileSystem::PlatformFileHandle file;
-                String tempFilePath = FileSystem::openTemporaryFile(ASCIILiteral("Blob"), file);
-
-                auto fileCloser = WTF::makeScopeExit([file]() mutable {
-                    FileSystem::closeFile(file);
-                });
-                
-                if (tempFilePath.isEmpty() || !FileSystem::isHandleValid(file)) {
-                    LOG_ERROR("Failed to open temporary file for writing a Blob to IndexedDB");
-                    return false;
-                }
-
-                for (auto& part : blob.filePathsOrDataBuffers) {
-                    if (part.second.data()) {
-                        int length = part.second.data()->size();
-                        if (FileSystem::writeToFile(file, reinterpret_cast<const char*>(part.second.data()->data()), length) != length) {
-                            LOG_ERROR("Failed writing a Blob to temporary file for storage in IndexedDB");
-                            return false;
-                        }
-                    } else {
-                        ASSERT(!part.first.isEmpty());
-                        if (!FileSystem::appendFileContentsToFileHandle(part.first, file)) {
-                            LOG_ERROR("Failed copying File contents to a Blob temporary file for storage in IndexedDB (%s to %s)", part.first.utf8().data(), tempFilePath.utf8().data());
-                            return false;
-                        }
-                    }
-                }
-
-                filePaths.append(tempFilePath.isolatedCopy());
+    if (path.isEmpty() || !FileSystem::isHandleValid(file)) {
+        LOG_ERROR("Failed to open temporary file for writing a Blob");
+        return false;
+    }
+
+    for (auto& part : filePathsOrDataBuffers) {
+        if (part.second.data()) {
+            int length = part.second.data()->size();
+            if (FileSystem::writeToFile(file, reinterpret_cast<const char*>(part.second.data()->data()), length) != length) {
+                LOG_ERROR("Failed writing a Blob to temporary file");
+                return false;
             }
+        } else {
+            ASSERT(!part.first.isEmpty());
+            if (!FileSystem::appendFileContentsToFileHandle(part.first, file)) {
+                LOG_ERROR("Failed copying File contents to a Blob temporary file (%s to %s)", part.first.utf8().data(), path.utf8().data());
+                return false;
+            }
+        }
+    }
+    return true;
+}
 
-            return true;
-        };
+void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void(const Vector<String>& filePaths)>&& completionHandler)
+{
+    Vector<BlobForFileWriting> blobsForWriting;
+    if (!populateBlobsForFileWriting(blobURLs, blobsForWriting)) {
+        completionHandler({ });
+        return;
+    }
 
-        if (!performWriting())
-            filePaths.clear();
+    blobUtilityQueue().dispatch([blobsForWriting = WTFMove(blobsForWriting), completionHandler = WTFMove(completionHandler)]() mutable {
+        Vector<String> filePaths;
+        for (auto& blob : blobsForWriting) {
+            FileSystem::PlatformFileHandle file;
+            String tempFilePath = FileSystem::openTemporaryFile(ASCIILiteral("Blob"), file);
+            if (!writeFilePathsOrDataBuffersToFile(blob.filePathsOrDataBuffers, file, tempFilePath)) {
+                filePaths.clear();
+                break;
+            }
+            filePaths.append(tempFilePath.isolatedCopy());
+        }
 
         callOnMainThread([completionHandler = WTFMove(completionHandler), filePaths = WTFMove(filePaths)]() {
             completionHandler(filePaths);
@@ -326,4 +326,20 @@ void BlobRegistryImpl::writeBlobsToTemporaryFiles(const Vector<String>& blobURLs
     });
 }
 
+void BlobRegistryImpl::writeBlobToFilePath(const URL& blobURL, const String& path, Function<void(bool success)>&& completionHandler)
+{
+    Vector<BlobForFileWriting> blobsForWriting;
+    if (!populateBlobsForFileWriting({ blobURL }, blobsForWriting) || blobsForWriting.size() != 1) {
+        completionHandler(false);
+        return;
+    }
+
+    blobUtilityQueue().dispatch([path, blobsForWriting = WTFMove(blobsForWriting), completionHandler = WTFMove(completionHandler)]() mutable {
+        bool success = writeFilePathsOrDataBuffersToFile(blobsForWriting.first().filePathsOrDataBuffers, FileSystem::openFile(path, FileSystem::FileOpenMode::Write), path);
+        callOnMainThread([success, completionHandler = WTFMove(completionHandler)]() {
+            completionHandler(success);
+        });
+    });
+}
+
 } // namespace WebCore
index 09312fa..24fecc9 100644 (file)
@@ -44,6 +44,7 @@ class URL;
 class ResourceHandle;
 class ResourceHandleClient;
 class ResourceRequest;
+class ThreadSafeDataBuffer;
 
 // BlobRegistryImpl is not thread-safe. It should only be called from main thread.
 class WEBCORE_EXPORT BlobRegistryImpl final : public BlobRegistry {
@@ -54,6 +55,7 @@ public:
     BlobData* getBlobDataFromURL(const URL&) const;
 
     Ref<ResourceHandle> createResourceHandle(const ResourceRequest&, ResourceHandleClient*);
+    void writeBlobToFilePath(const URL& blobURL, const String& path, Function<void(bool success)>&& completionHandler);
 
 private:
     void appendStorageItems(BlobData*, const BlobDataItemList&, long long offset, long long length);
@@ -70,6 +72,13 @@ private:
 
     void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void (const Vector<String>& filePaths)>&& completionHandler) override;
 
+    struct BlobForFileWriting {
+        String blobURL;
+        Vector<std::pair<String, ThreadSafeDataBuffer>> filePathsOrDataBuffers;
+    };
+
+    bool populateBlobsForFileWriting(const Vector<String>& blobURLs, Vector<BlobForFileWriting>&);
+
     HashMap<String, RefPtr<BlobData>> m_blobs;
 };
 
index 8196a37..a0d6761 100644 (file)
@@ -1,3 +1,55 @@
+2018-01-05  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        [Attachment Support] Add a way to write blob data to a file URL from the UI process
+        https://bugs.webkit.org/show_bug.cgi?id=181236
+
+        Reviewed by Brady Eidson.
+
+        Add support for writing a blob to a designated file path. In WebKit, this is mainly plumbing writeBlobToFilePath
+        through WebPageProxy to the network process.
+
+        * NetworkProcess/FileAPI/NetworkBlobRegistry.cpp:
+        (WebKit::NetworkBlobRegistry::writeBlobToFilePath):
+
+        Call out to the BlobRegistryImpl to write blobs to the file path. Additionally grant sandbox extensions for any
+        file-backed blob parts corresponding to the given blob URL.
+
+        (WebKit::NetworkBlobRegistry::filesInBlob):
+
+        Introduce a version of filesInBlob that doesn't check against the NetworkConnectionToWebProcess. This is used
+        when the UI process is the driver for writing a blob.
+
+        * NetworkProcess/FileAPI/NetworkBlobRegistry.h:
+        * NetworkProcess/NetworkProcess.cpp:
+        (WebKit::NetworkProcess::writeBlobToFilePath):
+
+        Temporarily grant sandbox access to the given file path.
+
+        * NetworkProcess/NetworkProcess.h:
+        * NetworkProcess/NetworkProcess.messages.in:
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<PromisedBlobInfo>::encode):
+        (IPC::ArgumentCoder<PromisedBlobInfo>::decode):
+        (IPC::ArgumentCoder<PromisedBlobData>::encode): Deleted.
+        (IPC::ArgumentCoder<PromisedBlobData>::decode): Deleted.
+
+        Remove PromisedBlobData (see WebCore/ChangeLog for more information).
+
+        * Shared/WebCoreArgumentCoders.h:
+        * UIProcess/Network/NetworkProcessProxy.cpp:
+        (WebKit::NetworkProcessProxy::didClose):
+
+        If the network process is terminated, flush any pending callbacks in m_writeBlobToFilePathCallbackMap, passing
+        in a failure result (success := false) and clearing the callback map.
+
+        (WebKit::NetworkProcessProxy::writeBlobToFilePath):
+        (WebKit::NetworkProcessProxy::didWriteBlobToFilePath):
+        * UIProcess/Network/NetworkProcessProxy.h:
+        * UIProcess/Network/NetworkProcessProxy.messages.in:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::writeBlobToFilePath):
+        * UIProcess/WebPageProxy.h:
+
 2018-01-05  Dan Bernstein  <mitz@apple.com>
 
         Add injected bundle equivalents of DOMHTMLDocument (DOMHTMLDocumentExtensions)
index 1cd375c..f0824d7 100644 (file)
@@ -140,6 +140,25 @@ void NetworkBlobRegistry::writeBlobsToTemporaryFiles(const Vector<String>& blobU
     blobRegistry().writeBlobsToTemporaryFiles(blobURLs, WTFMove(completionHandler));
 }
 
+void NetworkBlobRegistry::writeBlobToFilePath(const URL& blobURL, const String& path, Function<void(bool success)>&& completionHandler)
+{
+    if (!blobRegistry().isBlobRegistryImpl()) {
+        completionHandler(false);
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    auto blobFiles = filesInBlob({ ParsedURLString, blobURL });
+    for (auto& file : blobFiles)
+        file->prepareForFileAccess();
+
+    static_cast<BlobRegistryImpl&>(blobRegistry()).writeBlobToFilePath(blobURL, path, [blobFiles = WTFMove(blobFiles), completionHandler = WTFMove(completionHandler)] (bool success) {
+        for (auto& file : blobFiles)
+            file->revokeFileAccess();
+        completionHandler(success);
+    });
+}
+
 void NetworkBlobRegistry::connectionToWebProcessDidClose(NetworkConnectionToWebProcess* connection)
 {
     if (!m_blobsForConnection.contains(connection))
@@ -155,12 +174,17 @@ void NetworkBlobRegistry::connectionToWebProcessDidClose(NetworkConnectionToWebP
 Vector<RefPtr<BlobDataFileReference>> NetworkBlobRegistry::filesInBlob(NetworkConnectionToWebProcess& connection, const WebCore::URL& url)
 {
     if (!m_blobsForConnection.contains(&connection) || !m_blobsForConnection.find(&connection)->value.contains(url))
-        return Vector<RefPtr<BlobDataFileReference>>();
+        return { };
 
+    return filesInBlob(url);
+}
+
+Vector<RefPtr<BlobDataFileReference>> NetworkBlobRegistry::filesInBlob(const URL& url)
+{
     ASSERT(blobRegistry().isBlobRegistryImpl());
     BlobData* blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(url);
     if (!blobData)
-        return Vector<RefPtr<BlobDataFileReference>>();
+        return { };
 
     Vector<RefPtr<BlobDataFileReference>> result;
     for (const BlobDataItem& item : blobData->items()) {
index 78dbd35..c19a659 100644 (file)
@@ -54,10 +54,12 @@ public:
     void unregisterBlobURL(NetworkConnectionToWebProcess*, const WebCore::URL&);
     uint64_t blobSize(NetworkConnectionToWebProcess*, const WebCore::URL&);
     void writeBlobsToTemporaryFiles(const Vector<String>& blobURLs, Function<void (const Vector<String>&)>&& completionHandler);
+    void writeBlobToFilePath(const WebCore::URL& blobURL, const String& path, Function<void(bool success)>&& completionHandler);
 
     void connectionToWebProcessDidClose(NetworkConnectionToWebProcess*);
 
     Vector<RefPtr<WebCore::BlobDataFileReference>> filesInBlob(NetworkConnectionToWebProcess&, const WebCore::URL&);
+    Vector<RefPtr<WebCore::BlobDataFileReference>> filesInBlob(const WebCore::URL&);
 
 private:
     ~NetworkBlobRegistry();
index 5a1b3ac..ae4f955 100644 (file)
@@ -36,6 +36,7 @@
 #include "LegacyCustomProtocolManager.h"
 #endif
 #include "Logging.h"
+#include "NetworkBlobRegistry.h"
 #include "NetworkConnectionToWebProcess.h"
 #include "NetworkProcessCreationParameters.h"
 #include "NetworkProcessPlatformStrategies.h"
@@ -332,6 +333,21 @@ void NetworkProcess::didGrantSandboxExtensionsToStorageProcessForBlobs(uint64_t
         handler();
 }
 
+void NetworkProcess::writeBlobToFilePath(const WebCore::URL& url, const String& path, SandboxExtension::Handle&& handleForWriting, uint64_t requestID)
+{
+    auto extension = SandboxExtension::create(WTFMove(handleForWriting));
+    if (!extension) {
+        parentProcessConnection()->send(Messages::NetworkProcessProxy::DidWriteBlobToFilePath(false, requestID), 0);
+        return;
+    }
+
+    extension->consume();
+    NetworkBlobRegistry::singleton().writeBlobToFilePath(url, path, [this, extension = WTFMove(extension), requestID] (bool success) {
+        extension->revoke();
+        parentProcessConnection()->send(Messages::NetworkProcessProxy::DidWriteBlobToFilePath(success, requestID), 0);
+    });
+}
+
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
 void NetworkProcess::updatePrevalentDomainsToPartitionOrBlockCookies(PAL::SessionID sessionID, const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, bool shouldClearFirst)
 {
index ce7ec55..dd14913 100644 (file)
@@ -225,6 +225,8 @@ private:
 
     void didGrantSandboxExtensionsToStorageProcessForBlobs(uint64_t requestID);
 
+    void writeBlobToFilePath(const WebCore::URL&, const String& path, SandboxExtension::Handle&&, uint64_t requestID);
+
 #if USE(SOUP)
     void setIgnoreTLSErrors(bool);
     void userPreferredLanguagesChanged(const Vector<String>&);
index 8b855f0..bd48b91 100644 (file)
@@ -79,6 +79,8 @@ messages -> NetworkProcess LegacyReceiver {
 
     DidGrantSandboxExtensionsToStorageProcessForBlobs(uint64_t requestID)
 
+    WriteBlobToFilePath(WebCore::URL blobURL, String path, WebKit::SandboxExtension::Handle handle, uint64_t callbackID)
+
     PreconnectTo(WebCore::URL url, enum WebCore::StoredCredentialsPolicy storedCredentialsPolicy);
 
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
index b565ecb..81c4e0f 100644 (file)
@@ -2746,33 +2746,11 @@ std::optional<MediaSelectionOption> ArgumentCoder<MediaSelectionOption>::decode(
     return {{ WTFMove(*displayName), WTFMove(*type) }};
 }
 
-void ArgumentCoder<PromisedBlobData>::encode(Encoder& encoder, const PromisedBlobData& data)
-{
-    encoder << data.blobURL;
-    encoder << data.filePath;
-    encodeSharedBuffer(encoder, data.data.get());
-}
-
-bool ArgumentCoder<PromisedBlobData>::decode(Decoder& decoder, PromisedBlobData& data)
-{
-    if (!decoder.decode(data.blobURL))
-        return false;
-
-    if (!decoder.decode(data.filePath))
-        return false;
-
-    if (!decodeSharedBuffer(decoder, data.data))
-        return false;
-
-    return true;
-}
-
 void ArgumentCoder<PromisedBlobInfo>::encode(Encoder& encoder, const PromisedBlobInfo& info)
 {
     encoder << info.blobURL;
     encoder << info.contentType;
     encoder << info.filename;
-    encoder.encodeEnum(info.blobType);
     encodeTypesAndData(encoder, info.additionalTypes, info.additionalData);
 }
 
@@ -2787,9 +2765,6 @@ bool ArgumentCoder<PromisedBlobInfo>::decode(Decoder& decoder, PromisedBlobInfo&
     if (!decoder.decode(info.filename))
         return false;
 
-    if (!decoder.decode(info.blobType))
-        return false;
-
     if (!decodeTypesAndData(decoder, info.additionalTypes, info.additionalData))
         return false;
 
index 8c69d1f..f53ded2 100644 (file)
@@ -103,7 +103,6 @@ struct PasteboardImage;
 struct PasteboardCustomData;
 struct PasteboardURL;
 struct PluginInfo;
-struct PromisedBlobData;
 struct PromisedBlobInfo;
 struct RecentSearch;
 struct ResourceLoadStatistics;
@@ -685,11 +684,6 @@ template<> struct ArgumentCoder<WebCore::MediaSelectionOption> {
     static std::optional<WebCore::MediaSelectionOption> decode(Decoder&);
 };
 
-template<> struct ArgumentCoder<WebCore::PromisedBlobData> {
-    static void encode(Encoder&, const WebCore::PromisedBlobData&);
-    static bool decode(Decoder&, WebCore::PromisedBlobData&);
-};
-
 template<> struct ArgumentCoder<WebCore::PromisedBlobInfo> {
     static void encode(Encoder&, const WebCore::PromisedBlobInfo&);
     static bool decode(Decoder&, WebCore::PromisedBlobInfo&);
index 3455a3f..4d643d5 100644 (file)
@@ -245,6 +245,10 @@ void NetworkProcessProxy::didClose(IPC::Connection&)
 
     m_tokenForHoldingLockedFiles = nullptr;
 
+    for (auto& callback : m_writeBlobToFilePathCallbackMap.values())
+        callback(false);
+    m_writeBlobToFilePathCallbackMap.clear();
+
     // This may cause us to be deleted.
     networkProcessCrashed();
 }
@@ -458,6 +462,30 @@ void NetworkProcessProxy::sendProcessDidResume()
         send(Messages::NetworkProcess::ProcessDidResume(), 0);
 }
 
+void NetworkProcessProxy::writeBlobToFilePath(const WebCore::URL& url, const String& path, CompletionHandler<void(bool)>&& callback)
+{
+    if (!canSendMessage()) {
+        callback(false);
+        return;
+    }
+
+    static uint64_t writeBlobToFilePathCallbackIdentifiers = 0;
+    uint64_t callbackID = ++writeBlobToFilePathCallbackIdentifiers;
+    m_writeBlobToFilePathCallbackMap.add(callbackID, WTFMove(callback));
+
+    SandboxExtension::Handle handleForWriting;
+    SandboxExtension::createHandle(path, SandboxExtension::Type::ReadWrite, handleForWriting);
+    send(Messages::NetworkProcess::WriteBlobToFilePath(url, path, handleForWriting, callbackID), 0);
+}
+
+void NetworkProcessProxy::didWriteBlobToFilePath(bool success, uint64_t callbackID)
+{
+    if (auto handler = m_writeBlobToFilePathCallbackMap.take(callbackID))
+        handler(success);
+    else
+        ASSERT_NOT_REACHED();
+}
+
 void NetworkProcessProxy::processReadyToSuspend()
 {
     m_throttler.processReadyToSuspend();
index e1bfb76..db875cc 100644 (file)
@@ -47,6 +47,7 @@ class ProtectionSpace;
 class ResourceRequest;
 enum class ShouldSample;
 class SecurityOrigin;
+class URL;
 struct SecurityOriginData;
 }
 
@@ -82,6 +83,8 @@ public:
     void updateStorageAccessForPrevalentDomains(PAL::SessionID, const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, bool value, CompletionHandler<void(bool)>&& callback);
 #endif
 
+    void writeBlobToFilePath(const WebCore::URL&, const String& path, CompletionHandler<void(bool)>&& callback);
+
     void processReadyToSuspend();
 
     void setIsHoldingLockedFiles(bool);
@@ -121,6 +124,7 @@ private:
     void didFetchWebsiteData(uint64_t callbackID, const WebsiteData&);
     void didDeleteWebsiteData(uint64_t callbackID);
     void didDeleteWebsiteDataForOrigins(uint64_t callbackID);
+    void didWriteBlobToFilePath(bool success, uint64_t callbackID);
     void grantSandboxExtensionsToStorageProcessForBlobs(uint64_t requestID, const Vector<String>& paths);
     void logDiagnosticMessage(uint64_t pageID, const String& message, const String& description, WebCore::ShouldSample);
     void logDiagnosticMessageWithResult(uint64_t pageID, const String& message, const String& description, uint32_t result, WebCore::ShouldSample);
@@ -151,6 +155,7 @@ private:
     ProcessThrottler m_throttler;
     ProcessThrottler::BackgroundActivityToken m_tokenForHoldingLockedFiles;
 
+    HashMap<uint64_t, CompletionHandler<void(bool success)>> m_writeBlobToFilePathCallbackMap;
     HashMap<uint64_t, WTF::CompletionHandler<void(bool wasGranted)>> m_storageAccessResponseCallbackMap;
 };
 
index fa81b41..7f773ac 100644 (file)
@@ -29,6 +29,8 @@ messages -> NetworkProcessProxy LegacyReceiver {
     DidDeleteWebsiteData(uint64_t callbackID)
     DidDeleteWebsiteDataForOrigins(uint64_t callbackID)
 
+    DidWriteBlobToFilePath(bool success, uint64_t callbackID)
+
     GrantSandboxExtensionsToStorageProcessForBlobs(uint64_t requestID, Vector<String> paths)
 
     ProcessReadyToSuspend()
index 84dd857..e10a2eb 100644 (file)
@@ -67,6 +67,7 @@
 #include "NativeWebWheelEvent.h"
 #include "NavigationActionData.h"
 #include "NetworkProcessMessages.h"
+#include "NetworkProcessProxy.h"
 #include "NotificationPermissionRequest.h"
 #include "NotificationPermissionRequestManager.h"
 #include "OptionalCallbackID.h"
@@ -7281,6 +7282,16 @@ void WebPageProxy::didRemoveAttachment(const String& identifier)
 
 #endif // ENABLE(ATTACHMENT_ELEMENT)
 
+void WebPageProxy::writeBlobToFilePath(const URL& url, const String& path, Function<void(bool success)>&& callback)
+{
+    if (!isValid()) {
+        callback(false);
+        return;
+    }
+
+    m_process->processPool().ensureNetworkProcess().writeBlobToFilePath(url, path, WTFMove(callback));
+}
+
 #if ENABLE(APPLICATION_MANIFEST)
 void WebPageProxy::getApplicationManifest(Function<void(const std::optional<WebCore::ApplicationManifest>&, CallbackBase::Error)>&& callbackFunction)
 {
index 1891110..3d2a7c7 100644 (file)
@@ -1262,6 +1262,8 @@ public:
     void getApplicationManifest(Function<void(const std::optional<WebCore::ApplicationManifest>&, CallbackBase::Error)>&&);
 #endif
 
+    void writeBlobToFilePath(const WebCore::URL& blobURL, const String& path, Function<void(bool success)>&&);
+
     WebPreferencesStore preferencesStore() const;
 
 private: