Allow the File object to be created with a replacement file
https://bugs.webkit.org/show_bug.cgi?id=213825

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2020-07-01
Reviewed by Darin Adler.

Source/WebCore:

Working towards webkit.org/b/213347, it needs to be possible to create
the File object with an optional replacement file. Only the registered
BlobDataFileReference will be created with both the original file path
and the replacement file path. So it can delete the replacement file when
it is destroyed. Otherwise BlobDataFileReference will be created with the
replacement file path.

It is important to create the File object with the replacement file because
it needs to get the meta-data and the bytes of the replacement file not
the original file.

* fileapi/File.cpp:
(WebCore::File::create):
* fileapi/File.h:
* fileapi/ThreadableBlobRegistry.cpp:
(WebCore::ThreadableBlobRegistry::registerFileBlobURL):
* fileapi/ThreadableBlobRegistry.h:
* html/DirectoryFileListCreator.cpp:
(WebCore::createFileList):
* html/FileInputType.cpp:
(WebCore::FileInputType::filesFromFormControlState):
When the Files are created from a FormControlState, they will be created
without replacement files since they might have been deleted.

(WebCore::FileInputType::filesChosen):
(WebCore::FileInputType::receiveDroppedFiles):
* platform/FileChooser.cpp:
(WebCore::FileChooser::chooseFiles):
(WebCore::FileChooser::chooseMediaFiles):
* platform/FileChooser.h:
(WebCore::FileChooserFileInfo::isolatedCopy const):
(WebCore::FileChooser::chooseFiles):
(WebCore::FileChooserFileInfo::FileChooserFileInfo): Deleted.
* platform/network/BlobDataFileReference.cpp:
(WebCore::BlobDataFileReference::BlobDataFileReference):
(WebCore::BlobDataFileReference::~BlobDataFileReference):
(WebCore::BlobDataFileReference::path):
(WebCore::BlobDataFileReference::startTrackingModifications):
* platform/network/BlobDataFileReference.h:
* platform/network/BlobRegistry.h:

Source/WebKit:

The UIProcess passes a list of strings which represents the replacement
paths along with a list to the original paths to the WebProcess. The
WebProcess passes these two list to FileChooser which creates the File
objects and register the Blobs.

The WebProcess registers the Blobs in the NetworkProcess which creates
BlobDataFileReference objects with both the original path and the
replacement path.

The WebProcess unregisters the Blobs from the NetworkProcess which deletes
the corresponding BlobDataFileReference from its registry. Upon destroying
the BlobDataFileReference, the replacement file should be deleted.

* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::registerFileBlobURL):
(WebKit::NetworkConnectionToWebProcess::registerBlobURLOptionallyFileBacked):
* NetworkProcess/NetworkConnectionToWebProcess.h:
* NetworkProcess/NetworkConnectionToWebProcess.messages.in:
* NetworkProcess/NetworkProcessPlatformStrategies.cpp:
(WebKit::NetworkProcessPlatformStrategies::createBlobRegistry):
* Shared/BlobDataFileReferenceWithSandboxExtension.cpp:
(WebKit::BlobDataFileReferenceWithSandboxExtension::BlobDataFileReferenceWithSandboxExtension):
* Shared/BlobDataFileReferenceWithSandboxExtension.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::didChooseFilesForOpenPanel):
* WebProcess/FileAPI/BlobRegistryProxy.cpp:
(WebKit::BlobRegistryProxy::registerFileBlobURL):
* WebProcess/FileAPI/BlobRegistryProxy.h:
* WebProcess/WebPage/WebOpenPanelResultListener.cpp:
(WebKit::WebOpenPanelResultListener::didChooseFiles):
* WebProcess/WebPage/WebOpenPanelResultListener.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::didChooseFilesForOpenPanel):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Source/WebKitLegacy/mac:

* WebCoreSupport/WebPlatformStrategies.mm:

Source/WebKitLegacy/win:

* WebCoreSupport/WebPlatformStrategies.cpp:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@263830 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index bb57336..a1f5145 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,51 @@
+2020-07-01  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Allow the File object to be created with a replacement file
+        https://bugs.webkit.org/show_bug.cgi?id=213825
+
+        Reviewed by Darin Adler.
+
+        Working towards webkit.org/b/213347, it needs to be possible to create 
+        the File object with an optional replacement file. Only the registered
+        BlobDataFileReference will be created with both the original file path
+        and the replacement file path. So it can delete the replacement file when
+        it is destroyed. Otherwise BlobDataFileReference will be created with the
+        replacement file path.
+
+        It is important to create the File object with the replacement file because
+        it needs to get the meta-data and the bytes of the replacement file not
+        the original file.
+
+        * fileapi/File.cpp:
+        (WebCore::File::create):
+        * fileapi/File.h:
+        * fileapi/ThreadableBlobRegistry.cpp:
+        (WebCore::ThreadableBlobRegistry::registerFileBlobURL):
+        * fileapi/ThreadableBlobRegistry.h:
+        * html/DirectoryFileListCreator.cpp:
+        (WebCore::createFileList):
+        * html/FileInputType.cpp:
+        (WebCore::FileInputType::filesFromFormControlState):
+        When the Files are created from a FormControlState, they will be created
+        without replacement files since they might have been deleted.
+
+        (WebCore::FileInputType::filesChosen):
+        (WebCore::FileInputType::receiveDroppedFiles):
+        * platform/FileChooser.cpp:
+        (WebCore::FileChooser::chooseFiles):
+        (WebCore::FileChooser::chooseMediaFiles):
+        * platform/FileChooser.h:
+        (WebCore::FileChooserFileInfo::isolatedCopy const):
+        (WebCore::FileChooser::chooseFiles):
+        (WebCore::FileChooserFileInfo::FileChooserFileInfo): Deleted.
+        * platform/network/BlobDataFileReference.cpp:
+        (WebCore::BlobDataFileReference::BlobDataFileReference):
+        (WebCore::BlobDataFileReference::~BlobDataFileReference):
+        (WebCore::BlobDataFileReference::path):
+        (WebCore::BlobDataFileReference::startTrackingModifications):
+        * platform/network/BlobDataFileReference.h:
+        * platform/network/BlobRegistry.h:
+
 2020-07-01  Don Olmstead  <don.olmstead@sony.com>
 
         [CMake] Add WOFF2 targets
diff --git a/Source/WebCore/fileapi/File.cpp b/Source/WebCore/fileapi/File.cpp
index 8d6e387..8a76a73 100644
--- a/Source/WebCore/fileapi/File.cpp
+++ b/Source/WebCore/fileapi/File.cpp
@@ -46,16 +46,17 @@
     return file;
 }
 
-Ref<File> File::create(const String& path, const String& nameOverride)
+Ref<File> File::create(const String& path, const String& replacementPath, const String& nameOverride)
 {
     String name;
     String type;
-    computeNameAndContentType(path, nameOverride, name, type);
+    String effectivePath = !replacementPath.isNull() ? replacementPath : path;
+    computeNameAndContentType(effectivePath, nameOverride, name, type);
 
     auto internalURL = BlobURL::createInternalURL();
-    ThreadableBlobRegistry::registerFileBlobURL(internalURL, path, type);
+    ThreadableBlobRegistry::registerFileBlobURL(internalURL, path, replacementPath, type);
 
-    return adoptRef(*new File(WTFMove(internalURL), WTFMove(type), String { path }, WTFMove(name)));
+    return adoptRef(*new File(WTFMove(internalURL), WTFMove(type), WTFMove(effectivePath), WTFMove(name)));
 }
 
 File::File(URL&& url, String&& type, String&& path, String&& name)
diff --git a/Source/WebCore/fileapi/File.h b/Source/WebCore/fileapi/File.h
index d2f938b..87974d0 100644
--- a/Source/WebCore/fileapi/File.h
+++ b/Source/WebCore/fileapi/File.h
@@ -42,7 +42,7 @@
     };
 
     // Create a file with an optional name exposed to the author (via File.name and associated DOM properties) that differs from the one provided in the path.
-    WEBCORE_EXPORT static Ref<File> create(const String& path, const String& nameOverride = { });
+    WEBCORE_EXPORT static Ref<File> create(const String& path, const String& replacementPath = { }, const String& nameOverride = { });
 
     // Create a File using the 'new File' constructor.
     static Ref<File> create(Vector<BlobPartVariant>&& blobPartVariants, const String& filename, const PropertyBag& propertyBag)
diff --git a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
index 5e1d4c0..70cbe6d 100644
--- a/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
+++ b/Source/WebCore/fileapi/ThreadableBlobRegistry.cpp
@@ -64,15 +64,17 @@
     return *map;
 }
 
-void ThreadableBlobRegistry::registerFileBlobURL(const URL& url, const String& path, const String& contentType)
+void ThreadableBlobRegistry::registerFileBlobURL(const URL& url, const String& path, const String& replacementPath, const String& contentType)
 {
+    String effectivePath = !replacementPath.isNull() ? replacementPath : path;
+
     if (isMainThread()) {
-        blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
+        blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(effectivePath), path, contentType);
         return;
     }
 
-    callOnMainThread([url = url.isolatedCopy(), path = path.isolatedCopy(), contentType = contentType.isolatedCopy()] {
-        blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(path), contentType);
+    callOnMainThread([url = url.isolatedCopy(), effectivePath = effectivePath.isolatedCopy(), path = path.isolatedCopy(), contentType = contentType.isolatedCopy()] {
+        blobRegistry().registerFileBlobURL(url, BlobDataFileReference::create(effectivePath), path, contentType);
     });
 }
 
diff --git a/Source/WebCore/fileapi/ThreadableBlobRegistry.h b/Source/WebCore/fileapi/ThreadableBlobRegistry.h
index a9c79fe..ecb74f1 100644
--- a/Source/WebCore/fileapi/ThreadableBlobRegistry.h
+++ b/Source/WebCore/fileapi/ThreadableBlobRegistry.h
@@ -40,7 +40,7 @@
 
 class ThreadableBlobRegistry {
 public:
-    static void registerFileBlobURL(const URL&, const String& path, const String& contentType);
+    static void registerFileBlobURL(const URL&, const String& path, const String& replacementPath, const String& contentType);
     static void registerBlobURL(const URL&, Vector<BlobPart>&& blobParts, const String& contentType);
     static void registerBlobURL(SecurityOrigin*, const URL&, const URL& srcURL);
     static void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, const String& fileBackedPath, const String& contentType);
diff --git a/Source/WebCore/html/DirectoryFileListCreator.cpp b/Source/WebCore/html/DirectoryFileListCreator.cpp
index 1af9eb2..f00989d 100644
--- a/Source/WebCore/html/DirectoryFileListCreator.cpp
+++ b/Source/WebCore/html/DirectoryFileListCreator.cpp
@@ -64,7 +64,7 @@
         if (FileSystem::fileIsDirectory(info.path, FileSystem::ShouldFollowSymbolicLinks::No))
             appendDirectoryFiles(info.path, FileSystem::pathGetFileName(info.path), fileObjects);
         else
-            fileObjects.append(File::create(info.path, info.displayName));
+            fileObjects.append(File::create(info.path, { }, info.displayName));
     }
     return FileList::create(WTFMove(fileObjects));
 }
diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp
index f3c7098..86f3d32 100644
--- a/Source/WebCore/html/FileInputType.cpp
+++ b/Source/WebCore/html/FileInputType.cpp
@@ -115,12 +115,8 @@
     Vector<FileChooserFileInfo> files;
     size_t size = state.size();
     files.reserveInitialCapacity(size / 2);
-    for (size_t i = 0; i < size; i += 2) {
-        if (!state[i + 1].isEmpty())
-            files.uncheckedAppend({ state[i], state[i + 1] });
-        else
-            files.uncheckedAppend({ state[i] });
-    }
+    for (size_t i = 0; i < size; i += 2)
+        files.uncheckedAppend({ state[i], { }, state[i + 1] });
     return files;
 }
 
@@ -414,7 +410,7 @@
 
     if (!allowsDirectories()) {
         auto files = paths.map([](auto& fileInfo) {
-            return File::create(fileInfo.path, fileInfo.displayName);
+            return File::create(fileInfo.path, fileInfo.replacementPath, fileInfo.displayName);
         });
         didCreateFileList(FileList::create(WTFMove(files)), icon);
         return;
@@ -469,11 +465,11 @@
         Vector<FileChooserFileInfo> files;
         files.reserveInitialCapacity(paths.size());
         for (auto& path : paths)
-            files.uncheckedAppend({ path });
+            files.uncheckedAppend({ path, { }, { } });
 
         filesChosen(files);
     } else
-        filesChosen({ FileChooserFileInfo { paths[0] } });
+        filesChosen({ { paths[0], { }, { } } });
 
     return true;
 }
diff --git a/Source/WebCore/platform/FileChooser.cpp b/Source/WebCore/platform/FileChooser.cpp
index ac7f5d4..8e4ece7 100644
--- a/Source/WebCore/platform/FileChooser.cpp
+++ b/Source/WebCore/platform/FileChooser.cpp
@@ -58,7 +58,7 @@
     chooseFiles(filenames);
 }
 
-void FileChooser::chooseFiles(const Vector<String>& filenames)
+void FileChooser::chooseFiles(const Vector<String>& filenames, const Vector<String>& replacementNames)
 {
     // FIXME: This is inelegant. We should not be looking at settings here.
     if (m_settings.selectedFiles == filenames)
@@ -68,8 +68,8 @@
         return;
 
     Vector<FileChooserFileInfo> files;
-    for (auto& filename : filenames)
-        files.append(FileChooserFileInfo(filename));
+    for (size_t i = 0, size = filenames.size(); i < size; ++i)
+        files.append({ filenames[i], i < replacementNames.size() ? replacementNames[i] : nullString(), { } });
     m_client->filesChosen(files);
 }
 
@@ -88,7 +88,7 @@
 
     Vector<FileChooserFileInfo> files;
     for (auto& filename : filenames)
-        files.append(FileChooserFileInfo(filename));
+        files.append({ filename, { }, { } });
     m_client->filesChosen(files, displayString, icon);
 }
 
diff --git a/Source/WebCore/platform/FileChooser.h b/Source/WebCore/platform/FileChooser.h
index e51eb9e..ab68dac 100644
--- a/Source/WebCore/platform/FileChooser.h
+++ b/Source/WebCore/platform/FileChooser.h
@@ -46,18 +46,13 @@
 class Icon;
 
 struct FileChooserFileInfo {
-    FileChooserFileInfo(const String& path, const String& displayName = String())
-        : path(path)
-        , displayName(displayName)
-    {
-    }
-
     FileChooserFileInfo isolatedCopy() const
     {
-        return { path.isolatedCopy(), displayName.isolatedCopy() };
+        return { path.isolatedCopy(), replacementPath.isolatedCopy(), displayName.isolatedCopy() };
     }
 
     const String path;
+    const String replacementPath;
     const String displayName;
 };
 
@@ -87,7 +82,7 @@
     void invalidate();
 
     WEBCORE_EXPORT void chooseFile(const String& path);
-    WEBCORE_EXPORT void chooseFiles(const Vector<String>& paths);
+    WEBCORE_EXPORT void chooseFiles(const Vector<String>& paths, const Vector<String>& replacementPaths = { });
 #if PLATFORM(IOS_FAMILY)
     // FIXME: This function is almost identical to FileChooser::chooseFiles(). We should merge this
     // function with FileChooser::chooseFiles() and hence remove the PLATFORM(IOS_FAMILY)-guard.
diff --git a/Source/WebCore/platform/network/BlobDataFileReference.cpp b/Source/WebCore/platform/network/BlobDataFileReference.cpp
index 5abfd75..dfb4b58 100644
--- a/Source/WebCore/platform/network/BlobDataFileReference.cpp
+++ b/Source/WebCore/platform/network/BlobDataFileReference.cpp
@@ -32,17 +32,16 @@
 
 namespace WebCore {
 
-BlobDataFileReference::BlobDataFileReference(const String& path)
+BlobDataFileReference::BlobDataFileReference(const String& path, const String& replacementPath)
     : m_path(path)
+    , m_replacementPath(replacementPath)
 {
 }
 
 BlobDataFileReference::~BlobDataFileReference()
 {
-#if ENABLE(FILE_REPLACEMENT)
     if (!m_replacementPath.isNull())
         FileSystem::deleteFile(m_replacementPath);
-#endif
 }
 
 const String& BlobDataFileReference::path()
@@ -50,10 +49,9 @@
 #if ENABLE(FILE_REPLACEMENT)
     if (m_replacementShouldBeGenerated)
         generateReplacementFile();
-
+#endif
     if (!m_replacementPath.isNull())
         return m_replacementPath;
-#endif
 
     return m_path;
 }
@@ -101,6 +99,13 @@
         return;
 #endif
 
+    // This is a registered blob with a replacement file. Get the Metadata of the replacement file.
+    if (!m_replacementPath.isNull()) {
+        metadata = FileSystem::fileMetadataFollowingSymlinks(m_replacementPath);
+        if (!metadata)
+            return;
+    }
+
     m_size = metadata.value().length;
 }
 
diff --git a/Source/WebCore/platform/network/BlobDataFileReference.h b/Source/WebCore/platform/network/BlobDataFileReference.h
index 658829d..8fcbe8c 100644
--- a/Source/WebCore/platform/network/BlobDataFileReference.h
+++ b/Source/WebCore/platform/network/BlobDataFileReference.h
@@ -35,9 +35,9 @@
 
 class WEBCORE_EXPORT BlobDataFileReference : public RefCounted<BlobDataFileReference> {
 public:
-    static Ref<BlobDataFileReference> create(const String& path)
+    static Ref<BlobDataFileReference> create(const String& path, const String& replacementPath = { })
     {
-        return adoptRef(*new BlobDataFileReference(path));
+        return adoptRef(*new BlobDataFileReference(path, replacementPath));
     }
 
     virtual ~BlobDataFileReference();
@@ -52,7 +52,7 @@
     virtual void revokeFileAccess();
 
 protected:
-    BlobDataFileReference(const String& path);
+    BlobDataFileReference(const String& path, const String& replacementPath);
 
 private:
 #if ENABLE(FILE_REPLACEMENT)
@@ -60,8 +60,8 @@
 #endif
 
     String m_path;
-#if ENABLE(FILE_REPLACEMENT)
     String m_replacementPath;
+#if ENABLE(FILE_REPLACEMENT)
     bool m_replacementShouldBeGenerated { false };
 #endif
     unsigned long long m_size { 0 };
diff --git a/Source/WebCore/platform/network/BlobRegistry.h b/Source/WebCore/platform/network/BlobRegistry.h
index fe91e81..4b15cdd 100644
--- a/Source/WebCore/platform/network/BlobRegistry.h
+++ b/Source/WebCore/platform/network/BlobRegistry.h
@@ -47,7 +47,7 @@
 public:
 
     // Registers a blob URL referring to the specified file.
-    virtual void registerFileBlobURL(const URL&, Ref<BlobDataFileReference>&&, const String& contentType) = 0;
+    virtual void registerFileBlobURL(const URL&, Ref<BlobDataFileReference>&&, const String& path, const String& contentType) = 0;
 
     // Registers a blob URL referring to the specified blob data.
     virtual void registerBlobURL(const URL&, Vector<BlobPart>&&, const String& contentType) = 0;
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index e04ab44..5030da1 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,46 @@
+2020-07-01  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Allow the File object to be created with a replacement file
+        https://bugs.webkit.org/show_bug.cgi?id=213825
+
+        Reviewed by Darin Adler.
+
+        The UIProcess passes a list of strings which represents the replacement
+        paths along with a list to the original paths to the WebProcess. The 
+        WebProcess passes these two list to FileChooser which creates the File
+        objects and register the Blobs.
+
+        The WebProcess registers the Blobs in the NetworkProcess which creates
+        BlobDataFileReference objects with both the original path and the
+        replacement path.
+
+        The WebProcess unregisters the Blobs from the NetworkProcess which deletes
+        the corresponding BlobDataFileReference from its registry. Upon destroying
+        the BlobDataFileReference, the replacement file should be deleted.
+
+        * NetworkProcess/NetworkConnectionToWebProcess.cpp:
+        (WebKit::NetworkConnectionToWebProcess::registerFileBlobURL):
+        (WebKit::NetworkConnectionToWebProcess::registerBlobURLOptionallyFileBacked):
+        * NetworkProcess/NetworkConnectionToWebProcess.h:
+        * NetworkProcess/NetworkConnectionToWebProcess.messages.in:
+        * NetworkProcess/NetworkProcessPlatformStrategies.cpp:
+        (WebKit::NetworkProcessPlatformStrategies::createBlobRegistry):
+        * Shared/BlobDataFileReferenceWithSandboxExtension.cpp:
+        (WebKit::BlobDataFileReferenceWithSandboxExtension::BlobDataFileReferenceWithSandboxExtension):
+        * Shared/BlobDataFileReferenceWithSandboxExtension.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::didChooseFilesForOpenPanel):
+        * WebProcess/FileAPI/BlobRegistryProxy.cpp:
+        (WebKit::BlobRegistryProxy::registerFileBlobURL):
+        * WebProcess/FileAPI/BlobRegistryProxy.h:
+        * WebProcess/WebPage/WebOpenPanelResultListener.cpp:
+        (WebKit::WebOpenPanelResultListener::didChooseFiles):
+        * WebProcess/WebPage/WebOpenPanelResultListener.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::didChooseFilesForOpenPanel):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2020-07-01  Tim Horton  <timothy_horton@apple.com>
 
         Swipe snapshot is removed too early when swiping away from a page that is still loading
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
index 5c192f2..c8d6ee7 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
@@ -732,7 +732,7 @@
 
 #endif
 
-void NetworkConnectionToWebProcess::registerFileBlobURL(const URL& url, const String& path, SandboxExtension::Handle&& extensionHandle, const String& contentType)
+void NetworkConnectionToWebProcess::registerFileBlobURL(const URL& url, const String& path, const String& replacementPath, SandboxExtension::Handle&& extensionHandle, const String& contentType)
 {
     NETWORK_PROCESS_MESSAGE_CHECK(!url.isEmpty());
 
@@ -740,7 +740,7 @@
     if (!session)
         return;
 
-    session->blobRegistry().registerFileBlobURL(url, BlobDataFileReferenceWithSandboxExtension::create(path, SandboxExtension::create(WTFMove(extensionHandle))), contentType);
+    session->blobRegistry().registerFileBlobURL(url, BlobDataFileReferenceWithSandboxExtension::create(path, replacementPath, SandboxExtension::create(WTFMove(extensionHandle))), contentType);
 }
 
 void NetworkConnectionToWebProcess::registerBlobURL(const URL& url, Vector<BlobPart>&& blobParts, const String& contentType)
@@ -769,7 +769,7 @@
     if (!session)
         return;
 
-    session->blobRegistry().registerBlobURLOptionallyFileBacked(url, srcURL, BlobDataFileReferenceWithSandboxExtension::create(fileBackedPath, nullptr), contentType);
+    session->blobRegistry().registerBlobURLOptionallyFileBacked(url, srcURL, BlobDataFileReferenceWithSandboxExtension::create(fileBackedPath), contentType);
 }
 
 void NetworkConnectionToWebProcess::registerBlobURLForSlice(const URL& url, const URL& srcURL, int64_t start, int64_t end)
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
index e823000..18cced9 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
@@ -215,7 +215,7 @@
     void setRawCookie(const WebCore::Cookie&);
     void deleteCookie(const URL&, const String& cookieName);
 
-    void registerFileBlobURL(const URL&, const String& path, SandboxExtension::Handle&&, const String& contentType);
+    void registerFileBlobURL(const URL&, const String& path, const String& replacementPath, SandboxExtension::Handle&&, const String& contentType);
     void registerBlobURL(const URL&, Vector<WebCore::BlobPart>&&, const String& contentType);
     void registerBlobURLFromURL(const URL&, const URL& srcURL);
     void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, const String& fileBackedPath, const String& contentType);
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
index 2200d4c..7b82252 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
@@ -46,7 +46,7 @@
     UnsubscribeFromCookieChangeNotifications(HashSet<String> hosts)
 #endif
 
-    RegisterFileBlobURL(URL url, String path, WebKit::SandboxExtension::Handle extensionHandle, String contentType)
+    RegisterFileBlobURL(URL url, String path, String replacementPath, WebKit::SandboxExtension::Handle extensionHandle, String contentType)
     RegisterBlobURL(URL url, Vector<WebCore::BlobPart> blobParts, String contentType)
     RegisterBlobURLFromURL(URL url, URL srcURL)
     RegisterBlobURLOptionallyFileBacked(URL url, URL srcURL, String fileBackedPath, String contentType)
diff --git a/Source/WebKit/NetworkProcess/NetworkProcessPlatformStrategies.cpp b/Source/WebKit/NetworkProcess/NetworkProcessPlatformStrategies.cpp
index f69601c..cffc99f 100644
--- a/Source/WebKit/NetworkProcess/NetworkProcessPlatformStrategies.cpp
+++ b/Source/WebKit/NetworkProcess/NetworkProcessPlatformStrategies.cpp
@@ -57,7 +57,7 @@
 {
     using namespace WebCore;
     class EmptyBlobRegistry : public WebCore::BlobRegistry {
-        void registerFileBlobURL(const URL&, Ref<BlobDataFileReference>&&, const String& contentType) final { ASSERT_NOT_REACHED(); }
+        void registerFileBlobURL(const URL&, Ref<BlobDataFileReference>&&, const String& path, const String& contentType) final { ASSERT_NOT_REACHED(); }
         void registerBlobURL(const URL&, Vector<BlobPart>&&, const String& contentType) final { ASSERT_NOT_REACHED(); }
         void registerBlobURL(const URL&, const URL& srcURL) final { ASSERT_NOT_REACHED(); }
         void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, RefPtr<BlobDataFileReference>&&, const String& contentType) final { ASSERT_NOT_REACHED(); }
diff --git a/Source/WebKit/Shared/BlobDataFileReferenceWithSandboxExtension.cpp b/Source/WebKit/Shared/BlobDataFileReferenceWithSandboxExtension.cpp
index fc74b60..9a56e39 100644
--- a/Source/WebKit/Shared/BlobDataFileReferenceWithSandboxExtension.cpp
+++ b/Source/WebKit/Shared/BlobDataFileReferenceWithSandboxExtension.cpp
@@ -30,8 +30,8 @@
 
 namespace WebKit {
 
-BlobDataFileReferenceWithSandboxExtension::BlobDataFileReferenceWithSandboxExtension(const String& path, RefPtr<SandboxExtension>&& sandboxExtension)
-    : BlobDataFileReference(path)
+BlobDataFileReferenceWithSandboxExtension::BlobDataFileReferenceWithSandboxExtension(const String& path, const String& replacementPath, RefPtr<SandboxExtension>&& sandboxExtension)
+    : BlobDataFileReference(path, replacementPath)
     , m_sandboxExtension(WTFMove(sandboxExtension))
 {
 }
diff --git a/Source/WebKit/Shared/BlobDataFileReferenceWithSandboxExtension.h b/Source/WebKit/Shared/BlobDataFileReferenceWithSandboxExtension.h
index 75a5d4d..7b8329f 100644
--- a/Source/WebKit/Shared/BlobDataFileReferenceWithSandboxExtension.h
+++ b/Source/WebKit/Shared/BlobDataFileReferenceWithSandboxExtension.h
@@ -34,13 +34,13 @@
 
 class BlobDataFileReferenceWithSandboxExtension final : public WebCore::BlobDataFileReference {
 public:
-    static Ref<BlobDataFileReference> create(const String& path, RefPtr<SandboxExtension>&& sandboxExtension)
+    static Ref<BlobDataFileReference> create(const String& path, const String& replacementPath = { }, RefPtr<SandboxExtension>&& sandboxExtension = nullptr)
     {
-        return adoptRef(*new BlobDataFileReferenceWithSandboxExtension(path, WTFMove(sandboxExtension)));
+        return adoptRef(*new BlobDataFileReferenceWithSandboxExtension(path, replacementPath, WTFMove(sandboxExtension)));
     }
 
 private:
-    BlobDataFileReferenceWithSandboxExtension(const String& path, RefPtr<SandboxExtension>&&);
+    BlobDataFileReferenceWithSandboxExtension(const String& path, const String& replacementPath, RefPtr<SandboxExtension>&&);
     virtual ~BlobDataFileReferenceWithSandboxExtension();
 
     void prepareForFileAccess() override;
diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp
index d9bd744..7663b44 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.cpp
+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp
@@ -6700,7 +6700,7 @@
     send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTFMove(sandboxExtensionHandles)));
 #endif
 
-    send(Messages::WebPage::DidChooseFilesForOpenPanel(fileURLs));
+    send(Messages::WebPage::DidChooseFilesForOpenPanel(fileURLs, { }));
 
     m_openPanelResultListener->invalidate();
     m_openPanelResultListener = nullptr;
diff --git a/Source/WebKit/WebProcess/FileAPI/BlobRegistryProxy.cpp b/Source/WebKit/WebProcess/FileAPI/BlobRegistryProxy.cpp
index 8f47b8f..903f941 100644
--- a/Source/WebKit/WebProcess/FileAPI/BlobRegistryProxy.cpp
+++ b/Source/WebKit/WebProcess/FileAPI/BlobRegistryProxy.cpp
@@ -36,7 +36,7 @@
 namespace WebKit {
 using namespace WebCore;
 
-void BlobRegistryProxy::registerFileBlobURL(const URL& url, Ref<BlobDataFileReference>&& file, const String& contentType)
+void BlobRegistryProxy::registerFileBlobURL(const URL& url, Ref<BlobDataFileReference>&& file, const String& path, const String& contentType)
 {
     SandboxExtension::Handle extensionHandle;
 
@@ -44,7 +44,8 @@
     if (!file->path().isEmpty())
         SandboxExtension::createHandle(file->path(), SandboxExtension::Type::ReadOnly, extensionHandle);
 
-    WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::RegisterFileBlobURL(url, file->path(), extensionHandle, contentType), 0);
+    String replacementPath = path == file->path() ? nullString() : file->path();
+    WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::RegisterFileBlobURL(url, path, replacementPath, extensionHandle, contentType), 0);
 }
 
 void BlobRegistryProxy::registerBlobURL(const URL& url, Vector<BlobPart>&& blobParts, const String& contentType)
diff --git a/Source/WebKit/WebProcess/FileAPI/BlobRegistryProxy.h b/Source/WebKit/WebProcess/FileAPI/BlobRegistryProxy.h
index 40984db..e837a69 100644
--- a/Source/WebKit/WebProcess/FileAPI/BlobRegistryProxy.h
+++ b/Source/WebKit/WebProcess/FileAPI/BlobRegistryProxy.h
@@ -31,7 +31,7 @@
 
 class BlobRegistryProxy final : public WebCore::BlobRegistry {
 public:
-    void registerFileBlobURL(const URL&, Ref<WebCore::BlobDataFileReference>&&, const String& contentType) final;
+    void registerFileBlobURL(const URL&, Ref<WebCore::BlobDataFileReference>&&, const String& path, const String& contentType) final;
     void registerBlobURL(const URL&, Vector<WebCore::BlobPart>&&, const String& contentType) final;
     void registerBlobURL(const URL&, const URL& srcURL) final;
     void registerBlobURLOptionallyFileBacked(const URL&, const URL& srcURL, RefPtr<WebCore::BlobDataFileReference>&&, const String& contentType) final;
diff --git a/Source/WebKit/WebProcess/WebPage/WebOpenPanelResultListener.cpp b/Source/WebKit/WebProcess/WebPage/WebOpenPanelResultListener.cpp
index d98343c..d2aaef5 100644
--- a/Source/WebKit/WebProcess/WebPage/WebOpenPanelResultListener.cpp
+++ b/Source/WebKit/WebProcess/WebPage/WebOpenPanelResultListener.cpp
@@ -46,9 +46,9 @@
 {
 }
 
-void WebOpenPanelResultListener::didChooseFiles(const Vector<String>& files)
+void WebOpenPanelResultListener::didChooseFiles(const Vector<String>& files, const Vector<String>& replacementFiles)
 {
-    m_fileChooser->chooseFiles(files);
+    m_fileChooser->chooseFiles(files, replacementFiles);
 }
 
 #if PLATFORM(IOS_FAMILY)
diff --git a/Source/WebKit/WebProcess/WebPage/WebOpenPanelResultListener.h b/Source/WebKit/WebProcess/WebPage/WebOpenPanelResultListener.h
index d0d859b..9e670b5 100644
--- a/Source/WebKit/WebProcess/WebPage/WebOpenPanelResultListener.h
+++ b/Source/WebKit/WebProcess/WebPage/WebOpenPanelResultListener.h
@@ -44,7 +44,7 @@
     ~WebOpenPanelResultListener();
 
     void disconnectFromPage() { m_page = 0; }
-    void didChooseFiles(const Vector<String>&);
+    void didChooseFiles(const Vector<String>& files, const Vector<String>& replacementFiles);
 #if PLATFORM(IOS_FAMILY)
     void didChooseFilesWithDisplayStringAndIcon(const Vector<String>&, const String& displayString, WebCore::Icon*);
 #endif
diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp
index 7d90118..1df2782 100644
--- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp
+++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp
@@ -4301,12 +4301,12 @@
 }
 #endif
 
-void WebPage::didChooseFilesForOpenPanel(const Vector<String>& files)
+void WebPage::didChooseFilesForOpenPanel(const Vector<String>& files, const Vector<String>& replacementFiles)
 {
     if (!m_activeOpenPanelResultListener)
         return;
 
-    m_activeOpenPanelResultListener->didChooseFiles(files);
+    m_activeOpenPanelResultListener->didChooseFiles(files, replacementFiles);
     m_activeOpenPanelResultListener = nullptr;
 }
 
diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h
index 2004649..0db2c7b 100644
--- a/Source/WebKit/WebProcess/WebPage/WebPage.h
+++ b/Source/WebKit/WebProcess/WebPage/WebPage.h
@@ -1602,7 +1602,7 @@
     void failedToShowPopupMenu();
 #endif
 
-    void didChooseFilesForOpenPanel(const Vector<String>&);
+    void didChooseFilesForOpenPanel(const Vector<String>& files, const Vector<String>& replacementFiles);
     void didCancelForOpenPanel();
 
 #if PLATFORM(IOS_FAMILY)
diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in
index 6889d62..c5e3431 100644
--- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in
+++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in
@@ -343,7 +343,7 @@
 #if PLATFORM(IOS_FAMILY)
     DidChooseFilesForOpenPanelWithDisplayStringAndIcon(Vector<String> fileURLs, String displayString, IPC::DataReference iconData, WebKit::SandboxExtension::Handle frontboardServicesSandboxExtension, WebKit::SandboxExtension::Handle iconServicesSandboxExtension)
 #endif
-    DidChooseFilesForOpenPanel(Vector<String> fileURLs)
+    DidChooseFilesForOpenPanel(Vector<String> fileURLs, Vector<String> replacementURLs)
     DidCancelForOpenPanel()
 #if ENABLE(SANDBOX_EXTENSIONS)
     ExtendSandboxForFilesFromOpenPanel(WebKit::SandboxExtension::HandleArray sandboxExtensions)
diff --git a/Source/WebKitLegacy/mac/ChangeLog b/Source/WebKitLegacy/mac/ChangeLog
index ebe325a..397c6388 100644
--- a/Source/WebKitLegacy/mac/ChangeLog
+++ b/Source/WebKitLegacy/mac/ChangeLog
@@ -1,3 +1,12 @@
+2020-07-01  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Allow the File object to be created with a replacement file
+        https://bugs.webkit.org/show_bug.cgi?id=213825
+
+        Reviewed by Darin Adler.
+
+        * WebCoreSupport/WebPlatformStrategies.mm:
+
 2020-06-30  Sam Weinig  <weinig@apple.com>
 
         Split Color serialization out of Color classes
diff --git a/Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.mm b/Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.mm
index 2c8030c..faf93b7 100644
--- a/Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.mm
+++ b/Source/WebKitLegacy/mac/WebCoreSupport/WebPlatformStrategies.mm
@@ -93,7 +93,7 @@
 
 class WebBlobRegistry final : public BlobRegistry {
 private:
-    void registerFileBlobURL(const URL& url, Ref<BlobDataFileReference>&& reference, const String& contentType) final { m_blobRegistry.registerFileBlobURL(url, WTFMove(reference), contentType); }
+    void registerFileBlobURL(const URL& url, Ref<BlobDataFileReference>&& reference, const String&, const String& contentType) final { m_blobRegistry.registerFileBlobURL(url, WTFMove(reference), contentType); }
     void registerBlobURL(const URL& url, Vector<BlobPart>&& parts, const String& contentType) final { m_blobRegistry.registerBlobURL(url, WTFMove(parts), contentType); }
     void registerBlobURL(const URL& url, const URL& srcURL) final { m_blobRegistry.registerBlobURL(url, srcURL); }
     void registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, RefPtr<BlobDataFileReference>&& reference, const String& contentType) final { m_blobRegistry.registerBlobURLOptionallyFileBacked(url, srcURL, WTFMove(reference), contentType); }
diff --git a/Source/WebKitLegacy/win/ChangeLog b/Source/WebKitLegacy/win/ChangeLog
index 2b54396..ea7d9a2 100644
--- a/Source/WebKitLegacy/win/ChangeLog
+++ b/Source/WebKitLegacy/win/ChangeLog
@@ -1,3 +1,12 @@
+2020-07-01  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        Allow the File object to be created with a replacement file
+        https://bugs.webkit.org/show_bug.cgi?id=213825
+
+        Reviewed by Darin Adler.
+
+        * WebCoreSupport/WebPlatformStrategies.cpp:
+
 2020-06-28  Geoffrey Garen  <ggaren@apple.com>
 
         Rename initializeThreading to initialize
diff --git a/Source/WebKitLegacy/win/WebCoreSupport/WebPlatformStrategies.cpp b/Source/WebKitLegacy/win/WebCoreSupport/WebPlatformStrategies.cpp
index 9b257f4..475b21f 100644
--- a/Source/WebKitLegacy/win/WebCoreSupport/WebPlatformStrategies.cpp
+++ b/Source/WebKitLegacy/win/WebCoreSupport/WebPlatformStrategies.cpp
@@ -80,7 +80,7 @@
 
 class WebBlobRegistry final : public BlobRegistry {
 private:
-    void registerFileBlobURL(const URL& url, Ref<BlobDataFileReference>&& reference, const String& contentType) final { m_blobRegistry.registerFileBlobURL(url, WTFMove(reference), contentType); }
+    void registerFileBlobURL(const URL& url, Ref<BlobDataFileReference>&& reference, const String&, const String& contentType) final { m_blobRegistry.registerFileBlobURL(url, WTFMove(reference), contentType); }
     void registerBlobURL(const URL& url, Vector<BlobPart>&& parts, const String& contentType) final { m_blobRegistry.registerBlobURL(url, WTFMove(parts), contentType); }
     void registerBlobURL(const URL& url, const URL& srcURL) final { m_blobRegistry.registerBlobURL(url, srcURL); }
     void registerBlobURLOptionallyFileBacked(const URL& url, const URL& srcURL, RefPtr<BlobDataFileReference>&& reference, const String& contentType) final { m_blobRegistry.registerBlobURLOptionallyFileBacked(url, srcURL, WTFMove(reference), contentType); }