Title: [248139] trunk
Revision
248139
Author
[email protected]
Date
2019-08-01 15:29:52 -0700 (Thu, 01 Aug 2019)

Log Message

Move FormData zip file generation to NetworkProcess and enable it for all WebKit clients for uploading directories
https://bugs.webkit.org/show_bug.cgi?id=200102
<rdar://problem/53275114>

Patch by Alex Christensen <[email protected]> on 2019-08-01
Reviewed by Darin Adler.

Source/WebCore:

To enable directory uploading in WebKit2, we extended WebKit1's model of asking the application to generate a file for uploading.
This means the WebProcess needed access to everything necessary to zip a whole directory, and clients that have not implemented
the strange WKBundlePageUIClient callbacks won't be able to upload directories.  Safari's implementation had already been copied
to BlobDataFileReference::generateReplacementFile, so I reused that code to do the zipping.  Instead of a complicated model of
keeping track of a filename, possibly a generated filename, and whether we think we own the file or not and having nobody clean up,
we now do the generation, use, and cleaning up in the network process starting with a new function generateFilesForUpload.
This removes unimplemented SPI in WebUIDelegatePrivate in WebKitLegacy and stops calling the WKBundlePageUIClient related to upload
file generation and replaces them with automatic behavior equivalent to Safari's implementation of the WKBundlePageUIClient calls.
Since we no longer need to do these file operations in the WebProcess, I am also reverting r245322 and r246077 which tightens the sandbox.

Covered by an API test.

* Modules/fetch/FetchBody.cpp:
(WebCore::FetchBody::extract):
(WebCore::FetchBody::bodyAsFormData const):
* loader/FormSubmission.cpp:
(WebCore::FormSubmission::create):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::submitForm):
(WebCore::FrameLoader::loadDifferentDocumentItem):
* loader/ResourceLoader.cpp:
(WebCore::ResourceLoader::didReceiveResponse):
(WebCore::ResourceLoader::cleanupForError):
* page/Chrome.cpp:
(WebCore::ChromeClient::shouldReplaceWithGeneratedFileForUpload): Deleted.
(WebCore::ChromeClient::generateReplacementFile): Deleted.
* page/ChromeClient.h:
* platform/network/FormData.cpp:
(WebCore::FormData::FormData):
(WebCore::FormData::~FormData):
(WebCore::FormData::createMultiPart):
(WebCore::FormDataElement::lengthInBytes const):
(WebCore::FormData::appendFile):
(WebCore::FormData::appendFileRange):
(WebCore::FormData::appendMultiPartFileValue):
(WebCore::FormData::appendMultiPartKeyValuePairItems):
(WebCore::FormData::resolveBlobReferences):
(WebCore::generateFileForUpload):
(WebCore::FormData::generateFilesForUpload):
(WebCore::FormData::generateFiles): Deleted.
(WebCore::FormData::hasGeneratedFiles const): Deleted.
(WebCore::FormData::hasOwnedGeneratedFiles const): Deleted.
(WebCore::FormData::removeGeneratedFilesIfNeeded): Deleted.
* platform/network/FormData.h:
(WebCore::FormDataElement::FormDataElement):
(WebCore::FormDataElement::EncodedFileData::isolatedCopy const):
(WebCore::FormDataElement::EncodedFileData::operator== const):
(WebCore::FormDataElement::EncodedFileData::encode const):
(WebCore::FormDataElement::EncodedFileData::decode):
* platform/network/cf/FormDataStreamCFNet.cpp:
(WebCore::advanceCurrentStream):
(WebCore::formCreate):
(WebCore::formFinalize):
(WebCore::createHTTPBodyCFReadStream):
* platform/network/mac/BlobDataFileReferenceMac.mm:
(WebCore::generateFileForUpload):
(WebCore::BlobDataFileReference::generateReplacementFile):
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::send):

Source/WebKit:

* NetworkProcess/NetworkResourceLoadParameters.cpp:
(WebKit::NetworkResourceLoadParameters::encode const):
* Platform/IPC/FormDataReference.h:
(IPC::FormDataReference::encode const):
* Resources/SandboxProfiles/ios/com.apple.WebKit.Networking.sb:
* WebProcess/InjectedBundle/API/APIInjectedBundlePageUIClient.h:
(API::InjectedBundle::PageUIClient::shouldGenerateFileForUpload): Deleted.
(API::InjectedBundle::PageUIClient::generateFileForUpload): Deleted.
* WebProcess/InjectedBundle/InjectedBundlePageUIClient.cpp:
(WebKit::InjectedBundlePageUIClient::shouldGenerateFileForUpload): Deleted.
(WebKit::InjectedBundlePageUIClient::generateFileForUpload): Deleted.
* WebProcess/InjectedBundle/InjectedBundlePageUIClient.h:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::shouldReplaceWithGeneratedFileForUpload): Deleted.
(WebKit::WebChromeClient::generateReplacementFile): Deleted.
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/com.apple.WebProcess.sb.in:

Source/WebKitLegacy/mac:

* DefaultDelegates/WebDefaultUIDelegate.mm:
(-[WebDefaultUIDelegate webView:shouldReplaceUploadFile:usingGeneratedFilename:]): Deleted.
(-[WebDefaultUIDelegate webView:generateReplacementFile:]): Deleted.
* WebCoreSupport/WebChromeClient.h:
* WebCoreSupport/WebChromeClient.mm:
(WebChromeClient::shouldReplaceWithGeneratedFileForUpload): Deleted.
(WebChromeClient::generateReplacementFile): Deleted.
* WebView/WebUIDelegatePrivate.h:

Source/WTF:

Move code from BlobDataFileReference::generateReplacementFile to FileSystem::createZipArchive.

* wtf/FileSystem.cpp:
(WTF::FileSystemImpl::createZipArchive):
* wtf/FileSystem.h:
* wtf/cocoa/FileSystemCocoa.mm:
(WTF::FileSystemImpl::createZipArchive):

Tools:

Add an API test that is Mac-only right now because runOpenPanelWithParameters is only supported on Mac for some reason
and because clicking on a TestWKWebView only works on Mac.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/UploadDirectory.mm: Added.
(-[UploadDelegate initWithDirectory:]):
(-[UploadDelegate webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:]):
(-[UploadDelegate sentDirectory]):
(TEST):
* TestWebKitAPI/cocoa/TestWKWebView.h:
* TestWebKitAPI/cocoa/TestWKWebView.mm:
(-[TestWKWebView sendClickAtPoint:]):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (248138 => 248139)


--- trunk/Source/WTF/ChangeLog	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WTF/ChangeLog	2019-08-01 22:29:52 UTC (rev 248139)
@@ -1,3 +1,19 @@
+2019-08-01  Alex Christensen  <[email protected]>
+
+        Move FormData zip file generation to NetworkProcess and enable it for all WebKit clients for uploading directories
+        https://bugs.webkit.org/show_bug.cgi?id=200102
+        <rdar://problem/53275114>
+
+        Reviewed by Darin Adler.
+
+        Move code from BlobDataFileReference::generateReplacementFile to FileSystem::createZipArchive.
+
+        * wtf/FileSystem.cpp:
+        (WTF::FileSystemImpl::createZipArchive):
+        * wtf/FileSystem.h:
+        * wtf/cocoa/FileSystemCocoa.mm:
+        (WTF::FileSystemImpl::createZipArchive):
+
 2019-08-01  Per Arne Vollan  <[email protected]>
 
         Initialize memory pressure flag in MemoryPressureHandler

Modified: trunk/Source/WTF/wtf/FileSystem.cpp (248138 => 248139)


--- trunk/Source/WTF/wtf/FileSystem.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WTF/wtf/FileSystem.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -385,5 +385,12 @@
 }
 #endif
 
+#if !PLATFORM(COCOA)
+String createTemporaryZipArchive(const String& directory)
+{
+    return { };
+}
+#endif
+
 } // namespace FileSystemImpl
 } // namespace WTF

Modified: trunk/Source/WTF/wtf/FileSystem.h (248138 => 248139)


--- trunk/Source/WTF/wtf/FileSystem.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WTF/wtf/FileSystem.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -124,6 +124,7 @@
 WTF_EXPORT_PRIVATE bool getVolumeFreeSpace(const String&, uint64_t&);
 WTF_EXPORT_PRIVATE Optional<int32_t> getFileDeviceId(const CString&);
 WTF_EXPORT_PRIVATE bool createSymbolicLink(const String& targetPath, const String& symbolicLinkPath);
+WTF_EXPORT_PRIVATE String createTemporaryZipArchive(const String& directory);
 
 WTF_EXPORT_PRIVATE void setMetadataURL(const String& path, const String& urlString, const String& referrer = { });
 

Modified: trunk/Source/WTF/wtf/cocoa/FileSystemCocoa.mm (248138 => 248139)


--- trunk/Source/WTF/wtf/cocoa/FileSystemCocoa.mm	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WTF/wtf/cocoa/FileSystemCocoa.mm	2019-08-01 22:29:52 UTC (rev 248139)
@@ -29,6 +29,24 @@
 #import "config.h"
 #import <wtf/FileSystem.h>
 
+#include <wtf/SoftLinking.h>
+
+#if USE(APPLE_INTERNAL_SDK)
+#include <Bom/BOMCopier.h>
+#endif
+
+typedef struct _BOMCopier* BOMCopier;
+
+SOFT_LINK_PRIVATE_FRAMEWORK(Bom)
+SOFT_LINK(Bom, BOMCopierNew, BOMCopier, (), ())
+SOFT_LINK(Bom, BOMCopierFree, void, (BOMCopier copier), (copier))
+SOFT_LINK(Bom, BOMCopierCopyWithOptions, int, (BOMCopier copier, const char* fromObj, const char* toObj, CFDictionaryRef options), (copier, fromObj, toObj, options))
+
+#define kBOMCopierOptionCreatePKZipKey CFSTR("createPKZip")
+#define kBOMCopierOptionSequesterResourcesKey CFSTR("sequesterResources")
+#define kBOMCopierOptionKeepParentKey CFSTR("keepParent")
+#define kBOMCopierOptionCopyResourcesKey CFSTR("copyResources")
+
 @interface WTFWebFileManagerDelegate : NSObject <NSFileManagerDelegate>
 @end
 
@@ -48,6 +66,32 @@
 
 namespace FileSystemImpl {
 
+String createTemporaryZipArchive(const String& path)
+{
+    String temporaryFile;
+    
+    RetainPtr<NSFileCoordinator> coordinator = adoptNS([[NSFileCoordinator alloc] initWithFilePresenter:nil]);
+    [coordinator coordinateReadingItemAtURL:[NSURL fileURLWithPath:path] options:NSFileCoordinatorReadingWithoutChanges error:nullptr byAccessor:[&](NSURL *newURL) mutable {
+        CString archivePath([NSTemporaryDirectory() stringByAppendingPathComponent:@"WebKitGeneratedFileXXXXXX"].fileSystemRepresentation);
+        if (mkstemp(archivePath.mutableData()) == -1)
+            return;
+        
+        NSDictionary *options = @{
+            (__bridge id)kBOMCopierOptionCreatePKZipKey : @YES,
+            (__bridge id)kBOMCopierOptionSequesterResourcesKey : @YES,
+            (__bridge id)kBOMCopierOptionKeepParentKey : @YES,
+            (__bridge id)kBOMCopierOptionCopyResourcesKey : @YES,
+        };
+        
+        BOMCopier copier = BOMCopierNew();
+        if (!BOMCopierCopyWithOptions(copier, newURL.path.fileSystemRepresentation, archivePath.data(), (__bridge CFDictionaryRef)options))
+            temporaryFile = String::fromUTF8(archivePath);
+        BOMCopierFree(copier);
+    }];
+    
+    return temporaryFile;
+}
+
 String homeDirectoryPath()
 {
     return NSHomeDirectory();

Modified: trunk/Source/WebCore/ChangeLog (248138 => 248139)


--- trunk/Source/WebCore/ChangeLog	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/ChangeLog	2019-08-01 22:29:52 UTC (rev 248139)
@@ -1,3 +1,71 @@
+2019-08-01  Alex Christensen  <[email protected]>
+
+        Move FormData zip file generation to NetworkProcess and enable it for all WebKit clients for uploading directories
+        https://bugs.webkit.org/show_bug.cgi?id=200102
+        <rdar://problem/53275114>
+
+        Reviewed by Darin Adler.
+
+        To enable directory uploading in WebKit2, we extended WebKit1's model of asking the application to generate a file for uploading.
+        This means the WebProcess needed access to everything necessary to zip a whole directory, and clients that have not implemented
+        the strange WKBundlePageUIClient callbacks won't be able to upload directories.  Safari's implementation had already been copied
+        to BlobDataFileReference::generateReplacementFile, so I reused that code to do the zipping.  Instead of a complicated model of
+        keeping track of a filename, possibly a generated filename, and whether we think we own the file or not and having nobody clean up,
+        we now do the generation, use, and cleaning up in the network process starting with a new function generateFilesForUpload.
+        This removes unimplemented SPI in WebUIDelegatePrivate in WebKitLegacy and stops calling the WKBundlePageUIClient related to upload
+        file generation and replaces them with automatic behavior equivalent to Safari's implementation of the WKBundlePageUIClient calls.
+        Since we no longer need to do these file operations in the WebProcess, I am also reverting r245322 and r246077 which tightens the sandbox.
+
+        Covered by an API test.
+
+        * Modules/fetch/FetchBody.cpp:
+        (WebCore::FetchBody::extract):
+        (WebCore::FetchBody::bodyAsFormData const):
+        * loader/FormSubmission.cpp:
+        (WebCore::FormSubmission::create):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::submitForm):
+        (WebCore::FrameLoader::loadDifferentDocumentItem):
+        * loader/ResourceLoader.cpp:
+        (WebCore::ResourceLoader::didReceiveResponse):
+        (WebCore::ResourceLoader::cleanupForError):
+        * page/Chrome.cpp:
+        (WebCore::ChromeClient::shouldReplaceWithGeneratedFileForUpload): Deleted.
+        (WebCore::ChromeClient::generateReplacementFile): Deleted.
+        * page/ChromeClient.h:
+        * platform/network/FormData.cpp:
+        (WebCore::FormData::FormData):
+        (WebCore::FormData::~FormData):
+        (WebCore::FormData::createMultiPart):
+        (WebCore::FormDataElement::lengthInBytes const):
+        (WebCore::FormData::appendFile):
+        (WebCore::FormData::appendFileRange):
+        (WebCore::FormData::appendMultiPartFileValue):
+        (WebCore::FormData::appendMultiPartKeyValuePairItems):
+        (WebCore::FormData::resolveBlobReferences):
+        (WebCore::generateFileForUpload):
+        (WebCore::FormData::generateFilesForUpload):
+        (WebCore::FormData::generateFiles): Deleted.
+        (WebCore::FormData::hasGeneratedFiles const): Deleted.
+        (WebCore::FormData::hasOwnedGeneratedFiles const): Deleted.
+        (WebCore::FormData::removeGeneratedFilesIfNeeded): Deleted.
+        * platform/network/FormData.h:
+        (WebCore::FormDataElement::FormDataElement):
+        (WebCore::FormDataElement::EncodedFileData::isolatedCopy const):
+        (WebCore::FormDataElement::EncodedFileData::operator== const):
+        (WebCore::FormDataElement::EncodedFileData::encode const):
+        (WebCore::FormDataElement::EncodedFileData::decode):
+        * platform/network/cf/FormDataStreamCFNet.cpp:
+        (WebCore::advanceCurrentStream):
+        (WebCore::formCreate):
+        (WebCore::formFinalize):
+        (WebCore::createHTTPBodyCFReadStream):
+        * platform/network/mac/BlobDataFileReferenceMac.mm:
+        (WebCore::generateFileForUpload):
+        (WebCore::BlobDataFileReference::generateReplacementFile):
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::send):
+
 2019-08-01  Wenson Hsieh  <[email protected]>
 
         [Text autosizing] [iPadOS] Add targeted hacks to address some remaining text autosizing issues

Modified: trunk/Source/WebCore/Modules/fetch/FetchBody.cpp (248138 => 248139)


--- trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/Modules/fetch/FetchBody.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -40,7 +40,7 @@
 
 namespace WebCore {
 
-FetchBody FetchBody::extract(ScriptExecutionContext& context, Init&& value, String& contentType)
+FetchBody FetchBody::extract(ScriptExecutionContext&, Init&& value, String& contentType)
 {
     return WTF::switchOn(value, [&](RefPtr<Blob>& value) mutable {
         Ref<const Blob> blob = value.releaseNonNull();
@@ -49,7 +49,7 @@
         return FetchBody(WTFMove(blob));
     }, [&](RefPtr<DOMFormData>& value) mutable {
         Ref<DOMFormData> domFormData = value.releaseNonNull();
-        auto formData = FormData::createMultiPart(domFormData.get(), &downcast<Document>(context));
+        auto formData = FormData::createMultiPart(domFormData.get());
         contentType = makeString("multipart/form-data; boundary=", formData->boundary().data());
         return FetchBody(WTFMove(formData));
     }, [&](RefPtr<URLSearchParams>& value) mutable {
@@ -250,9 +250,8 @@
     if (isArrayBufferView())
         return FormData::create(arrayBufferViewBody().baseAddress(), arrayBufferViewBody().byteLength());
     if (isFormData()) {
-        ASSERT(!context.isWorkerGlobalScope());
+        ASSERT_UNUSED(context, !context.isWorkerGlobalScope());
         auto body = makeRef(const_cast<FormData&>(formDataBody()));
-        body->generateFiles(&downcast<Document>(context));
         return body;
     }
     if (auto* data = ""

Modified: trunk/Source/WebCore/loader/FormSubmission.cpp (248138 => 248139)


--- trunk/Source/WebCore/loader/FormSubmission.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/loader/FormSubmission.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -198,7 +198,7 @@
     String boundary;
 
     if (isMultiPartForm) {
-        formData = FormData::createMultiPart(domFormData, &document);
+        formData = FormData::createMultiPart(domFormData);
         boundary = formData->boundary().data();
     } else {
         formData = FormData::create(domFormData, attributes.method() == Method::Get ? FormData::FormURLEncoded : FormData::parseEncodingType(encodingType));

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (248138 => 248139)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -473,7 +473,6 @@
         m_submittedFormURL = submission->requestURL();
     }
 
-    submission->data().generateFiles(m_frame.document());
     submission->setReferrer(outgoingReferrer());
     submission->setOrigin(outgoingOrigin());
 
@@ -3773,8 +3772,6 @@
     // If this was a repost that failed the page cache, we might try to repost the form.
     NavigationAction action;
     if (formData) {
-        formData->generateFiles(m_frame.document());
-
         request.setHTTPMethod("POST");
         request.setHTTPBody(WTFMove(formData));
         request.setHTTPContentType(item.formContentType());

Modified: trunk/Source/WebCore/loader/ResourceLoader.cpp (248138 => 248139)


--- trunk/Source/WebCore/loader/ResourceLoader.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/loader/ResourceLoader.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -492,9 +492,6 @@
 
     m_response = r;
 
-    if (FormData* data = ""
-        data->removeGeneratedFilesIfNeeded();
-
     if (m_options.sendLoadCallbacks == SendCallbackPolicy::SendCallbacks)
         frameLoader()->notifier().didReceiveResponse(this, m_response);
 }
@@ -579,9 +576,6 @@
 
 void ResourceLoader::cleanupForError(const ResourceError& error)
 {
-    if (FormData* data = ""
-        data->removeGeneratedFilesIfNeeded();
-
     if (m_notifiedLoadComplete)
         return;
     m_notifiedLoadComplete = true;

Modified: trunk/Source/WebCore/page/Chrome.cpp (248138 => 248139)


--- trunk/Source/WebCore/page/Chrome.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/page/Chrome.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -525,17 +525,6 @@
 #endif
 }
 
-bool ChromeClient::shouldReplaceWithGeneratedFileForUpload(const String&, String&)
-{
-    return false;
-}
-
-String ChromeClient::generateReplacementFile(const String&)
-{
-    ASSERT_NOT_REACHED();
-    return String();
-}
-
 bool Chrome::selectItemWritingDirectionIsNatural()
 {
     return m_client.selectItemWritingDirectionIsNatural();

Modified: trunk/Source/WebCore/page/ChromeClient.h (248138 => 248139)


--- trunk/Source/WebCore/page/ChromeClient.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/page/ChromeClient.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -235,9 +235,6 @@
     // the new cache.
     virtual void reachedApplicationCacheOriginQuota(SecurityOrigin&, int64_t totalSpaceNeeded) = 0;
 
-    virtual bool shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename);
-    virtual String generateReplacementFile(const String& path);
-
 #if ENABLE(IOS_TOUCH_EVENTS)
     virtual void didPreventDefaultForEvent() = 0;
 #endif

Modified: trunk/Source/WebCore/platform/network/FormData.cpp (248138 => 248139)


--- trunk/Source/WebCore/platform/network/FormData.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/platform/network/FormData.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -27,7 +27,6 @@
 #include "Chrome.h"
 #include "ChromeClient.h"
 #include "DOMFormData.h"
-#include "Document.h"
 #include "File.h"
 #include "FormDataBuilder.h"
 #include "Page.h"
@@ -50,22 +49,10 @@
     , m_alwaysStream(false)
     , m_containsPasswordData(data.m_containsPasswordData)
 {
-    // We shouldn't be copying FormData that hasn't already removed its generated files
-    // but just in case, make sure the new FormData is ready to generate its own files.
-    for (auto& element : m_elements) {
-        if (auto* fileData = WTF::get_if<FormDataElement::EncodedFileData>(element.data)) {
-            fileData->generatedFilename = { };
-            fileData->ownsGeneratedFile = false;
-        }
-    }
 }
 
 FormData::~FormData()
 {
-    // This cleanup should've happened when the form submission finished.
-    // Just in case, let's assert, and do the cleanup anyway in release builds.
-    ASSERT(!hasOwnedGeneratedFiles());
-    removeGeneratedFilesIfNeeded();
 }
 
 Ref<FormData> FormData::create()
@@ -109,10 +96,10 @@
     return result;
 }
 
-Ref<FormData> FormData::createMultiPart(const DOMFormData& formData, Document* document)
+Ref<FormData> FormData::createMultiPart(const DOMFormData& formData)
 {
     auto result = create();
-    result->appendMultiPartKeyValuePairItems(formData, document);
+    result->appendMultiPartKeyValuePairItems(formData);
     return result;
 }
 
@@ -146,7 +133,7 @@
             if (fileData.fileLength != BlobDataItem::toEndOfFile)
                 return static_cast<uint64_t>(fileData.fileLength);
             long long fileSize;
-            if (FileSystem::getFileSize(fileData.shouldGenerateFile ? fileData.generatedFilename : fileData.filename, fileSize))
+            if (FileSystem::getFileSize(fileData.filename, fileSize))
                 return static_cast<uint64_t>(fileSize);
             return static_cast<uint64_t>(0);
         }, [] (const FormDataElement::EncodedBlobData& blobData) {
@@ -184,15 +171,15 @@
     m_elements.append(WTFMove(vector));
 }
 
-void FormData::appendFile(const String& filename, bool shouldGenerateFile)
+void FormData::appendFile(const String& filename)
 {
-    m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, WTF::nullopt, shouldGenerateFile));
+    m_elements.append(FormDataElement(filename, 0, BlobDataItem::toEndOfFile, WTF::nullopt));
     m_lengthInBytes = WTF::nullopt;
 }
 
-void FormData::appendFileRange(const String& filename, long long start, long long length, Optional<WallTime> expectedModificationTime, bool shouldGenerateFile)
+void FormData::appendFileRange(const String& filename, long long start, long long length, Optional<WallTime> expectedModificationTime)
 {
-    m_elements.append(FormDataElement(filename, start, length, expectedModificationTime, shouldGenerateFile));
+    m_elements.append(FormDataElement(filename, start, length, expectedModificationTime));
     m_lengthInBytes = WTF::nullopt;
 }
 
@@ -207,22 +194,10 @@
     return normalizeLineEndingsToCRLF(encoding.encode(value, UnencodableHandling::Entities));
 }
 
-void FormData::appendMultiPartFileValue(const File& file, Vector<char>& header, TextEncoding& encoding, Document* document)
+void FormData::appendMultiPartFileValue(const File& file, Vector<char>& header, TextEncoding& encoding)
 {
     auto name = file.name();
 
-    // Let the application specify a filename if it's going to generate a replacement file for the upload.
-    bool shouldGenerateFile = false;
-    auto& path = file.path();
-    if (!path.isEmpty()) {
-        if (Page* page = document->page()) {
-            String generatedFileName;
-            shouldGenerateFile = page->chrome().client().shouldReplaceWithGeneratedFileForUpload(path, generatedFileName);
-            if (shouldGenerateFile)
-                name = generatedFileName;
-        }
-    }
-
     // We have to include the filename=".." part in the header, even if the filename is empty
     FormDataBuilder::addFilenameToMultiPartHeader(header, encoding, name);
 
@@ -238,7 +213,7 @@
     appendData(header.data(), header.size());
 
     if (!file.path().isEmpty())
-        appendFile(file.path(), shouldGenerateFile);
+        appendFile(file.path());
     else if (file.size())
         appendBlob(file.url());
 }
@@ -252,7 +227,7 @@
     appendData(normalizedStringData.data(), normalizedStringData.size());
 }
 
-void FormData::appendMultiPartKeyValuePairItems(const DOMFormData& formData, Document* document)
+void FormData::appendMultiPartKeyValuePairItems(const DOMFormData& formData)
 {
     m_boundary = FormDataBuilder::generateUniqueBoundaryString();
 
@@ -266,7 +241,7 @@
         FormDataBuilder::beginMultiPartHeader(header, m_boundary.data(), normalizedName);
 
         if (WTF::holds_alternative<RefPtr<File>>(item.data))
-            appendMultiPartFileValue(*WTF::get<RefPtr<File>>(item.data), header, encoding, document);
+            appendMultiPartFileValue(*WTF::get<RefPtr<File>>(item.data), header, encoding);
         else
             appendMultiPartStringValue(WTF::get<String>(item.data), header, encoding);
 
@@ -359,7 +334,7 @@
             [&] (const Vector<char>& bytes) {
                 newFormData->appendData(bytes.data(), bytes.size());
             }, [&] (const FormDataElement::EncodedFileData& fileData) {
-                newFormData->appendFileRange(fileData.filename, fileData.fileStart, fileData.fileLength, fileData.expectedFileModificationTime, fileData.shouldGenerateFile);
+                newFormData->appendFileRange(fileData.filename, fileData.fileStart, fileData.fileLength, fileData.expectedFileModificationTime);
             }, [&] (const FormDataElement::EncodedBlobData& blobData) {
                 appendBlobResolved(blobRegistry, newFormData.get(), blobData.url);
             }
@@ -368,66 +343,41 @@
     return newFormData;
 }
 
-void FormData::generateFiles(Document* document)
+FormDataForUpload FormData::prepareForUpload()
 {
-    Page* page = document->page();
-    if (!page)
-        return;
-
+    Vector<String> generatedFiles;
     for (auto& element : m_elements) {
-        if (auto* fileData = WTF::get_if<FormDataElement::EncodedFileData>(element.data)) {
-            if (fileData->shouldGenerateFile) {
-                ASSERT(!fileData->ownsGeneratedFile);
-                ASSERT(fileData->generatedFilename.isEmpty());
-                if (!fileData->generatedFilename.isEmpty())
-                    continue;
-                fileData->generatedFilename = page->chrome().client().generateReplacementFile(fileData->filename);
-                if (!fileData->generatedFilename.isEmpty())
-                    fileData->ownsGeneratedFile = true;
-            }
-        }
-    }
-}
+        auto* fileData = WTF::get_if<FormDataElement::EncodedFileData>(element.data);
+        if (!fileData)
+            continue;
+        if (!FileSystem::fileIsDirectory(fileData->filename, FileSystem::ShouldFollowSymbolicLinks::Yes))
+            continue;
+        if (fileData->fileStart || fileData->fileLength != BlobDataItem::toEndOfFile)
+            continue;
+        if (!fileData->fileModificationTimeMatchesExpectation())
+            continue;
 
-bool FormData::hasGeneratedFiles() const
-{
-    for (auto& element : m_elements) {
-        if (auto* fileData = WTF::get_if<FormDataElement::EncodedFileData>(element.data)) {
-            if (!fileData->generatedFilename.isEmpty())
-                return true;
-        }
+        auto generatedFilename = FileSystem::createTemporaryZipArchive(fileData->filename);
+        if (!generatedFilename)
+            continue;
+        fileData->filename = generatedFilename;
+        generatedFiles.append(WTFMove(generatedFilename));
     }
-    return false;
+    
+    return { *this, WTFMove(generatedFiles) };
 }
 
-bool FormData::hasOwnedGeneratedFiles() const
+FormDataForUpload::FormDataForUpload(FormData& data, Vector<String>&& temporaryZipFiles)
+    : m_data(data)
+    , m_temporaryZipFiles(WTFMove(temporaryZipFiles))
 {
-    for (auto& element : m_elements) {
-        if (auto* fileData = WTF::get_if<FormDataElement::EncodedFileData>(element.data)) {
-            if (fileData->ownsGeneratedFile) {
-                ASSERT(!fileData->generatedFilename.isEmpty());
-                return true;
-            }
-        }
-    }
-    return false;
 }
 
-void FormData::removeGeneratedFilesIfNeeded()
+FormDataForUpload::~FormDataForUpload()
 {
-    for (auto& element : m_elements) {
-        if (auto* fileData = WTF::get_if<FormDataElement::EncodedFileData>(element.data)) {
-            if (fileData->ownsGeneratedFile) {
-                ASSERT(!fileData->generatedFilename.isEmpty());
-                ASSERT(fileData->shouldGenerateFile);
-                String directory = FileSystem::directoryName(fileData->generatedFilename);
-                FileSystem::deleteFile(fileData->generatedFilename);
-                FileSystem::deleteEmptyDirectory(directory);
-                fileData->generatedFilename = String();
-                fileData->ownsGeneratedFile = false;
-            }
-        }
-    }
+    ASSERT(isMainThread());
+    for (auto& file : m_temporaryZipFiles)
+        FileSystem::deleteFile(file);
 }
 
 uint64_t FormData::lengthInBytes() const
@@ -460,4 +410,19 @@
     return { };
 }
 
+bool FormDataElement::EncodedFileData::fileModificationTimeMatchesExpectation() const
+{
+    if (!expectedFileModificationTime)
+        return true;
+
+    auto fileModificationTime = FileSystem::getFileModificationTime(filename);
+    if (!fileModificationTime)
+        return false;
+
+    if (fileModificationTime->secondsSinceEpoch().secondsAs<time_t>() != expectedFileModificationTime->secondsSinceEpoch().secondsAs<time_t>())
+        return false;
+
+    return true;
+}
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/network/FormData.h (248138 => 248139)


--- trunk/Source/WebCore/platform/network/FormData.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/platform/network/FormData.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -31,7 +31,6 @@
 
 class BlobRegistry;
 class DOMFormData;
-class Document;
 class File;
 class SharedBuffer;
 class TextEncoding;
@@ -46,8 +45,8 @@
         : data(WTFMove(data)) { }
     explicit FormDataElement(Vector<char>&& array)
         : data(WTFMove(array)) { }
-    FormDataElement(const String& filename, int64_t fileStart, int64_t fileLength, Optional<WallTime> expectedFileModificationTime, bool shouldGenerateFile)
-        : data(EncodedFileData { filename, fileStart, fileLength, expectedFileModificationTime, { }, shouldGenerateFile, false }) { }
+    FormDataElement(const String& filename, int64_t fileStart, int64_t fileLength, Optional<WallTime> expectedFileModificationTime)
+        : data(EncodedFileData { filename, fileStart, fileLength, expectedFileModificationTime }) { }
     explicit FormDataElement(const URL& blobURL)
         : data(EncodedBlobData { blobURL }) { }
 
@@ -73,17 +72,12 @@
         int64_t fileStart { 0 };
         int64_t fileLength { 0 };
         Optional<WallTime> expectedFileModificationTime;
-        String generatedFilename;
-        bool shouldGenerateFile { false };
-        bool ownsGeneratedFile { false };
 
-        // FIXME: Generated file support in FormData is almost identical to Blob, they should be merged.
-        // We can't just switch to using Blobs for all files because EncodedFile form data elements do not
-        // have a valid expectedFileModificationTime, meaning we always upload the latest content from disk.
+        bool fileModificationTimeMatchesExpectation() const;
 
         EncodedFileData isolatedCopy() const
         {
-            return { filename.isolatedCopy(), fileStart, fileLength, expectedFileModificationTime, generatedFilename.isolatedCopy(), shouldGenerateFile, ownsGeneratedFile };
+            return { filename.isolatedCopy(), fileStart, fileLength, expectedFileModificationTime };
         }
         
         bool operator==(const EncodedFileData& other) const
@@ -91,14 +85,11 @@
             return filename == other.filename
                 && fileStart == other.fileStart
                 && fileLength == other.fileLength
-                && expectedFileModificationTime == other.expectedFileModificationTime
-                && generatedFilename == other.generatedFilename
-                && shouldGenerateFile == other.shouldGenerateFile
-                && ownsGeneratedFile == other.ownsGeneratedFile;
+                && expectedFileModificationTime == other.expectedFileModificationTime;
         }
         template<typename Encoder> void encode(Encoder& encoder) const
         {
-            encoder << filename << fileStart << fileLength << expectedFileModificationTime << generatedFilename << shouldGenerateFile;
+            encoder << filename << fileStart << fileLength << expectedFileModificationTime;
         }
         template<typename Decoder> static Optional<EncodedFileData> decode(Decoder& decoder)
         {
@@ -121,27 +112,12 @@
             decoder >> expectedFileModificationTime;
             if (!expectedFileModificationTime)
                 return WTF::nullopt;
-            
-            Optional<String> generatedFilename;
-            decoder >> generatedFilename;
-            if (!generatedFilename)
-                return WTF::nullopt;
 
-            Optional<bool> shouldGenerateFile;
-            decoder >> shouldGenerateFile;
-            if (!shouldGenerateFile)
-                return WTF::nullopt;
-
-            bool ownsGeneratedFile = false;
-            
             return {{
                 WTFMove(*filename),
                 WTFMove(*fileStart),
                 WTFMove(*fileLength),
-                WTFMove(*expectedFileModificationTime),
-                WTFMove(*generatedFilename),
-                WTFMove(*shouldGenerateFile),
-                WTFMove(ownsGeneratedFile)
+                WTFMove(*expectedFileModificationTime)
             }};
         }
 
@@ -189,6 +165,22 @@
     Data data;
 };
 
+class FormData;
+
+struct FormDataForUpload {
+public:
+    FormDataForUpload(FormDataForUpload&&) = default;
+    ~FormDataForUpload();
+
+    FormData& data() { return m_data.get(); }
+private:
+    friend class FormData;
+    FormDataForUpload(FormData&, Vector<String>&&);
+    
+    Ref<FormData> m_data;
+    Vector<String> m_temporaryZipFiles;
+};
+
 class FormData : public RefCounted<FormData> {
 public:
     enum EncodingType {
@@ -204,7 +196,7 @@
     static Ref<FormData> create(const Vector<char>&);
     static Ref<FormData> create(const Vector<uint8_t>&);
     static Ref<FormData> create(const DOMFormData&, EncodingType = FormURLEncoded);
-    static Ref<FormData> createMultiPart(const DOMFormData&, Document*);
+    static Ref<FormData> createMultiPart(const DOMFormData&);
     WEBCORE_EXPORT ~FormData();
 
     // FIXME: Both these functions perform a deep copy of m_elements, but differ in handling of other data members.
@@ -218,8 +210,8 @@
     static RefPtr<FormData> decode(Decoder&);
 
     WEBCORE_EXPORT void appendData(const void* data, size_t);
-    void appendFile(const String& filePath, bool shouldGenerateFile = false);
-    WEBCORE_EXPORT void appendFileRange(const String& filename, long long start, long long length, Optional<WallTime> expectedModificationTime, bool shouldGenerateFile = false);
+    void appendFile(const String& filePath);
+    WEBCORE_EXPORT void appendFileRange(const String& filename, long long start, long long length, Optional<WallTime> expectedModificationTime);
     WEBCORE_EXPORT void appendBlob(const URL& blobURL);
 
     WEBCORE_EXPORT Vector<char> flatten() const; // omits files
@@ -229,6 +221,8 @@
     // If the FormData has no blob references to resolve, this is returned.
     WEBCORE_EXPORT Ref<FormData> resolveBlobReferences(BlobRegistry&);
 
+    WEBCORE_EXPORT FormDataForUpload prepareForUpload();
+
     bool isEmpty() const { return m_elements.isEmpty(); }
     const Vector<FormDataElement>& elements() const { return m_elements; }
     const Vector<char>& boundary() const { return m_boundary; }
@@ -235,9 +229,6 @@
 
     RefPtr<SharedBuffer> asSharedBuffer() const;
 
-    void generateFiles(Document*);
-    void removeGeneratedFilesIfNeeded();
-
     bool alwaysStream() const { return m_alwaysStream; }
     void setAlwaysStream(bool alwaysStream) { m_alwaysStream = alwaysStream; }
 
@@ -266,14 +257,11 @@
     FormData();
     FormData(const FormData&);
 
-    void appendMultiPartFileValue(const File&, Vector<char>& header, TextEncoding&, Document*);
+    void appendMultiPartFileValue(const File&, Vector<char>& header, TextEncoding&);
     void appendMultiPartStringValue(const String&, Vector<char>& header, TextEncoding&);
-    void appendMultiPartKeyValuePairItems(const DOMFormData&, Document*);
+    void appendMultiPartKeyValuePairItems(const DOMFormData&);
     void appendNonMultiPartKeyValuePairItems(const DOMFormData&, EncodingType);
 
-    bool hasGeneratedFiles() const;
-    bool hasOwnedGeneratedFiles() const;
-
     Vector<FormDataElement> m_elements;
 
     int64_t m_identifier { 0 };

Modified: trunk/Source/WebCore/platform/network/cf/FormDataStreamCFNet.cpp (248138 => 248139)


--- trunk/Source/WebCore/platform/network/cf/FormDataStreamCFNet.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/platform/network/cf/FormDataStreamCFNet.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -92,20 +92,23 @@
 }
 
 struct FormCreationContext {
-    RefPtr<FormData> formData;
+    FormDataForUpload data;
     unsigned long long streamLength;
 };
 
 struct FormStreamFields {
-    RefPtr<FormData> formData;
+    FormStreamFields(FormDataForUpload&& data)
+        : data(WTFMove(data)) { }
+
+    FormDataForUpload data;
     SchedulePairHashSet scheduledRunLoopPairs;
     Vector<FormDataElement> remainingElements; // in reverse order
-    CFReadStreamRef currentStream;
-    long long currentStreamRangeLength;
+    CFReadStreamRef currentStream { nullptr };
+    long long currentStreamRangeLength { BlobDataItem::toEndOfFile };
     MallocPtr<char> currentData;
-    CFReadStreamRef formStream;
-    unsigned long long streamLength;
-    unsigned long long bytesSent;
+    CFReadStreamRef formStream { nullptr };
+    unsigned long long streamLength { 0 };
+    unsigned long long bytesSent { 0 };
     Lock streamIsBeingOpenedOrClosedLock;
 };
 
@@ -145,15 +148,11 @@
             form->currentData = WTFMove(data);
             return true;
         }, [form] (const FormDataElement::EncodedFileData& fileData) {
-            // Check if the file has been changed or not if required.
-            if (fileData.expectedFileModificationTime) {
-                auto fileModificationTime = FileSystem::getFileModificationTime(fileData.filename);
-                if (!fileModificationTime)
-                    return false;
-                if (fileModificationTime->secondsSinceEpoch().secondsAs<time_t>() != fileData.expectedFileModificationTime->secondsSinceEpoch().secondsAs<time_t>())
-                    return false;
-            }
-            const String& path = fileData.shouldGenerateFile ? fileData.generatedFilename : fileData.filename;
+            // Check if the file has been changed.
+            if (!fileData.fileModificationTimeMatchesExpectation())
+                return false;
+
+            const String& path = fileData.filename;
             form->currentStream = CFReadStreamCreateWithFile(0, FileSystem::pathAsURL(path).get());
             if (!form->currentStream) {
                 // The file must have been removed or become unreadable.
@@ -208,14 +207,10 @@
 static void* formCreate(CFReadStreamRef stream, void* context)
 {
     FormCreationContext* formContext = static_cast<FormCreationContext*>(context);
-
-    FormStreamFields* newInfo = new FormStreamFields;
-    newInfo->formData = WTFMove(formContext->formData);
-    newInfo->currentStream = 0;
-    newInfo->currentStreamRangeLength = BlobDataItem::toEndOfFile;
+    
+    FormStreamFields* newInfo = new FormStreamFields(WTFMove(formContext->data));
     newInfo->formStream = stream; // Don't retain. That would create a reference cycle.
     newInfo->streamLength = formContext->streamLength;
-    newInfo->bytesSent = 0;
     
     callOnMainThread([formContext] {
         delete formContext;
@@ -222,10 +217,10 @@
     });
 
     // Append in reverse order since we remove elements from the end.
-    size_t size = newInfo->formData->elements().size();
+    size_t size = newInfo->data.data().elements().size();
     newInfo->remainingElements.reserveInitialCapacity(size);
     for (size_t i = 0; i < size; ++i)
-        newInfo->remainingElements.uncheckedAppend(newInfo->formData->elements()[size - i - 1]);
+        newInfo->remainingElements.uncheckedAppend(newInfo->data.data().elements()[size - i - 1]);
 
     return newInfo;
 }
@@ -317,7 +312,7 @@
     FormStreamFields* form = static_cast<FormStreamFields*>(context);
 
     if (kCFCompareEqualTo == CFStringCompare(propertyName, formDataPointerPropertyName, 0)) {
-        long long formDataAsNumber = static_cast<long long>(reinterpret_cast<intptr_t>(form->formData.get()));
+        long long formDataAsNumber = static_cast<long long>(reinterpret_cast<intptr_t>(&form->data.data()));
         return CFNumberCreate(0, kCFNumberLongLongType, &formDataAsNumber);
     }
 
@@ -378,13 +373,14 @@
 RetainPtr<CFReadStreamRef> createHTTPBodyCFReadStream(FormData& formData)
 {
     auto resolvedFormData = formData.resolveBlobReferences(blobRegistry());
+    auto dataForUpload = resolvedFormData->prepareForUpload();
 
     // Precompute the content length so CFNetwork doesn't use chunked mode.
     unsigned long long length = 0;
-    for (auto& element : resolvedFormData->elements())
+    for (auto& element : dataForUpload.data().elements())
         length += element.lengthInBytes();
 
-    FormCreationContext* formContext = new FormCreationContext { WTFMove(resolvedFormData), length };
+    FormCreationContext* formContext = new FormCreationContext { WTFMove(dataForUpload), length };
     CFReadStreamCallBacksV1 callBacks = { 1, formCreate, formFinalize, nullptr, formOpen, nullptr, formRead, nullptr, formCanRead, formClose, formCopyProperty, nullptr, nullptr, formSchedule, formUnschedule };
     return adoptCF(CFReadStreamCreate(nullptr, static_cast<const void*>(&callBacks), formContext));
 }

Modified: trunk/Source/WebCore/platform/network/mac/BlobDataFileReferenceMac.mm (248138 => 248139)


--- trunk/Source/WebCore/platform/network/mac/BlobDataFileReferenceMac.mm	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/platform/network/mac/BlobDataFileReferenceMac.mm	2019-08-01 22:29:52 UTC (rev 248139)
@@ -30,25 +30,8 @@
 
 #include <wtf/FileMetadata.h>
 #include <wtf/FileSystem.h>
-#include <wtf/SoftLinking.h>
 #include <wtf/text/CString.h>
 
-#if USE(APPLE_INTERNAL_SDK)
-#include <Bom/BOMCopier.h>
-#endif
-
-typedef struct _BOMCopier* BOMCopier;
-
-SOFT_LINK_PRIVATE_FRAMEWORK(Bom)
-SOFT_LINK(Bom, BOMCopierNew, BOMCopier, (), ())
-SOFT_LINK(Bom, BOMCopierFree, void, (BOMCopier copier), (copier))
-SOFT_LINK(Bom, BOMCopierCopyWithOptions, int, (BOMCopier copier, const char* fromObj, const char* toObj, CFDictionaryRef options), (copier, fromObj, toObj, options))
-
-#define kBOMCopierOptionCreatePKZipKey CFSTR("createPKZip")
-#define kBOMCopierOptionSequesterResourcesKey CFSTR("sequesterResources")
-#define kBOMCopierOptionKeepParentKey CFSTR("keepParent")
-#define kBOMCopierOptionCopyResourcesKey CFSTR("copyResources")
-
 namespace WebCore {
 
 void BlobDataFileReference::generateReplacementFile()
@@ -58,26 +41,10 @@
 
     prepareForFileAccess();
 
-    RetainPtr<NSFileCoordinator> coordinator = adoptNS([[NSFileCoordinator alloc] initWithFilePresenter:nil]);
-    [coordinator coordinateReadingItemAtURL:[NSURL fileURLWithPath:m_path] options:NSFileCoordinatorReadingWithoutChanges error:nullptr byAccessor:^(NSURL *newURL) {
-        // The archive is put into a subdirectory of temporary directory for historic reasons. Changing this will require WebCore to change at the same time.
-        CString archivePath([NSTemporaryDirectory() stringByAppendingPathComponent:@"WebKitGeneratedFileXXXXXX"].fileSystemRepresentation);
-        if (mkstemp(archivePath.mutableData()) == -1)
-            return;
+    auto generatedFile = FileSystem::createTemporaryZipArchive(m_path);
+    if (!generatedFile.isNull())
+        m_replacementPath = WTFMove(generatedFile);
 
-        NSDictionary *options = @{
-            (__bridge id)kBOMCopierOptionCreatePKZipKey : @YES,
-            (__bridge id)kBOMCopierOptionSequesterResourcesKey : @YES,
-            (__bridge id)kBOMCopierOptionKeepParentKey : @YES,
-            (__bridge id)kBOMCopierOptionCopyResourcesKey : @YES,
-        };
-
-        BOMCopier copier = BOMCopierNew();
-        if (!BOMCopierCopyWithOptions(copier, newURL.path.fileSystemRepresentation, archivePath.data(), (__bridge CFDictionaryRef)options))
-            m_replacementPath = String::fromUTF8(archivePath);
-        BOMCopierFree(copier);
-    }];
-
     m_replacementShouldBeGenerated = false;
     if (!m_replacementPath.isNull()) {
         if (auto metadata = FileSystem::fileMetadataFollowingSymlinks(m_replacementPath))

Modified: trunk/Source/WebCore/xml/XMLHttpRequest.cpp (248138 => 248139)


--- trunk/Source/WebCore/xml/XMLHttpRequest.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebCore/xml/XMLHttpRequest.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -533,8 +533,7 @@
         return WTFMove(result.value());
 
     if (m_method != "GET" && m_method != "HEAD") {
-        m_requestEntityBody = FormData::createMultiPart(body, document());
-        m_requestEntityBody->generateFiles(document());
+        m_requestEntityBody = FormData::createMultiPart(body);
         if (!m_requestHeaders.contains(HTTPHeaderName::ContentType))
             m_requestHeaders.set(HTTPHeaderName::ContentType, makeString("multipart/form-data; boundary=", m_requestEntityBody->boundary().data()));
     }

Modified: trunk/Source/WebKit/ChangeLog (248138 => 248139)


--- trunk/Source/WebKit/ChangeLog	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/ChangeLog	2019-08-01 22:29:52 UTC (rev 248139)
@@ -1,3 +1,29 @@
+2019-08-01  Alex Christensen  <[email protected]>
+
+        Move FormData zip file generation to NetworkProcess and enable it for all WebKit clients for uploading directories
+        https://bugs.webkit.org/show_bug.cgi?id=200102
+        <rdar://problem/53275114>
+
+        Reviewed by Darin Adler.
+
+        * NetworkProcess/NetworkResourceLoadParameters.cpp:
+        (WebKit::NetworkResourceLoadParameters::encode const):
+        * Platform/IPC/FormDataReference.h:
+        (IPC::FormDataReference::encode const):
+        * Resources/SandboxProfiles/ios/com.apple.WebKit.Networking.sb:
+        * WebProcess/InjectedBundle/API/APIInjectedBundlePageUIClient.h:
+        (API::InjectedBundle::PageUIClient::shouldGenerateFileForUpload): Deleted.
+        (API::InjectedBundle::PageUIClient::generateFileForUpload): Deleted.
+        * WebProcess/InjectedBundle/InjectedBundlePageUIClient.cpp:
+        (WebKit::InjectedBundlePageUIClient::shouldGenerateFileForUpload): Deleted.
+        (WebKit::InjectedBundlePageUIClient::generateFileForUpload): Deleted.
+        * WebProcess/InjectedBundle/InjectedBundlePageUIClient.h:
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::shouldReplaceWithGeneratedFileForUpload): Deleted.
+        (WebKit::WebChromeClient::generateReplacementFile): Deleted.
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/com.apple.WebProcess.sb.in:
+
 2019-08-01  Tim Horton  <[email protected]>
 
         REGRESSION: HSBC Personal Banking download/print dialog is usually positioned off screen on iPad

Modified: trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp (248138 => 248139)


--- trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/NetworkProcess/NetworkResourceLoadParameters.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -57,7 +57,7 @@
         for (size_t i = 0, count = elements.size(); i < count; ++i) {
             const FormDataElement& element = elements[i];
             if (auto* fileData = WTF::get_if<FormDataElement::EncodedFileData>(element.data)) {
-                const String& path = fileData->shouldGenerateFile ? fileData->generatedFilename : fileData->filename;
+                const String& path = fileData->filename;
                 SandboxExtension::createHandle(path, SandboxExtension::Type::ReadOnly, requestBodySandboxExtensions[extensionIndex++]);
             }
         }

Modified: trunk/Source/WebKit/Platform/IPC/FormDataReference.h (248138 => 248139)


--- trunk/Source/WebKit/Platform/IPC/FormDataReference.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/Platform/IPC/FormDataReference.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -60,7 +60,7 @@
         size_t extensionIndex = 0;
         for (auto& element : elements) {
             if (auto* fileData = WTF::get_if<WebCore::FormDataElement::EncodedFileData>(element.data)) {
-                const String& path = fileData->shouldGenerateFile ? fileData->generatedFilename : fileData->filename;
+                const String& path = fileData->filename;
                 WebKit::SandboxExtension::createHandle(path, WebKit::SandboxExtension::Type::ReadOnly, sandboxExtensionHandles[extensionIndex++]);
             }
         }

Modified: trunk/Source/WebKit/Resources/SandboxProfiles/ios/com.apple.WebKit.Networking.sb (248138 => 248139)


--- trunk/Source/WebKit/Resources/SandboxProfiles/ios/com.apple.WebKit.Networking.sb	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/Resources/SandboxProfiles/ios/com.apple.WebKit.Networking.sb	2019-08-01 22:29:52 UTC (rev 248139)
@@ -83,6 +83,7 @@
     (global-name "com.apple.passd.library"))
 
 (allow mach-lookup
+    (global-name "com.apple.FileCoordination")
     (global-name "com.apple.dmd.policy")
     (global-name "com.apple.siri.context.service")
     (global-name "com.apple.ctcategories.service"))

Modified: trunk/Source/WebKit/WebProcess/InjectedBundle/API/APIInjectedBundlePageUIClient.h (248138 => 248139)


--- trunk/Source/WebKit/WebProcess/InjectedBundle/API/APIInjectedBundlePageUIClient.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/WebProcess/InjectedBundle/API/APIInjectedBundlePageUIClient.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -58,9 +58,6 @@
     virtual void mouseDidMoveOverElement(WebKit::WebPage*, const WebCore::HitTestResult&, OptionSet<WebKit::WebEvent::Modifier>, RefPtr<API::Object>& userData) { UNUSED_PARAM(userData); }
     virtual void pageDidScroll(WebKit::WebPage*) { }
 
-    virtual WTF::String shouldGenerateFileForUpload(WebKit::WebPage*, const WTF::String& originalFilePath) { UNUSED_PARAM(originalFilePath); return WTF::String(); }
-    virtual WTF::String generateFileForUpload(WebKit::WebPage*, const WTF::String& originalFilePath) { UNUSED_PARAM(originalFilePath); return emptyString(); }
-
     enum class UIElementVisibility {
         Unknown,
         Visible,

Modified: trunk/Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageUIClient.cpp (248138 => 248139)


--- trunk/Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageUIClient.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageUIClient.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -93,22 +93,6 @@
     m_client.pageDidScroll(toAPI(page), m_client.base.clientInfo);
 }
 
-String InjectedBundlePageUIClient::shouldGenerateFileForUpload(WebPage* page, const String& originalFilePath)
-{
-    if (!m_client.shouldGenerateFileForUpload)
-        return String();
-    RefPtr<API::String> generatedFilePath = adoptRef(toImpl(m_client.shouldGenerateFileForUpload(toAPI(page), toAPI(originalFilePath.impl()), m_client.base.clientInfo)));
-    return generatedFilePath ? generatedFilePath->string() : String();
-}
-
-String InjectedBundlePageUIClient::generateFileForUpload(WebPage* page, const String& originalFilePath)
-{
-    if (!m_client.generateFileForUpload)
-        return String();
-    RefPtr<API::String> generatedFilePath = adoptRef(toImpl(m_client.generateFileForUpload(toAPI(page), toAPI(originalFilePath.impl()), m_client.base.clientInfo)));
-    return generatedFilePath ? generatedFilePath->string() : String();
-}
-
 static API::InjectedBundle::PageUIClient::UIElementVisibility toUIElementVisibility(WKBundlePageUIElementVisibility visibility)
 {
     switch (visibility) {

Modified: trunk/Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageUIClient.h (248138 => 248139)


--- trunk/Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageUIClient.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/WebProcess/InjectedBundle/InjectedBundlePageUIClient.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -54,9 +54,6 @@
     void mouseDidMoveOverElement(WebPage*, const WebCore::HitTestResult&, OptionSet<WebEvent::Modifier>, RefPtr<API::Object>& userData) override;
     void pageDidScroll(WebPage*) override;
 
-    String shouldGenerateFileForUpload(WebPage*, const String& originalFilePath) override;
-    String generateFileForUpload(WebPage*, const String& originalFilePath) override;
-    
     UIElementVisibility statusBarIsVisible(WebPage*) override;
     UIElementVisibility menuBarIsVisible(WebPage*) override;
     UIElementVisibility toolbarsAreVisible(WebPage*) override;

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (248138 => 248139)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp	2019-08-01 22:29:52 UTC (rev 248139)
@@ -789,17 +789,6 @@
     cacheStorage.storeUpdatedQuotaForOrigin(&origin, newQuota);
 }
 
-bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
-{
-    generatedFilename = m_page.injectedBundleUIClient().shouldGenerateFileForUpload(&m_page, path);
-    return !generatedFilename.isNull();
-}
-
-String WebChromeClient::generateReplacementFile(const String& path)
-{
-    return m_page.injectedBundleUIClient().generateFileForUpload(&m_page, path);
-}
-
 #if ENABLE(INPUT_TYPE_COLOR)
 
 std::unique_ptr<ColorChooser> WebChromeClient::createColorChooser(ColorChooserClient& client, const Color& initialColor)

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h (248138 => 248139)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -142,9 +142,6 @@
 
     void reachedMaxAppCacheSize(int64_t spaceNeeded) final;
     void reachedApplicationCacheOriginQuota(WebCore::SecurityOrigin&, int64_t spaceNeeded) final;
-
-    bool shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename) final;
-    String generateReplacementFile(const String& path) final;
     
 #if ENABLE(INPUT_TYPE_COLOR)
     std::unique_ptr<WebCore::ColorChooser> createColorChooser(WebCore::ColorChooserClient&, const WebCore::Color&) final;

Modified: trunk/Source/WebKit/WebProcess/com.apple.WebProcess.sb.in (248138 => 248139)


--- trunk/Source/WebKit/WebProcess/com.apple.WebProcess.sb.in	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKit/WebProcess/com.apple.WebProcess.sb.in	2019-08-01 22:29:52 UTC (rev 248139)
@@ -587,9 +587,6 @@
 (allow mach-lookup
        (global-name "com.apple.webinspector"))
 
-(allow mach-lookup
-    (global-name "com.apple.FileCoordination"))
-
 ;; Various services required by AppKit and other frameworks
 (allow mach-lookup
 #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101400
@@ -978,18 +975,9 @@
         (syscall-number SYS_stat64_extended) ;; <rdar://problem/50473330>
         (syscall-number SYS_lstat_extended)
         (syscall-number SYS_lstat64_extended)
-        (syscall-number SYS_iopolicysys)
-        (syscall-number SYS_workq_open)
-        (syscall-number SYS_getgroups)
         (syscall-number SYS_fgetattrlist) ;; <rdar://problem/50931110>
         (syscall-number SYS_kqueue) ;; <rdar://problem/49609201>
         (syscall-number SYS_kqueue_workloop_ctl) ;; <rdar://problem/50999499>
-        (syscall-number SYS_open_dprotected_np)
-        (syscall-number SYS_flistxattr)
-        (syscall-number SYS_fsetattrlist)
-        (syscall-number SYS_fchown)
-        (syscall-number SYS_fchflags)
-        (syscall-number SYS_fstat64_extended)
     )
 )
 

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (248138 => 248139)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2019-08-01 22:29:52 UTC (rev 248139)
@@ -1,3 +1,20 @@
+2019-08-01  Alex Christensen  <[email protected]>
+
+        Move FormData zip file generation to NetworkProcess and enable it for all WebKit clients for uploading directories
+        https://bugs.webkit.org/show_bug.cgi?id=200102
+        <rdar://problem/53275114>
+
+        Reviewed by Darin Adler.
+
+        * DefaultDelegates/WebDefaultUIDelegate.mm:
+        (-[WebDefaultUIDelegate webView:shouldReplaceUploadFile:usingGeneratedFilename:]): Deleted.
+        (-[WebDefaultUIDelegate webView:generateReplacementFile:]): Deleted.
+        * WebCoreSupport/WebChromeClient.h:
+        * WebCoreSupport/WebChromeClient.mm:
+        (WebChromeClient::shouldReplaceWithGeneratedFileForUpload): Deleted.
+        (WebChromeClient::generateReplacementFile): Deleted.
+        * WebView/WebUIDelegatePrivate.h:
+
 2019-07-25  Dean Jackson  <[email protected]>
 
         Add helper for ignoring deprecated implementation warnings

Modified: trunk/Source/WebKitLegacy/mac/DefaultDelegates/WebDefaultUIDelegate.mm (248138 => 248139)


--- trunk/Source/WebKitLegacy/mac/DefaultDelegates/WebDefaultUIDelegate.mm	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKitLegacy/mac/DefaultDelegates/WebDefaultUIDelegate.mm	2019-08-01 22:29:52 UTC (rev 248139)
@@ -256,16 +256,6 @@
 {
 }
 
-- (BOOL)webView:(WebView *)sender shouldReplaceUploadFile:(NSString *)path usingGeneratedFilename:(NSString **)filename
-{
-    return NO;
-}
-
-- (NSString *)webView:(WebView *)sender generateReplacementFile:(NSString *)path
-{
-    return nil;
-}
-
 #if PLATFORM(IOS_FAMILY)
 - (void)webViewSupportedOrientationsUpdated:(WebView *)sender
 {

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h (248138 => 248139)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -158,9 +158,6 @@
     void enableSuddenTermination() final;
     void disableSuddenTermination() final;
 
-    bool shouldReplaceWithGeneratedFileForUpload(const String& path, String &generatedFilename) final;
-    String generateReplacementFile(const String& path) final;
-
 #if !PLATFORM(IOS_FAMILY)
     void elementDidFocus(WebCore::Element&) override;
     void elementDidBlur(WebCore::Element&) override;

Modified: trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm (248138 => 248139)


--- trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm	2019-08-01 22:29:52 UTC (rev 248139)
@@ -855,20 +855,6 @@
 #endif
 }
 
-bool WebChromeClient::shouldReplaceWithGeneratedFileForUpload(const String& path, String& generatedFilename)
-{
-    NSString* filename;
-    if (![[m_webView _UIDelegateForwarder] webView:m_webView shouldReplaceUploadFile:path usingGeneratedFilename:&filename])
-        return false;
-    generatedFilename = filename;
-    return true;
-}
-
-String WebChromeClient::generateReplacementFile(const String& path)
-{
-    return [[m_webView _UIDelegateForwarder] webView:m_webView generateReplacementFile:path];
-}
-
 #if !PLATFORM(IOS_FAMILY)
 void WebChromeClient::elementDidFocus(WebCore::Element& element)
 {

Modified: trunk/Source/WebKitLegacy/mac/WebView/WebUIDelegatePrivate.h (248138 => 248139)


--- trunk/Source/WebKitLegacy/mac/WebView/WebUIDelegatePrivate.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Source/WebKitLegacy/mac/WebView/WebUIDelegatePrivate.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -248,9 +248,6 @@
 
 - (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features;
 
-- (BOOL)webView:(WebView *)sender shouldReplaceUploadFile:(NSString *)path usingGeneratedFilename:(NSString **)filename;
-- (NSString *)webView:(WebView *)sender generateReplacementFile:(NSString *)path;
-
 /*!
     @method webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:
     @param webView The WebView sending the delegate method.

Modified: trunk/Tools/ChangeLog (248138 => 248139)


--- trunk/Tools/ChangeLog	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Tools/ChangeLog	2019-08-01 22:29:52 UTC (rev 248139)
@@ -1,3 +1,24 @@
+2019-08-01  Alex Christensen  <[email protected]>
+
+        Move FormData zip file generation to NetworkProcess and enable it for all WebKit clients for uploading directories
+        https://bugs.webkit.org/show_bug.cgi?id=200102
+        <rdar://problem/53275114>
+
+        Reviewed by Darin Adler.
+
+        Add an API test that is Mac-only right now because runOpenPanelWithParameters is only supported on Mac for some reason
+        and because clicking on a TestWKWebView only works on Mac.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/UploadDirectory.mm: Added.
+        (-[UploadDelegate initWithDirectory:]):
+        (-[UploadDelegate webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:]):
+        (-[UploadDelegate sentDirectory]):
+        (TEST):
+        * TestWebKitAPI/cocoa/TestWKWebView.h:
+        * TestWebKitAPI/cocoa/TestWKWebView.mm:
+        (-[TestWKWebView sendClickAtPoint:]):
+
 2019-08-01  Zhifei Fang  <[email protected]>
 
         [results.webkit.org] Timeline.CanvasXAxisComponent height should be defined by option

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (248138 => 248139)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2019-08-01 22:29:52 UTC (rev 248139)
@@ -342,6 +342,7 @@
 		5C23DF0B2246015800F454B6 /* Challenge.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C23DF0A2245C9D700F454B6 /* Challenge.mm */; };
 		5C2936931D5BF70D00DEAB1E /* CookieAcceptPolicy.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C2936911D5BF63E00DEAB1E /* CookieAcceptPolicy.mm */; };
 		5C2936961D5C00ED00DEAB1E /* CookieMessage.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5C2936941D5BFD1900DEAB1E /* CookieMessage.html */; };
+		5C3A77AA22F20BEA003827FF /* UploadDirectory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A77A922F20B8A003827FF /* UploadDirectory.mm */; };
 		5C3B1D2622A74F6700BCF4D0 /* ContextMenus.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C3B1D2522A74EA400BCF4D0 /* ContextMenus.mm */; };
 		5C4259462266A68A0039AA7A /* BasicProposedCredentialPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C42594422669E9B0039AA7A /* BasicProposedCredentialPlugIn.mm */; };
 		5C4A84951F7EEFFC00ACFC54 /* Configuration.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C4A84941F7EEFD400ACFC54 /* Configuration.mm */; };
@@ -1819,6 +1820,7 @@
 		5C23DF0A2245C9D700F454B6 /* Challenge.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Challenge.mm; sourceTree = "<group>"; };
 		5C2936911D5BF63E00DEAB1E /* CookieAcceptPolicy.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CookieAcceptPolicy.mm; sourceTree = "<group>"; };
 		5C2936941D5BFD1900DEAB1E /* CookieMessage.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = CookieMessage.html; sourceTree = "<group>"; };
+		5C3A77A922F20B8A003827FF /* UploadDirectory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UploadDirectory.mm; sourceTree = "<group>"; };
 		5C3B1D2522A74EA400BCF4D0 /* ContextMenus.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ContextMenus.mm; sourceTree = "<group>"; };
 		5C42594422669E9B0039AA7A /* BasicProposedCredentialPlugIn.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BasicProposedCredentialPlugIn.mm; sourceTree = "<group>"; };
 		5C4A84941F7EEFD400ACFC54 /* Configuration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Configuration.mm; sourceTree = "<group>"; };
@@ -2828,6 +2830,7 @@
 				F4CD74C820FDB49600DE3794 /* TestURLSchemeHandler.mm */,
 				C22FA32A228F8708009D7988 /* TextWidth.mm */,
 				5CB40B4D1F4B98BE007DC7B9 /* UIDelegate.mm */,
+				5C3A77A922F20B8A003827FF /* UploadDirectory.mm */,
 				7CC3E1FA197E234100BE6252 /* UserContentController.mm */,
 				7C882E031C80C624006BF731 /* UserContentWorld.mm */,
 				7C882E041C80C624006BF731 /* UserContentWorldPlugIn.mm */,
@@ -4686,6 +4689,7 @@
 				5C9D923A22D7E2B0008E9266 /* UnifiedSource4-mm.mm in Sources */,
 				5C9D923C22D7E2B0008E9266 /* UnifiedSource5-mm.mm in Sources */,
 				5C9D923D22D7E2B0008E9266 /* UnifiedSource5.cpp in Sources */,
+				5C3A77AA22F20BEA003827FF /* UploadDirectory.mm in Sources */,
 				5C6E27A7224EEBEA00128736 /* URLCanonicalization.mm in Sources */,
 				E3A1E77F21B25B39008C6007 /* URLParserTextEncoding.cpp in Sources */,
 				7CCE7F271A411AF600447C4C /* UserContentController.mm in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UploadDirectory.mm (0 => 248139)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UploadDirectory.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/UploadDirectory.mm	2019-08-01 22:29:52 UTC (rev 248139)
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#import "config.h"
+
+#if PLATFORM(MAC)
+
+#import "DragAndDropSimulator.h"
+#import "TCPServer.h"
+#import "TestNavigationDelegate.h"
+#import "TestWKWebView.h"
+#import "Utilities.h"
+#import <WebKit/WebKit.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/text/WTFString.h>
+
+@interface UploadDelegate : NSObject <WKUIDelegate>
+- (instancetype)initWithDirectory:(NSURL *)directory;
+- (BOOL)sentDirectory;
+@end
+
+@implementation UploadDelegate {
+    RetainPtr<NSURL> _directory;
+    BOOL _sentDirectory;
+}
+
+- (instancetype)initWithDirectory:(NSURL *)directory
+{
+    if (!(self = [super init]))
+        return nil;
+    _directory = directory;
+    return self;
+}
+
+- (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray<NSURL *> * _Nullable URLs))completionHandler
+{
+    completionHandler(@[_directory.get()]);
+    _sentDirectory = YES;
+}
+
+- (BOOL)sentDirectory
+{
+    return _sentDirectory;
+}
+
+@end
+
+TEST(WebKit, UploadDirectory)
+{
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    NSError *error = nil;
+    NSURL *directory = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:@"UploadDirectory"] isDirectory:YES];
+    EXPECT_FALSE([fileManager fileExistsAtPath:directory.path]);
+    EXPECT_TRUE([fileManager createDirectoryAtURL:directory withIntermediateDirectories:YES attributes:nil error:&error]);
+    EXPECT_FALSE(error);
+    NSData *testData = [@"testdata" dataUsingEncoding:NSUTF8StringEncoding];
+    EXPECT_TRUE([fileManager createFileAtPath:[directory.path stringByAppendingPathComponent:@"testfile"] contents:testData attributes:nil]);
+
+    {
+        using namespace TestWebKitAPI;
+        TCPServer server([] (int socket) {
+            TCPServer::read(socket);
+            const char* response =
+            "HTTP/1.1 200 OK\r\n"
+            "Content-Type: text/html\r\n"
+            "Content-Length: 123\r\n\r\n"
+            "<form id='form' action='' method='post' enctype='multipart/form-data'><input type='file' name='testname'></form>";
+            TCPServer::write(socket, response, strlen(response));
+
+            auto header = TCPServer::read(socket);
+            EXPECT_TRUE(String(header.data(), header.size()).contains("Content-Length: 543"));
+            size_t bodyBytesRead = 0;
+            while (bodyBytesRead < 543)
+                bodyBytesRead += TCPServer::read(socket).size();
+            EXPECT_EQ(bodyBytesRead, 543ull);
+            const char* secondResponse =
+            "HTTP/1.1 200 OK\r\n"
+            "Content-Length: 0\r\n\r\n";
+            TCPServer::write(socket, secondResponse, strlen(secondResponse));
+        });
+
+        auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600)]);
+        auto delegate = adoptNS([[UploadDelegate alloc] initWithDirectory:directory]);
+        [webView setUIDelegate:delegate.get()];
+
+        [webView synchronouslyLoadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%d/", server.port()]]]];
+
+        auto chooseFileButtonLocation = NSMakePoint(10, 590);
+        [webView sendClickAtPoint:chooseFileButtonLocation];
+        while (![delegate sentDirectory])
+            TestWebKitAPI::Util::spinRunLoop();
+        [webView evaluateJavaScript:@"document.getElementById('form').submit()" completionHandler:nil];
+        [webView _test_waitForDidFinishNavigation];
+    }
+
+    EXPECT_TRUE([fileManager removeItemAtPath:directory.path error:&error]);
+    EXPECT_FALSE(error);
+}
+
+#endif

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h (248138 => 248139)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.h	2019-08-01 22:29:52 UTC (rev 248139)
@@ -106,6 +106,7 @@
 - (void)mouseUpAtPoint:(NSPoint)pointInWindow;
 - (void)mouseMoveToPoint:(NSPoint)pointInWindow withFlags:(NSEventModifierFlags)flags;
 - (void)sendClicksAtPoint:(NSPoint)pointInWindow numberOfClicks:(NSUInteger)numberOfClicks;
+- (void)sendClickAtPoint:(NSPoint)pointInWindow;
 - (NSWindow *)hostWindow;
 - (void)typeCharacter:(char)character;
 @end

Modified: trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm (248138 => 248139)


--- trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm	2019-08-01 22:27:27 UTC (rev 248138)
+++ trunk/Tools/TestWebKitAPI/cocoa/TestWKWebView.mm	2019-08-01 22:29:52 UTC (rev 248139)
@@ -593,6 +593,11 @@
     }
 }
 
+- (void)sendClickAtPoint:(NSPoint)pointInWindow
+{
+    [self sendClicksAtPoint:pointInWindow numberOfClicks:1];
+}
+
 - (void)mouseEnterAtPoint:(NSPoint)pointInWindow
 {
     [self mouseEntered:[self _mouseEventWithType:NSEventTypeMouseEntered atLocation:pointInWindow]];
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to