⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 286507 in webkit


Ignore:
Timestamp:
Dec 3, 2021, 12:17:15 PM (5 years ago)
Author:
sihui_liu@apple.com
Message:

Fetch and remove file system data via WKWebsiteDataStore
https://bugs.webkit.org/show_bug.cgi?id=233567

Reviewed by Youenn Fablet.

Source/WebCore:

  • Modules/filesystemaccess/FileSystemStorageConnection.h:

Source/WebKit:

Introduce a new WebsiteDataType value FileSystem for FileSystemAccess data. Network process now can fetch and
delete this type of data when fetching and deleteing website data (if FileSystem type is included in target
types).

To track origins that have FileSystem data, this patch introduces a new file named origin in the origin's
directory. This file will be created when OriginStorageManager is created.

To delete existing FileSystem data, network process finds origins that are requested to be deleted and have data
on disk, closes active access handles, and deletes the files. The origin file mentioned above will be deleted if
there is no other file left in the same directory, and empty directories will be deleted.

New API tests: FileSystemAccess.FetchAndRemoveData

FileSystemAccess.RemoveDataByModificationTime
FileSystemAccess.FetchDataForThirdParty

  • CMakeLists.txt:
  • DerivedSources-input.xcfilelist:
  • DerivedSources-output.xcfilelist:
  • DerivedSources.make:
  • NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:

(WebKit::WebResourceLoadStatisticsStore::monitoredDataTypes):

  • NetworkProcess/NetworkProcess.cpp:

(WebKit::NetworkProcess::fetchWebsiteData):
(WebKit::NetworkProcess::deleteWebsiteData):
(WebKit::NetworkProcess::deleteWebsiteDataForOrigins):
(WebKit::NetworkProcess::deleteAndRestrictWebsiteDataForRegistrableDomains):
(WebKit::NetworkProcess::registrableDomainsWithWebsiteData):

  • NetworkProcess/storage/FileSystemStorageHandle.h:

(WebKit::FileSystemStorageHandle::activeSyncAccessHandle const):

  • NetworkProcess/storage/FileSystemStorageManager.cpp:

(WebKit::FileSystemStorageManager::~FileSystemStorageManager):
(WebKit::FileSystemStorageManager::close):

  • NetworkProcess/storage/FileSystemStorageManager.h:
  • NetworkProcess/storage/NetworkStorageManager.cpp:

(WebKit::readOriginFromFile):
(WebKit::writeOriginToFileIfNecessary):
(WebKit::deleteOriginFileIfNecessary):
(WebKit::originDirectoryPath):
(WebKit::originFilePath):
(WebKit::NetworkStorageManager::localOriginStorageManager):
(WebKit::NetworkStorageManager::removeOriginStorageManagerIfPossible):
(WebKit::toWebsiteDataType):
(WebKit::NetworkStorageManager::forEachOriginDirectory):
(WebKit::NetworkStorageManager::fetchDataFromDisk):
(WebKit::NetworkStorageManager::fetchData):
(WebKit::NetworkStorageManager::deleteDataOnDisk):
(WebKit::NetworkStorageManager::deleteData):
(WebKit::NetworkStorageManager::deleteDataModifiedSince):
(WebKit::NetworkStorageManager::deleteDataForRegistrableDomains):
(WebKit::originPath): Deleted.

  • NetworkProcess/storage/NetworkStorageManager.h:
  • NetworkProcess/storage/OriginStorageManager.cpp:

(WebKit::OriginStorageManager::StorageBucket::toStorageIdentifier):
(WebKit::OriginStorageManager::StorageBucket::typeStoragePath const):
(WebKit::OriginStorageManager::StorageBucket::fileSystemStorageManager):
(WebKit::OriginStorageManager::StorageBucket::isActive):
(WebKit::OriginStorageManager::StorageBucket::deleteData):
(WebKit::OriginStorageManager::StorageBucket::deleteFileSystemStorageData):
(WebKit::OriginStorageManager::OriginStorageManager):
(WebKit::OriginStorageManager::isActive):
(WebKit::OriginStorageManager::deleteData):

  • NetworkProcess/storage/OriginStorageManager.h:
  • Shared/WebsiteData/WebsiteData.cpp:

(WebKit::WebsiteData::ownerProcess):

  • Shared/WebsiteData/WebsiteDataType.h:
  • UIProcess/API/Cocoa/WKWebsiteDataRecord.mm:

(dataTypesToString):

  • UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h:

(WebKit::toWebsiteDataType):
(WebKit::toWKWebsiteDataTypes):

  • UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h:
  • UIProcess/API/Cocoa/WKWebsiteDataStore.mm:

(+[WKWebsiteDataStore _allWebsiteDataTypesIncludingPrivate]):

  • WebKit.xcodeproj/project.pbxproj:
  • WebProcess/Network/NetworkProcessConnection.cpp:

(WebKit::NetworkProcessConnection::didReceiveMessage):

  • WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in: Added.

Source/WTF:

  • wtf/FileSystem.cpp:

(WTF::FileSystemImpl::readEntireFile): Read whole file content into a Vector.
(WTF::FileSystemImpl::deleteAllFilesModifiedSince): Recursively delete files and folders modified after
specified time in a directory.

  • wtf/FileSystem.h:

Tools:

  • TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm:
Location:
trunk
Files:
1 added
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r286504 r286507  
     12021-12-03  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Fetch and remove file system data via WKWebsiteDataStore
     4        https://bugs.webkit.org/show_bug.cgi?id=233567
     5
     6        Reviewed by Youenn Fablet.
     7
     8        * wtf/FileSystem.cpp:
     9        (WTF::FileSystemImpl::readEntireFile): Read whole file content into a Vector.
     10        (WTF::FileSystemImpl::deleteAllFilesModifiedSince): Recursively delete files and folders modified after
     11        specified time in a directory.
     12        * wtf/FileSystem.h:
     13
    1142021-12-03  Tim Horton  <timothy_horton@apple.com>
    215
  • trunk/Source/WTF/wtf/FileSystem.cpp

    r281694 r286507  
    515515}
    516516
     517std::optional<Vector<uint8_t>> readEntireFile(PlatformFileHandle handle)
     518{
     519    if (!FileSystem::isHandleValid(handle))
     520        return std::nullopt;
     521
     522    auto size = FileSystem::fileSize(handle).value_or(0);
     523    if (!size)
     524        return std::nullopt;
     525
     526    unsigned bytesToRead;
     527    if (!WTF::convertSafely(size, bytesToRead))
     528        return std::nullopt;
     529
     530    Vector<uint8_t> buffer(bytesToRead);
     531    unsigned totalBytesRead = FileSystem::readFromFile(handle, buffer.data(), buffer.size());
     532    if (totalBytesRead != bytesToRead)
     533        return std::nullopt;
     534
     535    return buffer;
     536}
     537
     538void deleteAllFilesModifiedSince(const String& directory, WallTime time)
     539{
     540    // This function may delete directory folder.
     541    if (time == -WallTime::infinity()) {
     542        deleteNonEmptyDirectory(directory);
     543        return;
     544    }
     545
     546    auto children = listDirectory(directory);
     547    for (auto& child : children) {
     548        auto childPath = FileSystem::pathByAppendingComponent(directory, child);
     549        auto childType = fileType(childPath);
     550        if (!childType)
     551            continue;
     552
     553        switch (*childType) {
     554        case FileType::Regular: {
     555            if (auto modificationTime = FileSystem::fileModificationTime(childPath); modificationTime && *modificationTime >= time)
     556                deleteFile(childPath);
     557            break;
     558        }
     559        case FileType::Directory:
     560            deleteAllFilesModifiedSince(childPath, time);
     561            deleteEmptyDirectory(childPath);
     562            break;
     563        case FileType::SymbolicLink:
     564            break;
     565        }
     566    }
     567
     568    FileSystem::deleteEmptyDirectory(directory);
     569}
     570
    517571#if HAVE(STD_FILESYSTEM) || HAVE(STD_EXPERIMENTAL_FILESYSTEM)
    518572
  • trunk/Source/WTF/wtf/FileSystem.h

    r284156 r286507  
    109109WTF_EXPORT_PRIVATE bool fileExists(const String&);
    110110WTF_EXPORT_PRIVATE bool deleteFile(const String&);
     111WTF_EXPORT_PRIVATE void deleteAllFilesModifiedSince(const String&, WallTime);
    111112WTF_EXPORT_PRIVATE bool deleteEmptyDirectory(const String&);
    112113WTF_EXPORT_PRIVATE bool moveFile(const String& oldPath, const String& newPath);
     
    147148using Salt = std::array<uint8_t, 8>;
    148149WTF_EXPORT_PRIVATE std::optional<Salt> readOrMakeSalt(const String& path);
     150WTF_EXPORT_PRIVATE std::optional<Vector<uint8_t>> readEntireFile(PlatformFileHandle);
    149151
    150152// Prefix is what the filename should be prefixed with, not the full path.
  • trunk/Source/WebCore/ChangeLog

    r286500 r286507  
     12021-12-03  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Fetch and remove file system data via WKWebsiteDataStore
     4        https://bugs.webkit.org/show_bug.cgi?id=233567
     5
     6        Reviewed by Youenn Fablet.
     7
     8        * Modules/filesystemaccess/FileSystemStorageConnection.h:
     9
    1102021-12-03  Alan Bujtas  <zalan@apple.com>
    211
  • trunk/Source/WebCore/Modules/filesystemaccess/FileSystemStorageConnection.h

    r286414 r286507  
    2828#include "FileSystemHandleIdentifier.h"
    2929#include "FileSystemSyncAccessHandleIdentifier.h"
     30#include "ProcessQualified.h"
    3031#include "ScriptExecutionContextIdentifier.h"
    3132#include <wtf/CompletionHandler.h>
  • trunk/Source/WebKit/CMakeLists.txt

    r286455 r286507  
    311311    WebProcess/WebCoreSupport/RemoteWebLockRegistry
    312312    WebProcess/WebCoreSupport/WebBroadcastChannelRegistry
     313    WebProcess/WebCoreSupport/WebFileSystemStorageConnection
    313314    WebProcess/WebCoreSupport/WebSpeechRecognitionConnection
    314315
  • trunk/Source/WebKit/ChangeLog

    r286505 r286507  
     12021-12-03  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Fetch and remove file system data via WKWebsiteDataStore
     4        https://bugs.webkit.org/show_bug.cgi?id=233567
     5
     6        Reviewed by Youenn Fablet.
     7
     8        Introduce a new WebsiteDataType value FileSystem for FileSystemAccess data. Network process now can fetch and
     9        delete this type of data when fetching and deleteing website data (if FileSystem type is included in target
     10        types).
     11
     12        To track origins that have FileSystem data, this patch introduces a new file named origin in the origin's
     13        directory. This file will be created when OriginStorageManager is created.
     14
     15        To delete existing FileSystem data, network process finds origins that are requested to be deleted and have data
     16        on disk, closes active access handles, and deletes the files. The origin file mentioned above will be deleted if
     17        there is no other file left in the same directory, and empty directories will be deleted.
     18
     19        New API tests: FileSystemAccess.FetchAndRemoveData
     20                       FileSystemAccess.RemoveDataByModificationTime
     21                       FileSystemAccess.FetchDataForThirdParty
     22
     23        * CMakeLists.txt:
     24        * DerivedSources-input.xcfilelist:
     25        * DerivedSources-output.xcfilelist:
     26        * DerivedSources.make:
     27        * NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
     28        (WebKit::WebResourceLoadStatisticsStore::monitoredDataTypes):
     29        * NetworkProcess/NetworkProcess.cpp:
     30        (WebKit::NetworkProcess::fetchWebsiteData):
     31        (WebKit::NetworkProcess::deleteWebsiteData):
     32        (WebKit::NetworkProcess::deleteWebsiteDataForOrigins):
     33        (WebKit::NetworkProcess::deleteAndRestrictWebsiteDataForRegistrableDomains):
     34        (WebKit::NetworkProcess::registrableDomainsWithWebsiteData):
     35        * NetworkProcess/storage/FileSystemStorageHandle.h:
     36        (WebKit::FileSystemStorageHandle::activeSyncAccessHandle const):
     37        * NetworkProcess/storage/FileSystemStorageManager.cpp:
     38        (WebKit::FileSystemStorageManager::~FileSystemStorageManager):
     39        (WebKit::FileSystemStorageManager::close):
     40        * NetworkProcess/storage/FileSystemStorageManager.h:
     41        * NetworkProcess/storage/NetworkStorageManager.cpp:
     42        (WebKit::readOriginFromFile):
     43        (WebKit::writeOriginToFileIfNecessary):
     44        (WebKit::deleteOriginFileIfNecessary):
     45        (WebKit::originDirectoryPath):
     46        (WebKit::originFilePath):
     47        (WebKit::NetworkStorageManager::localOriginStorageManager):
     48        (WebKit::NetworkStorageManager::removeOriginStorageManagerIfPossible):
     49        (WebKit::toWebsiteDataType):
     50        (WebKit::NetworkStorageManager::forEachOriginDirectory):
     51        (WebKit::NetworkStorageManager::fetchDataFromDisk):
     52        (WebKit::NetworkStorageManager::fetchData):
     53        (WebKit::NetworkStorageManager::deleteDataOnDisk):
     54        (WebKit::NetworkStorageManager::deleteData):
     55        (WebKit::NetworkStorageManager::deleteDataModifiedSince):
     56        (WebKit::NetworkStorageManager::deleteDataForRegistrableDomains):
     57        (WebKit::originPath): Deleted.
     58        * NetworkProcess/storage/NetworkStorageManager.h:
     59        * NetworkProcess/storage/OriginStorageManager.cpp:
     60        (WebKit::OriginStorageManager::StorageBucket::toStorageIdentifier):
     61        (WebKit::OriginStorageManager::StorageBucket::typeStoragePath const):
     62        (WebKit::OriginStorageManager::StorageBucket::fileSystemStorageManager):
     63        (WebKit::OriginStorageManager::StorageBucket::isActive):
     64        (WebKit::OriginStorageManager::StorageBucket::deleteData):
     65        (WebKit::OriginStorageManager::StorageBucket::deleteFileSystemStorageData):
     66        (WebKit::OriginStorageManager::OriginStorageManager):
     67        (WebKit::OriginStorageManager::isActive):
     68        (WebKit::OriginStorageManager::deleteData):
     69        * NetworkProcess/storage/OriginStorageManager.h:
     70        * Shared/WebsiteData/WebsiteData.cpp:
     71        (WebKit::WebsiteData::ownerProcess):
     72        * Shared/WebsiteData/WebsiteDataType.h:
     73        * UIProcess/API/Cocoa/WKWebsiteDataRecord.mm:
     74        (dataTypesToString):
     75        * UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h:
     76        (WebKit::toWebsiteDataType):
     77        (WebKit::toWKWebsiteDataTypes):
     78        * UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h:
     79        * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
     80        (+[WKWebsiteDataStore _allWebsiteDataTypesIncludingPrivate]):
     81        * WebKit.xcodeproj/project.pbxproj:
     82        * WebProcess/Network/NetworkProcessConnection.cpp:
     83        (WebKit::NetworkProcessConnection::didReceiveMessage):
     84        * WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in: Added.
     85
    1862021-12-03  Chris Dumez  <cdumez@apple.com>
    287
  • trunk/Source/WebKit/DerivedSources-input.xcfilelist

    r286455 r286507  
    222222$(PROJECT_DIR)/WebProcess/WebCoreSupport/WebBroadcastChannelRegistry.messages.in
    223223$(PROJECT_DIR)/WebProcess/WebCoreSupport/WebDeviceOrientationUpdateProvider.messages.in
     224$(PROJECT_DIR)/WebProcess/WebCoreSupport/WebFileSystemStorageConnection.messages.in
    224225$(PROJECT_DIR)/WebProcess/WebCoreSupport/WebSpeechRecognitionConnection.messages.in
    225226$(PROJECT_DIR)/WebProcess/WebPage/Cocoa/TextCheckingControllerProxy.messages.in
  • trunk/Source/WebKit/DerivedSources-output.xcfilelist

    r286455 r286507  
    494494$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebDeviceOrientationUpdateProviderProxyMessages.h
    495495$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebDeviceOrientationUpdateProviderProxyMessagesReplies.h
     496$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFileSystemStorageConnectionMessageReceiver.cpp
     497$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFileSystemStorageConnectionMessages.h
     498$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFileSystemStorageConnectionMessagesReplies.h
    496499$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFullScreenManagerMessageReceiver.cpp
    497500$(BUILT_PRODUCTS_DIR)/DerivedSources/WebKit2/WebFullScreenManagerMessages.h
  • trunk/Source/WebKit/DerivedSources.make

    r286455 r286507  
    223223        WebProcess/WebCoreSupport/WebBroadcastChannelRegistry \
    224224        WebProcess/WebCoreSupport/WebDeviceOrientationUpdateProvider \
     225        WebProcess/WebCoreSupport/WebFileSystemStorageConnection \
    225226        WebProcess/WebCoreSupport/WebSpeechRecognitionConnection \
    226227        WebProcess/Speech/SpeechRecognitionRealtimeMediaSourceManager \
  • trunk/Source/WebKit/NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp

    r285047 r286507  
    7575        WebsiteDataType::ServiceWorkerRegistrations,
    7676#endif
     77        WebsiteDataType::FileSystem,
    7778    }));
    7879
  • trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp

    r286484 r286507  
    15561556    }
    15571557#endif
     1558
     1559    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end()) {
     1560        iterator->value->fetchData(websiteDataTypes, [callbackAggregator](auto entries) mutable {
     1561            callbackAggregator->m_websiteData.entries.appendVector(WTFMove(entries));
     1562        });
     1563    }
    15581564}
    15591565
     
    16301636    }
    16311637#endif
     1638
     1639    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end())
     1640        iterator->value->deleteDataModifiedSince(websiteDataTypes, modifiedSince, [clearTasksHandler] { });
    16321641}
    16331642
     
    17361745    }
    17371746#endif
     1747
     1748    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end())
     1749        iterator->value->deleteData(websiteDataTypes, originDatas, [clearTasksHandler] { });
    17381750
    17391751    if (auto* networkSession = this->networkSession(sessionID)) {
     
    19601972    }
    19611973
     1974    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end()) {
     1975        iterator->value->deleteDataForRegistrableDomains(websiteDataTypes, domainsToDeleteAllNonCookieWebsiteDataFor, [callbackAggregator](auto deletedDomains) mutable {
     1976            for (auto domain : deletedDomains)
     1977                callbackAggregator->m_domains.add(WTFMove(domain));
     1978        });
     1979    }
     1980
    19621981    auto dataTypesForUIProcess = WebsiteData::filter(websiteDataTypes, WebsiteDataProcessType::UI);
    19631982    if (!dataTypesForUIProcess.isEmpty() && !domainsToDeleteAllNonCookieWebsiteDataFor.isEmpty()) {
     
    20742093                callbackAggregator->m_websiteData.entries.appendVector(entries);
    20752094            });
     2095        });
     2096    }
     2097
     2098    if (auto iterator = m_storageManagers.find(sessionID); iterator != m_storageManagers.end()) {
     2099        iterator->value->fetchData(websiteDataTypes, [callbackAggregator](auto entries) mutable {
     2100            callbackAggregator->m_websiteData.entries.appendVector(WTFMove(entries));
    20762101        });
    20772102    }
  • trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageHandle.h

    r285566 r286507  
    6363    Expected<AccessHandleInfo, FileSystemStorageError> createSyncAccessHandle();
    6464    std::optional<FileSystemStorageError> close(WebCore::FileSystemSyncAccessHandleIdentifier);
     65    std::optional<WebCore::FileSystemSyncAccessHandleIdentifier> activeSyncAccessHandle() const { return m_activeSyncAccessHandle; }
    6566
    6667private:
  • trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.cpp

    r285041 r286507  
    2929#include "FileSystemStorageError.h"
    3030#include "FileSystemStorageHandleRegistry.h"
     31#include "WebFileSystemStorageConnectionMessages.h"
    3132
    3233namespace WebKit {
     
    4344    ASSERT(!RunLoop::isMain());
    4445
    45     for (auto identifier : m_handles.keys())
    46         m_registry.unregisterHandle(identifier);
     46    close();
    4747}
    4848
     
    150150}
    151151
     152void FileSystemStorageManager::close()
     153{
     154    ASSERT(!RunLoop::isMain());
     155
     156    for (auto& [connectionID, identifiers] : m_handlesByConnection) {
     157        for (auto identifier : identifiers) {
     158            auto takenHandle = m_handles.take(identifier);
     159            m_registry.unregisterHandle(identifier);
     160
     161            // Send message to web process to invalidate active sync access handle.
     162            if (auto accessHandleIdentifier = takenHandle->activeSyncAccessHandle())
     163                IPC::Connection::send(connectionID, Messages::WebFileSystemStorageConnection::InvalidateAccessHandle(*accessHandleIdentifier), 0);
     164        }
     165    }
     166
     167    ASSERT(m_handles.isEmpty());
     168    m_handlesByConnection.clear();
     169    m_lockMap.clear();
     170}
     171
    152172} // namespace WebKit
  • trunk/Source/WebKit/NetworkProcess/storage/FileSystemStorageManager.h

    r285041 r286507  
    5050
    5151private:
     52    void close();
     53
    5254    String m_path;
    5355    FileSystemStorageHandleRegistry& m_registry;
  • trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.cpp

    r285912 r286507  
    3131#include "NetworkStorageManagerMessages.h"
    3232#include "OriginStorageManager.h"
     33#include "WebsiteDataType.h"
    3334#include <pal/crypto/CryptoDigest.h>
     35#include <wtf/Scope.h>
     36#include <wtf/persistence/PersistentDecoder.h>
     37#include <wtf/persistence/PersistentEncoder.h>
    3438#include <wtf/text/Base64.h>
    3539
    3640namespace WebKit {
     41
     42static std::optional<WebCore::ClientOrigin> readOriginFromFile(const String& filePath)
     43{
     44    ASSERT(!RunLoop::isMain());
     45
     46    if (!FileSystem::fileExists(filePath))
     47        return std::nullopt;
     48
     49    auto originFileHandle = FileSystem::openFile(filePath, FileSystem::FileOpenMode::Read);
     50    auto closeFile = makeScopeExit([&] {
     51        FileSystem::closeFile(originFileHandle);
     52    });
     53
     54    if (!FileSystem::isHandleValid(originFileHandle))
     55        return std::nullopt;
     56
     57    auto originContent = FileSystem::readEntireFile(originFileHandle);
     58    if (!originContent)
     59        return std::nullopt;
     60
     61    WTF::Persistence::Decoder decoder({ originContent->data(), originContent->size() });
     62    std::optional<WebCore::ClientOrigin> origin;
     63    decoder >> origin;
     64    return origin;
     65}
     66
     67static void writeOriginToFileIfNecessary(const String& filePath, const WebCore::ClientOrigin& origin)
     68{
     69    if (FileSystem::fileExists(filePath))
     70        return;
     71
     72    FileSystem::makeAllDirectories(FileSystem::parentPath(filePath));
     73    auto originFileHandle = FileSystem::openFile(filePath, FileSystem::FileOpenMode::ReadWrite);
     74    auto closeFile = makeScopeExit([&] {
     75        FileSystem::closeFile(originFileHandle);
     76    });
     77
     78    if (!FileSystem::isHandleValid(originFileHandle)) {
     79        LOG_ERROR("writeOriginToFileIfNecessary: Failed to open origin file");
     80        return;
     81    }
     82
     83    WTF::Persistence::Encoder encoder;
     84    encoder << origin;
     85    FileSystem::writeToFile(originFileHandle, encoder.buffer(), encoder.bufferSize());
     86}
     87
     88static void deleteOriginFileIfNecessary(const String& filePath)
     89{
     90    auto parentPath = FileSystem::parentPath(filePath);
     91    auto children = FileSystem::listDirectory(parentPath);
     92    if (children.size() == 1)
     93        FileSystem::deleteFile(filePath);
     94}
    3795
    3896Ref<NetworkStorageManager> NetworkStorageManager::create(PAL::SessionID sessionID, const String& path)
     
    117175}
    118176
    119 static String originPath(const String& rootPath, const WebCore::ClientOrigin& origin, FileSystem::Salt salt)
     177static String originDirectoryPath(const String& rootPath, const WebCore::ClientOrigin& origin, FileSystem::Salt salt)
    120178{
    121179    if (rootPath.isEmpty())
     
    127185}
    128186
     187static String originFilePath(const String& directory)
     188{
     189    return FileSystem::pathByAppendingComponent(directory, "origin"_s);
     190}
     191
    129192OriginStorageManager& NetworkStorageManager::localOriginStorageManager(const WebCore::ClientOrigin& origin)
    130193{
     
    132195
    133196    return *m_localOriginStorageManagers.ensure(origin, [&] {
    134         return makeUnique<OriginStorageManager>(originPath(m_path, origin, m_salt));
     197        auto originDirectory = originDirectoryPath(m_path, origin, m_salt);
     198        writeOriginToFileIfNecessary(originFilePath(originDirectory), origin);
     199        return makeUnique<OriginStorageManager>(WTFMove(originDirectory));
    135200    }).iterator->value;
     201}
     202
     203void NetworkStorageManager::removeOriginStorageManagerIfPossible(const WebCore::ClientOrigin& origin)
     204{
     205    if (auto iterator = m_localOriginStorageManagers.find(origin); iterator != m_localOriginStorageManagers.end()) {
     206        if (!iterator->value->isActive())
     207            m_localOriginStorageManagers.remove(iterator);
     208    }
    136209}
    137210
     
    306379}
    307380
     381static std::optional<WebsiteDataType> toWebsiteDataType(const String& storageType)
     382{
     383    if (storageType == "FileSystem")
     384        return WebsiteDataType::FileSystem;
     385
     386    return std::nullopt;
     387}
     388
     389void NetworkStorageManager::forEachOriginDirectory(const Function<void(const String&)>& apply)
     390{
     391    for (auto& topOrigin : FileSystem::listDirectory(m_path)) {
     392        auto topOriginDirectory = FileSystem::pathByAppendingComponent(m_path, topOrigin);
     393        auto openingOrigins = FileSystem::listDirectory(topOriginDirectory);
     394        if (openingOrigins.isEmpty()) {
     395            FileSystem::deleteEmptyDirectory(topOriginDirectory);
     396            continue;
     397        }
     398
     399        for (auto& openingOrigin : openingOrigins) {
     400            auto openingOriginDirectory = FileSystem::pathByAppendingComponent(topOriginDirectory, openingOrigin);
     401            apply(openingOriginDirectory);
     402        }
     403    }
     404}
     405
     406Vector<WebsiteData::Entry> NetworkStorageManager::fetchDataFromDisk(OptionSet<WebsiteDataType> targetTypes)
     407{
     408    ASSERT(!RunLoop::isMain());
     409
     410    HashMap<WebCore::SecurityOriginData, OptionSet<WebsiteDataType>> originTypes;
     411    forEachOriginDirectory([&](auto directory) mutable {
     412        auto origin = readOriginFromFile(originFilePath(directory));
     413        if (!origin)
     414            return;
     415
     416        for (auto& storageType : FileSystem::listDirectory(directory)) {
     417            if (auto type = toWebsiteDataType(storageType); type && targetTypes.contains(*type)) {
     418                // Return both top origin and opening origin for this data.
     419                originTypes.add(origin->clientOrigin, OptionSet<WebsiteDataType> { }).iterator->value.add(*type);
     420                originTypes.add(origin->topOrigin, OptionSet<WebsiteDataType> { }).iterator->value.add(*type);
     421            }
     422        }
     423    });
     424
     425    Vector<WebsiteData::Entry> entries;
     426    for (auto [origin, types] : originTypes) {
     427        for (auto type : types)
     428            entries.append({ WebsiteData::Entry { origin, type, 0 } });
     429    }
     430
     431    return entries;
     432}
     433
     434void NetworkStorageManager::fetchData(OptionSet<WebsiteDataType> types, CompletionHandler<void(Vector<WebsiteData::Entry>&&)>&& completionHandler)
     435{
     436    ASSERT(RunLoop::isMain());
     437    ASSERT(!m_closed);
     438
     439    m_queue->dispatch([this, protectedThis = Ref { *this }, types, completionHandler = WTFMove(completionHandler)]() mutable {
     440        auto entries = fetchDataFromDisk(types);
     441        RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), entries = crossThreadCopy(WTFMove(entries))]() mutable {
     442            completionHandler(WTFMove(entries));
     443        });
     444    });
     445}
     446
     447Vector<WebCore::ClientOrigin> NetworkStorageManager::deleteDataOnDisk(OptionSet<WebsiteDataType> types, WallTime modifiedSinceTime, const Function<bool(const WebCore::ClientOrigin&)>& filter)
     448{
     449    ASSERT(!RunLoop::isMain());
     450
     451    Vector<WebCore::ClientOrigin> deletedOrigins;
     452    forEachOriginDirectory([&](auto directory) mutable {
     453        auto filePath = originFilePath(directory);
     454        auto origin = readOriginFromFile(filePath);
     455        if (!origin) {
     456            // If origin cannot be retrieved, but we are asked to remove data for all origins, remove it.
     457            RELEASE_LOG_ERROR(Storage, "NetworkStorageManager::deleteDataOnDisk failed to read origin from '%s'", filePath.utf8().data());
     458            if (filter(WebCore::ClientOrigin { })) {
     459                FileSystem::deleteAllFilesModifiedSince(directory, modifiedSinceTime);
     460                FileSystem::deleteEmptyDirectory(directory);
     461            }
     462            return;
     463        }
     464
     465        if (!filter(*origin))
     466            return;
     467
     468        deletedOrigins.append(*origin);
     469        localOriginStorageManager(*origin).deleteData(types, modifiedSinceTime);
     470        removeOriginStorageManagerIfPossible(*origin);
     471        deleteOriginFileIfNecessary(filePath);
     472        FileSystem::deleteEmptyDirectory(directory);
     473    });
     474
     475    return deletedOrigins;
     476}
     477
     478void NetworkStorageManager::deleteData(OptionSet<WebsiteDataType> types, const Vector<WebCore::SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
     479{
     480    ASSERT(RunLoop::isMain());
     481    ASSERT(!m_closed);
     482
     483    m_queue->dispatch([this, protectedThis = Ref { *this }, types, origins = crossThreadCopy(origins), completionHandler = WTFMove(completionHandler)]() mutable {
     484        HashSet<WebCore::SecurityOriginData> originSet;
     485        originSet.reserveInitialCapacity(origins.size());
     486        for (auto origin : origins)
     487            originSet.add(WTFMove(origin));
     488
     489        deleteDataOnDisk(types, -WallTime::infinity(), [&originSet](auto origin) {
     490            return originSet.contains(origin.topOrigin) || originSet.contains(origin.clientOrigin);
     491        });
     492
     493        RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler)]() mutable {
     494            completionHandler();
     495        });
     496    });
     497}
     498
     499void NetworkStorageManager::deleteDataModifiedSince(OptionSet<WebsiteDataType> types, WallTime modifiedSinceTime, CompletionHandler<void()>&& completionHandler)
     500{
     501    ASSERT(RunLoop::isMain());
     502    ASSERT(!m_closed);
     503
     504    m_queue->dispatch([this, protectedThis = Ref { *this }, types, modifiedSinceTime, completionHandler = WTFMove(completionHandler)]() mutable {
     505        deleteDataOnDisk(types, modifiedSinceTime, [](auto&) {
     506            return true;
     507        });
     508
     509        RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler)]() mutable {
     510            completionHandler();
     511        });
     512    });
     513}
     514
     515void NetworkStorageManager::deleteDataForRegistrableDomains(OptionSet<WebsiteDataType> types, const Vector<WebCore::RegistrableDomain>& domains, CompletionHandler<void(HashSet<WebCore::RegistrableDomain>&&)>&& completionHandler)
     516{
     517    ASSERT(RunLoop::isMain());
     518    ASSERT(!m_closed);
     519
     520    m_queue->dispatch([this, protectedThis = Ref { *this }, types, domains = crossThreadCopy(domains), completionHandler = WTFMove(completionHandler)]() mutable {
     521        auto deletedOrigins = deleteDataOnDisk(types, -WallTime::infinity(), [&domains](auto& origin) {
     522            auto domain = WebCore::RegistrableDomain::uncheckedCreateFromHost(origin.clientOrigin.host);
     523            return domains.contains(domain);
     524        });
     525
     526        HashSet<WebCore::RegistrableDomain> deletedDomains;
     527        for (auto origin : deletedOrigins) {
     528            auto domain = WebCore::RegistrableDomain::uncheckedCreateFromHost(origin.clientOrigin.host);
     529            deletedDomains.add(domain);
     530        }
     531
     532        RunLoop::main().dispatch([protectedThis = WTFMove(protectedThis), completionHandler = WTFMove(completionHandler), domains = crossThreadCopy(WTFMove(deletedDomains))]() mutable {
     533            completionHandler(WTFMove(domains));
     534        });
     535    });
     536}
     537
    308538} // namespace WebKit
    309539
  • trunk/Source/WebKit/NetworkProcess/storage/NetworkStorageManager.h

    r285912 r286507  
    2929#include "FileSystemStorageError.h"
    3030#include "OriginStorageManager.h"
     31#include "WebsiteData.h"
    3132#include <WebCore/ClientOrigin.h>
    3233#include <WebCore/FileSystemHandleIdentifier.h>
    3334#include <WebCore/FileSystemSyncAccessHandleIdentifier.h>
    3435#include <pal/SessionID.h>
     36#include <wtf/Forward.h>
    3537
    3638namespace IPC {
     
    5658    void close();
    5759    void clearStorageForTesting(CompletionHandler<void()>&&);
     60    void fetchData(OptionSet<WebsiteDataType>, CompletionHandler<void(Vector<WebsiteData::Entry>&&)>&&);
     61    void deleteData(OptionSet<WebsiteDataType>, const Vector<WebCore::SecurityOriginData>&, CompletionHandler<void()>&&);
     62    void deleteDataModifiedSince(OptionSet<WebsiteDataType>, WallTime, CompletionHandler<void()>&&);
     63    void deleteDataForRegistrableDomains(OptionSet<WebsiteDataType>, const Vector<WebCore::RegistrableDomain>&, CompletionHandler<void(HashSet<WebCore::RegistrableDomain>&&)>&&);
    5864
    5965private:
     
    6167    ~NetworkStorageManager();
    6268    OriginStorageManager& localOriginStorageManager(const WebCore::ClientOrigin&);
     69    void removeOriginStorageManagerIfPossible(const WebCore::ClientOrigin&);
    6370    FileSystemStorageHandleRegistry& fileSystemStorageHandleRegistry();
     71
     72    void forEachOriginDirectory(const Function<void(const String&)>&);
     73    Vector<WebsiteData::Entry> fetchDataFromDisk(OptionSet<WebsiteDataType>);
     74    Vector<WebCore::ClientOrigin> deleteDataOnDisk(OptionSet<WebsiteDataType>, WallTime, const Function<bool(const WebCore::ClientOrigin&)>&);
    6475
    6576    // IPC::MessageReceiver (implemented by generated code)
  • trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.cpp

    r283029 r286507  
    5252    }
    5353
    54     String typeStoragePath(const String& storageIdentifier) const
     54    enum class StorageType : uint8_t {
     55        FileSystem,
     56    };
     57
     58    static String toStorageIdentifier(StorageType type)
    5559    {
    56         return m_rootPath.isEmpty() ? emptyString() : FileSystem::pathByAppendingComponent(m_rootPath, storageIdentifier);
     60        switch (type) {
     61        case StorageType::FileSystem:
     62            return "FileSystem"_s;
     63        default:
     64            break;
     65        }
     66        ASSERT_NOT_REACHED();
     67        return ""_s;
     68    }
     69
     70    String typeStoragePath(StorageType type) const
     71    {
     72        auto storageIdentifier = toStorageIdentifier(type);
     73        if (m_rootPath.isEmpty() || storageIdentifier.isEmpty())
     74            return emptyString();
     75
     76        return FileSystem::pathByAppendingComponent(m_rootPath, storageIdentifier);
    5777    }
    5878
     
    6080    {
    6181        if (!m_fileSystemStorageManager)
    62             m_fileSystemStorageManager = makeUnique<FileSystemStorageManager>(typeStoragePath("FileSystem"), registry);
     82            m_fileSystemStorageManager = makeUnique<FileSystemStorageManager>(typeStoragePath(StorageType::FileSystem), registry);
    6383
    6484        return *m_fileSystemStorageManager;
    6585    }
    6686
     87    bool isActive()
     88    {
     89        return !!m_fileSystemStorageManager;
     90    }
     91
     92    void deleteData(OptionSet<WebsiteDataType> types, WallTime modifiedSinceTime)
     93    {
     94        if (types.contains(WebsiteDataType::FileSystem))
     95            deleteFileSystemStorageData(modifiedSinceTime);
     96
     97        FileSystem::deleteNonEmptyDirectory(m_rootPath);
     98    }
     99
    67100private:
     101    void deleteFileSystemStorageData(WallTime modifiedSinceTime)
     102    {
     103        m_fileSystemStorageManager = nullptr;
     104
     105        auto fileSystemStoragePath = typeStoragePath(StorageType::FileSystem);
     106        FileSystem::deleteAllFilesModifiedSince(fileSystemStoragePath, modifiedSinceTime);
     107    }
     108
    68109    String m_rootPath;
    69110    String m_identifier;
     
    75116    : m_path(WTFMove(path))
    76117{
     118    ASSERT(!RunLoop::isMain());
    77119}
    78120
     
    104146}
    105147
     148bool OriginStorageManager::isActive()
     149{
     150    return defaultBucket().isActive();
     151}
     152
     153void OriginStorageManager::deleteData(OptionSet<WebsiteDataType> types, WallTime modifiedSince)
     154{
     155    ASSERT(!RunLoop::isMain());
     156    defaultBucket().deleteData(types, modifiedSince);
     157}
     158
    106159} // namespace WebKit
    107160
  • trunk/Source/WebKit/NetworkProcess/storage/OriginStorageManager.h

    r283271 r286507  
    2929#include <wtf/text/WTFString.h>
    3030
     31namespace WebCore {
     32struct ClientOrigin;
     33}
     34
    3135namespace WebKit {
    3236
    3337class FileSystemStorageHandleRegistry;
    3438class FileSystemStorageManager;
     39enum class WebsiteDataType : uint32_t;
    3540
    3641class OriginStorageManager {
     
    4449    void persist();
    4550    FileSystemStorageManager& fileSystemStorageManager(FileSystemStorageHandleRegistry&);
     51    bool isActive();
     52    void deleteData(OptionSet<WebsiteDataType>, WallTime);
    4653
    4754private:
     
    4956    class StorageBucket;
    5057    StorageBucket& defaultBucket();
     58
     59    void createOriginFileIfNecessary(const WebCore::ClientOrigin&);
     60    void deleteOriginFileIfNecessary();
    5161
    5262    std::unique_ptr<StorageBucket> m_defaultBucket;
  • trunk/Source/WebKit/Shared/WebsiteData/WebsiteData.cpp

    r285047 r286507  
    130130        return WebsiteDataProcessType::Network;
    131131#endif
     132    case WebsiteDataType::FileSystem:
     133        return WebsiteDataProcessType::Network;
    132134    }
    133135
  • trunk/Source/WebKit/Shared/WebsiteData/WebsiteDataType.h

    r285047 r286507  
    5353    AlternativeServices = 1 << 18,
    5454#endif
     55    FileSystem = 1 << 19,
    5556};
    5657
     
    8081        WebKit::WebsiteDataType::DOMCache,
    8182        WebKit::WebsiteDataType::DeviceIdHashSalt,
    82         WebKit::WebsiteDataType::PrivateClickMeasurements
     83        WebKit::WebsiteDataType::PrivateClickMeasurements,
    8384#if HAVE(CFNETWORK_ALTERNATIVE_SERVICE)
    84         , WebKit::WebsiteDataType::AlternativeServices
     85        WebKit::WebsiteDataType::AlternativeServices,
    8586#endif
     87        WebKit::WebsiteDataType::FileSystem
    8688    >;
    8789};
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecord.mm

    r276880 r286507  
    5252NSString * const _WKWebsiteDataTypePrivateClickMeasurements = @"_WKWebsiteDataTypePrivateClickMeasurements";
    5353NSString * const _WKWebsiteDataTypeAlternativeServices = @"_WKWebsiteDataTypeAlternativeServices";
     54NSString * const _WKWebsiteDataTypeFileSystem = @"_WKWebsiteDataTypeFileSystem";
    5455
    5556#if PLATFORM(MAC)
     
    111112    if ([dataTypes containsObject:_WKWebsiteDataTypeAlternativeServices])
    112113        [array addObject:@"Alternative Services"];
     114    if ([dataTypes containsObject:_WKWebsiteDataTypeFileSystem])
     115        [array addObject:@"File System"];
    113116
    114117    return [array componentsJoinedByString:@", "];
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordInternal.h

    r285047 r286507  
    7878        return WebsiteDataType::AlternativeServices;
    7979#endif
     80    if ([websiteDataType isEqualToString:_WKWebsiteDataTypeFileSystem])
     81        return WebsiteDataType::FileSystem;
    8082    return std::nullopt;
    8183}
     
    135137        [wkWebsiteDataTypes addObject:_WKWebsiteDataTypeAlternativeServices];
    136138#endif
     139    if (websiteDataTypes.contains(WebsiteDataType::FileSystem))
     140        [wkWebsiteDataTypes addObject:_WKWebsiteDataTypeFileSystem];
    137141
    138142    return wkWebsiteDataTypes;
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataRecordPrivate.h

    r279089 r286507  
    3838WK_EXTERN NSString * const _WKWebsiteDataTypePrivateClickMeasurements WK_API_AVAILABLE(macos(12.0), ios(15.0));
    3939WK_EXTERN NSString * const _WKWebsiteDataTypeAlternativeServices WK_API_AVAILABLE(macos(11.0), ios(14.0));
     40WK_EXTERN NSString * const _WKWebsiteDataTypeFileSystem WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
    4041
    4142#if !TARGET_OS_IPHONE
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm

    r285121 r286507  
    249249            _WKWebsiteDataTypeAdClickAttributions,
    250250            _WKWebsiteDataTypePrivateClickMeasurements,
    251             _WKWebsiteDataTypeAlternativeServices
     251            _WKWebsiteDataTypeAlternativeServices,
     252            _WKWebsiteDataTypeFileSystem
    252253#if !TARGET_OS_IPHONE
    253254            , _WKWebsiteDataTypePlugInData
  • trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj

    r286487 r286507  
    15001500                93D6B7B925534A170058DD3A /* WKSpeechRecognitionPermissionCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D6B7B725534A110058DD3A /* WKSpeechRecognitionPermissionCallback.h */; settings = {ATTRIBUTES = (Private, ); }; };
    15011501                93E6A4EE1BC5DD3900F8A0E7 /* _WKHitTestResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E6A4ED1BC5DD3900F8A0E7 /* _WKHitTestResult.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1502                93E799852756FA550074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E799822756FA540074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp */; };
     1503                93E799872756FAB40074008A /* WebFileSystemStorageConnectionMessagesReplies.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E799832756FA540074008A /* WebFileSystemStorageConnectionMessagesReplies.h */; };
     1504                93E799882756FAC20074008A /* WebFileSystemStorageConnectionMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E799812756FA530074008A /* WebFileSystemStorageConnectionMessages.h */; };
    15021505                93F549B41E3174B7000E7239 /* WKSnapshotConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F549B31E3174B7000E7239 /* WKSnapshotConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
    15031506                950F2880252414EA00B74F1C /* WKMouseDeviceObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 950F287E252414E900B74F1C /* WKMouseDeviceObserver.h */; };
     
    53025305                93D6B7B825534A120058DD3A /* WKSpeechRecognitionPermissionCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKSpeechRecognitionPermissionCallback.cpp; sourceTree = "<group>"; };
    53035306                93E6A4ED1BC5DD3900F8A0E7 /* _WKHitTestResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKHitTestResult.h; sourceTree = "<group>"; };
     5307                93E7997E2756F6700074008A /* WebFileSystemStorageConnection.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebFileSystemStorageConnection.messages.in; sourceTree = "<group>"; };
     5308                93E799812756FA530074008A /* WebFileSystemStorageConnectionMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebFileSystemStorageConnectionMessages.h; sourceTree = "<group>"; };
     5309                93E799822756FA540074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebFileSystemStorageConnectionMessageReceiver.cpp; sourceTree = "<group>"; };
     5310                93E799832756FA540074008A /* WebFileSystemStorageConnectionMessagesReplies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebFileSystemStorageConnectionMessagesReplies.h; sourceTree = "<group>"; };
    53045311                93F549B31E3174B7000E7239 /* WKSnapshotConfiguration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKSnapshotConfiguration.h; sourceTree = "<group>"; };
    53055312                93F549B51E3174DA000E7239 /* WKSnapshotConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKSnapshotConfiguration.mm; sourceTree = "<group>"; };
     
    1058310590                                9354242B2703BDCB005CA72C /* WebFileSystemStorageConnection.cpp */,
    1058410591                                9354242A2703BDCB005CA72C /* WebFileSystemStorageConnection.h */,
     10592                                93E7997E2756F6700074008A /* WebFileSystemStorageConnection.messages.in */,
    1058510593                                BC111A58112F4FBB00337BAB /* WebFrameLoaderClient.cpp */,
    1058610594                                BC032D6A10F4378D0058C15A /* WebFrameLoaderClient.h */,
     
    1206012068                                E3866B042399979C00F88FE9 /* WebDeviceOrientationUpdateProviderProxyMessageReceiver.cpp */,
    1206112069                                E3866B052399979C00F88FE9 /* WebDeviceOrientationUpdateProviderProxyMessages.h */,
     12070                                93E799822756FA540074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp */,
     12071                                93E799812756FA530074008A /* WebFileSystemStorageConnectionMessages.h */,
     12072                                93E799832756FA540074008A /* WebFileSystemStorageConnectionMessagesReplies.h */,
    1206212073                                CD73BA48131ACD8E00EEDED2 /* WebFullScreenManagerMessageReceiver.cpp */,
    1206312074                                CD73BA49131ACD8E00EEDED2 /* WebFullScreenManagerMessages.h */,
     
    1330713318                                BC111B5D112F629800337BAB /* WebEventFactory.h in Headers */,
    1330813319                                9354242C2703BDCB005CA72C /* WebFileSystemStorageConnection.h in Headers */,
     13320                                93E799882756FAC20074008A /* WebFileSystemStorageConnectionMessages.h in Headers */,
     13321                                93E799872756FAB40074008A /* WebFileSystemStorageConnectionMessagesReplies.h in Headers */,
    1330913322                                1A90C1EE1264FD50003E44D4 /* WebFindOptions.h in Headers */,
    1331013323                                BCE469541214E6CB000B98EB /* WebFormClient.h in Headers */,
     
    1540315416                                E3866B092399A2D500F88FE9 /* WebDeviceOrientationUpdateProviderProxyMessageReceiver.cpp in Sources */,
    1540415417                                2D92A789212B6AB100F493FD /* WebEvent.cpp in Sources */,
     15418                                93E799852756FA550074008A /* WebFileSystemStorageConnectionMessageReceiver.cpp in Sources */,
    1540515419                                CD73BA4E131ACDB700EEDED2 /* WebFullScreenManagerMessageReceiver.cpp in Sources */,
    1540615420                                CD73BA47131ACC9A00EEDED2 /* WebFullScreenManagerProxyMessageReceiver.cpp in Sources */,
  • trunk/Source/WebKit/WebProcess/Network/NetworkProcessConnection.cpp

    r282712 r286507  
    3838#include "WebCookieJar.h"
    3939#include "WebCoreArgumentCoders.h"
     40#include "WebFileSystemStorageConnection.h"
     41#include "WebFileSystemStorageConnectionMessages.h"
    4042#include "WebFrame.h"
    4143#include "WebIDBConnectionToServer.h"
     
    120122        return;
    121123    }
     124    if (decoder.messageReceiverName() == Messages::WebFileSystemStorageConnection::messageReceiverName()) {
     125        WebProcess::singleton().fileSystemStorageConnection().didReceiveMessage(connection, decoder);
     126        return;
     127    }
    122128
    123129#if USE(LIBWEBRTC)
  • trunk/Tools/ChangeLog

    r286505 r286507  
     12021-12-03  Sihui Liu  <sihui_liu@apple.com>
     2
     3        Fetch and remove file system data via WKWebsiteDataStore
     4        https://bugs.webkit.org/show_bug.cgi?id=233567
     5
     6        Reviewed by Youenn Fablet.
     7
     8        * TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm:
     9
    1102021-12-03  Chris Dumez  <cdumez@apple.com>
    211
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/FileSystemAccess.mm

    r286414 r286507  
    3030#import "DeprecatedGlobalValues.h"
    3131#import "PlatformUtilities.h"
     32#import "TestUIDelegate.h"
    3233#import "TestURLSchemeHandler.h"
    3334#import "TestWKWebView.h"
     
    3536#import <WebKit/WKWebViewConfigurationPrivate.h>
    3637#import <WebKit/WKWebViewPrivate.h>
     38#import <WebKit/WKWebsiteDataRecordPrivate.h>
    3739
    3840@interface FileSystemAccessMessageHandler : NSObject <WKScriptMessageHandler>
     
    4951@end
    5052
    51 static NSString *mainFrameString = @"<script> \
     53static NSString *workerFrameString = @"<script> \
    5254    function start() { \
    5355        var worker = new Worker('worker.js'); \
     
    116118
    117119    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
    118     [webView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
     120    [webView loadHTMLString:workerFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
    119121    TestWebKitAPI::Util::run(&receivedScriptMessage);
    120122    receivedScriptMessage = false;
     
    127129
    128130    auto secondWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
    129     [secondWebView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
     131    [secondWebView loadHTMLString:workerFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
    130132    TestWebKitAPI::Util::run(&receivedScriptMessage);
    131133    receivedScriptMessage = false;
     
    169171
    170172    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
    171     [webView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
     173    [webView loadHTMLString:workerFrameString baseURL:[NSURL URLWithString:@"webkit://webkit.org"]];
    172174    TestWebKitAPI::Util::run(&receivedScriptMessage);
    173175    receivedScriptMessage = false;
     
    259261}
    260262
     263static NSString *testString = @"<script> \
     264    async function open(shouldCreateFile) \
     265    { \
     266        try { \
     267            var rootHandle = await navigator.storage.getDirectory(); \
     268            var fileHandle = await rootHandle.getFileHandle('file-system-access.txt', { 'create' : shouldCreateFile }); \
     269            window.webkit.messageHandlers.testHandler.postMessage('file is opened'); \
     270        } catch(err) { \
     271            window.webkit.messageHandlers.testHandler.postMessage('error: ' + err.name + ' - ' + err.message); \
     272        } \
     273    } \
     274    open(true); \
     275    </script>";
     276
     277TEST(FileSystemAccess, FetchAndRemoveData)
     278{
     279    auto handler = adoptNS([[FileSystemAccessMessageHandler alloc] init]);
     280    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     281    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
     282    auto websiteDataStore = [configuration websiteDataStore];
     283    auto types = [NSSet setWithObject:_WKWebsiteDataTypeFileSystem];
     284
     285    // Remove existing data.
     286    done = false;
     287    [websiteDataStore removeDataOfTypes:types modifiedSince:[NSDate distantPast] completionHandler:^ {
     288        done = true;
     289    }];
     290    TestWebKitAPI::Util::run(&done);
     291
     292    auto preferences = [configuration preferences];
     293    preferences._fileSystemAccessEnabled = YES;
     294    preferences._storageAPIEnabled = YES;
     295    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
     296    [webView loadHTMLString:testString baseURL:[NSURL URLWithString:@"https://webkit.org"]];
     297    TestWebKitAPI::Util::run(&receivedScriptMessage);
     298    receivedScriptMessage = false;
     299    EXPECT_WK_STREQ(@"file is opened", [lastScriptMessage body]);
     300
     301    // Fetch data and remove it by origin.
     302    done = false;
     303    [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
     304        EXPECT_EQ(records.count, 1u);
     305        auto record = [records objectAtIndex:0];
     306        EXPECT_STREQ("webkit.org", [record.displayName UTF8String]);
     307
     308        // Remove data.
     309        [websiteDataStore removeDataOfTypes:types forDataRecords:records completionHandler:^{
     310            done = true;
     311        }];
     312    }];
     313    TestWebKitAPI::Util::run(&done);
     314
     315    // Fetch data after removal.
     316    done = false;
     317    [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
     318        EXPECT_EQ(records.count, 0u);
     319        done = true;
     320    }];
     321
     322    // File cannot be opened after data removal.
     323    [webView evaluateJavaScript:@"open(false)" completionHandler:nil];
     324    TestWebKitAPI::Util::run(&receivedScriptMessage);
     325    receivedScriptMessage = false;
     326    EXPECT_WK_STREQ(@"error: NotFoundError - The object can not be found here.", [lastScriptMessage body]);
     327}
     328
     329TEST(FileSystemAccess, RemoveDataByModificationTime)
     330{
     331    auto handler = adoptNS([[FileSystemAccessMessageHandler alloc] init]);
     332    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     333    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
     334    auto preferences = [configuration preferences];
     335    preferences._fileSystemAccessEnabled = YES;
     336    preferences._storageAPIEnabled = YES;
     337    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
     338    [webView loadHTMLString:testString baseURL:[NSURL URLWithString:@"https://webkit.org"]];
     339    TestWebKitAPI::Util::run(&receivedScriptMessage);
     340    receivedScriptMessage = false;
     341    EXPECT_WK_STREQ(@"file is opened", [lastScriptMessage body]);
     342
     343    auto websiteDataStore = [configuration websiteDataStore];
     344    auto types = [NSSet setWithObject:_WKWebsiteDataTypeFileSystem];
     345    done = false;
     346    __block NSUInteger recordsCount;
     347    [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
     348        recordsCount = records.count;
     349        EXPECT_GT(recordsCount, 0u);
     350        done = true;
     351    }];
     352    TestWebKitAPI::Util::run(&done);
     353
     354    done = false;
     355    [websiteDataStore removeDataOfTypes:types modifiedSince:[NSDate now] completionHandler:^ {
     356        [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
     357            recordsCount = records.count;
     358            EXPECT_EQ(records.count, recordsCount);
     359            done = true;
     360        }];
     361    }];
     362    TestWebKitAPI::Util::run(&done);
     363
     364    done = false;
     365    [websiteDataStore removeDataOfTypes:types modifiedSince:[NSDate distantPast] completionHandler:^ {
     366        [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
     367            EXPECT_EQ(records.count, 0u);
     368            done = true;
     369        }];
     370    }];
     371    TestWebKitAPI::Util::run(&done);
     372}
     373
     374static NSString *mainFrameString = @"<script> \
     375    function postResult(event) \
     376    { \
     377        window.webkit.messageHandlers.testHandler.postMessage(event.data); \
     378    } \
     379    addEventListener('message', postResult, false); \
     380    </script> \
     381    <iframe src='https://127.0.0.1:9091/'>";
     382
     383static const char* frameBytes = R"TESTRESOURCE(
     384<script>
     385function postMessage(message)
     386{
     387    parent.postMessage(message, '*');
     388}
     389async function open()
     390{
     391    try {
     392        var rootHandle = await navigator.storage.getDirectory();
     393        var fileHandle = await rootHandle.getFileHandle('file-system-access.txt', { 'create' : true });
     394        postMessage('file is opened');
     395    } catch(err) {
     396        postMessage('error: ' + err.name + ' - ' + err.message);
     397    }
     398}
     399open();
     400</script>
     401)TESTRESOURCE";
     402
     403TEST(FileSystemAccess, FetchDataForThirdParty)
     404{
     405    TestWebKitAPI::HTTPServer server({
     406        { "/", { frameBytes } },
     407    }, TestWebKitAPI::HTTPServer::Protocol::Https, nullptr, nullptr, 9091);
     408
     409    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     410    auto handler = adoptNS([[FileSystemAccessMessageHandler alloc] init]);
     411    [[configuration userContentController] addScriptMessageHandler:handler.get() name:@"testHandler"];
     412    auto preferences = [configuration preferences];
     413    preferences._fileSystemAccessEnabled = YES;
     414    preferences._storageAPIEnabled = YES;
     415
     416    auto websiteDataStore = [configuration websiteDataStore];
     417    auto types = [NSSet setWithObject:_WKWebsiteDataTypeFileSystem];
     418    done = false;
     419    [websiteDataStore removeDataOfTypes:types modifiedSince:[NSDate distantPast] completionHandler:^ {
     420        done = true;
     421    }];
     422    TestWebKitAPI::Util::run(&done);
     423
     424    auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
     425    auto navigationDelegate = adoptNS([TestNavigationDelegate new]);
     426    [navigationDelegate setDidReceiveAuthenticationChallenge:^(WKWebView *, NSURLAuthenticationChallenge *challenge, void (^callback)(NSURLSessionAuthChallengeDisposition, NSURLCredential *)) {
     427        EXPECT_WK_STREQ(challenge.protectionSpace.authenticationMethod, NSURLAuthenticationMethodServerTrust);
     428        callback(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
     429    }];
     430    [navigationDelegate setDecidePolicyForNavigationAction:[&](WKNavigationAction *action, void (^decisionHandler)(WKNavigationActionPolicy)) {
     431        decisionHandler(WKNavigationActionPolicyAllow);
     432    }];
     433    [webView setNavigationDelegate:navigationDelegate.get()];
     434
     435    [webView loadHTMLString:mainFrameString baseURL:[NSURL URLWithString:@"https://webkit.org"]];
     436    TestWebKitAPI::Util::run(&receivedScriptMessage);
     437    receivedScriptMessage = false;
     438    EXPECT_WK_STREQ(@"file is opened", [lastScriptMessage body]);
     439
     440    done = false;
     441    [websiteDataStore fetchDataRecordsOfTypes:types completionHandler:^(NSArray<WKWebsiteDataRecord *> *records) {
     442        // Should return both opening origin and top origin.
     443        EXPECT_EQ(records.count, 2u);
     444        auto sortFunction = ^(WKWebsiteDataRecord *record1, WKWebsiteDataRecord *record2){
     445            return [record1.displayName compare:record2.displayName];
     446        };
     447        auto sortedRecords = [records sortedArrayUsingComparator:sortFunction];
     448        EXPECT_WK_STREQ(@"127.0.0.1", [sortedRecords objectAtIndex:0].displayName);
     449        EXPECT_WK_STREQ(@"webkit.org", [sortedRecords objectAtIndex:1].displayName);
     450        done = true;
     451    }];
     452    TestWebKitAPI::Util::run(&done);
     453}
     454
    261455#endif // USE(APPLE_INTERNAL_SDK)
Note: See TracChangeset for help on using the changeset viewer.