summaryrefslogtreecommitdiff
path: root/Source/WebKit2/UIProcess/WebsiteData
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebKit2/UIProcess/WebsiteData
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebKit2/UIProcess/WebsiteData')
-rw-r--r--Source/WebKit2/UIProcess/WebsiteData/WebsiteDataRecord.cpp110
-rw-r--r--Source/WebKit2/UIProcess/WebsiteData/WebsiteDataRecord.h73
-rw-r--r--Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.cpp1207
-rw-r--r--Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.h131
-rw-r--r--Source/WebKit2/UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp39
5 files changed, 1560 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataRecord.cpp b/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataRecord.cpp
new file mode 100644
index 000000000..174a0b200
--- /dev/null
+++ b/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataRecord.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebsiteDataRecord.h"
+
+#include <WebCore/LocalizedStrings.h>
+#include <WebCore/PublicSuffix.h>
+#include <WebCore/SecurityOrigin.h>
+
+#if PLATFORM(COCOA)
+#import <WebCore/CFNetworkSPI.h>
+#endif
+
+static String displayNameForLocalFiles()
+{
+ return WEB_UI_STRING("Local documents on your computer", "'Website' name displayed when local documents have stored local data");
+}
+
+namespace WebKit {
+
+String WebsiteDataRecord::displayNameForCookieHostName(const String& hostName)
+{
+#if PLATFORM(COCOA)
+ if (hostName == String(kCFHTTPCookieLocalFileDomain))
+ return displayNameForLocalFiles();
+#else
+ if (hostName == "localhost")
+ return hostName;
+#endif
+
+#if ENABLE(PUBLIC_SUFFIX_LIST)
+ return WebCore::topPrivatelyControlledDomain(hostName.startsWith('.') ? hostName.substring(1) : hostName);
+#endif
+
+ return String();
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+String WebsiteDataRecord::displayNameForPluginDataHostName(const String& hostName)
+{
+#if ENABLE(PUBLIC_SUFFIX_LIST)
+ return WebCore::topPrivatelyControlledDomain(hostName);
+#endif
+
+ return String();
+}
+#endif
+
+String WebsiteDataRecord::displayNameForOrigin(const WebCore::SecurityOriginData& securityOrigin)
+{
+ const auto& protocol = securityOrigin.protocol;
+
+ if (protocol == "file")
+ return displayNameForLocalFiles();
+
+#if ENABLE(PUBLIC_SUFFIX_LIST)
+ if (protocol == "http" || protocol == "https")
+ return WebCore::topPrivatelyControlledDomain(securityOrigin.host);
+#endif
+
+ return String();
+}
+
+void WebsiteDataRecord::add(WebsiteDataType type, const WebCore::SecurityOriginData& origin)
+{
+ types |= type;
+
+ origins.add(origin);
+}
+
+void WebsiteDataRecord::addCookieHostName(const String& hostName)
+{
+ types |= WebsiteDataType::Cookies;
+
+ cookieHostNames.add(hostName);
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+void WebsiteDataRecord::addPluginDataHostName(const String& hostName)
+{
+ types |= WebsiteDataType::PlugInData;
+
+ pluginDataHostNames.add(hostName);
+}
+#endif
+
+}
diff --git a/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataRecord.h b/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataRecord.h
new file mode 100644
index 000000000..137fc1c31
--- /dev/null
+++ b/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataRecord.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "WebsiteDataType.h"
+#include <WebCore/SecurityOriginData.h>
+#include <WebCore/SecurityOriginHash.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/OptionSet.h>
+#include <wtf/Optional.h>
+#include <wtf/text/StringHash.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class SecurityOrigin;
+}
+
+namespace WebKit {
+
+struct WebsiteDataRecord {
+ static String displayNameForCookieHostName(const String& hostName);
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ static String displayNameForPluginDataHostName(const String& hostName);
+#endif
+ static String displayNameForOrigin(const WebCore::SecurityOriginData&);
+
+ void add(WebsiteDataType, const WebCore::SecurityOriginData&);
+ void addCookieHostName(const String& hostName);
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ void addPluginDataHostName(const String& hostName);
+#endif
+
+ String displayName;
+ OptionSet<WebsiteDataType> types;
+
+ struct Size {
+ uint64_t totalSize;
+ HashMap<unsigned, uint64_t> typeSizes;
+ };
+ std::optional<Size> size;
+
+ HashSet<WebCore::SecurityOriginData> origins;
+ HashSet<String> cookieHostNames;
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ HashSet<String> pluginDataHostNames;
+#endif
+};
+
+}
diff --git a/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.cpp b/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.cpp
new file mode 100644
index 000000000..8fec3e4e1
--- /dev/null
+++ b/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.cpp
@@ -0,0 +1,1207 @@
+/*
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebsiteDataStore.h"
+
+#include "APIProcessPoolConfiguration.h"
+#include "APIWebsiteDataRecord.h"
+#include "NetworkProcessMessages.h"
+#include "StorageManager.h"
+#include "WebProcessMessages.h"
+#include "WebProcessPool.h"
+#include "WebResourceLoadStatisticsStore.h"
+#include "WebResourceLoadStatisticsStoreMessages.h"
+#include "WebsiteData.h"
+#include <WebCore/ApplicationCacheStorage.h>
+#include <WebCore/DatabaseTracker.h>
+#include <WebCore/HTMLMediaElement.h>
+#include <WebCore/OriginLock.h>
+#include <WebCore/SecurityOrigin.h>
+#include <WebCore/SecurityOriginData.h>
+#include <wtf/RunLoop.h>
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+#include "PluginProcessManager.h"
+#endif
+
+namespace WebKit {
+
+static WebCore::SessionID generateNonPersistentSessionID()
+{
+ // FIXME: We count backwards here to not conflict with API::Session.
+ static uint64_t sessionID = std::numeric_limits<uint64_t>::max();
+
+ return WebCore::SessionID(--sessionID);
+}
+
+static uint64_t generateIdentifier()
+{
+ static uint64_t identifier;
+
+ return ++identifier;
+}
+
+Ref<WebsiteDataStore> WebsiteDataStore::createNonPersistent()
+{
+ return adoptRef(*new WebsiteDataStore(generateNonPersistentSessionID()));
+}
+
+Ref<WebsiteDataStore> WebsiteDataStore::create(Configuration configuration)
+{
+ return adoptRef(*new WebsiteDataStore(WTFMove(configuration)));
+}
+
+WebsiteDataStore::WebsiteDataStore(Configuration configuration)
+ : m_identifier(generateIdentifier())
+ , m_sessionID(WebCore::SessionID::defaultSessionID())
+ , m_configuration(WTFMove(configuration))
+ , m_storageManager(StorageManager::create(m_configuration.localStorageDirectory))
+ , m_resourceLoadStatistics(WebResourceLoadStatisticsStore::create(m_configuration.resourceLoadStatisticsDirectory))
+ , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
+{
+ platformInitialize();
+}
+
+WebsiteDataStore::WebsiteDataStore(WebCore::SessionID sessionID)
+ : m_identifier(generateIdentifier())
+ , m_sessionID(sessionID)
+ , m_configuration()
+ , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
+{
+ platformInitialize();
+}
+
+WebsiteDataStore::~WebsiteDataStore()
+{
+ platformDestroy();
+
+ if (m_sessionID.isEphemeral()) {
+ for (auto& processPool : WebProcessPool::allProcessPools())
+ processPool->sendToNetworkingProcess(Messages::NetworkProcess::DestroyPrivateBrowsingSession(m_sessionID));
+ }
+}
+
+void WebsiteDataStore::cloneSessionData(WebPageProxy& sourcePage, WebPageProxy& newPage)
+{
+ auto& sourceDataStore = sourcePage.websiteDataStore();
+ auto& newDataStore = newPage.websiteDataStore();
+
+ // FIXME: Handle this.
+ if (&sourceDataStore != &newDataStore)
+ return;
+
+ if (!sourceDataStore.m_storageManager)
+ return;
+
+ sourceDataStore.m_storageManager->cloneSessionStorageNamespace(sourcePage.pageID(), newPage.pageID());
+}
+
+enum class ProcessAccessType {
+ None,
+ OnlyIfLaunched,
+ Launch,
+};
+
+static ProcessAccessType computeNetworkProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
+{
+ ProcessAccessType processAccessType = ProcessAccessType::None;
+
+ if (dataTypes.contains(WebsiteDataType::Cookies)) {
+ if (isNonPersistentStore)
+ processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
+ else
+ processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
+ }
+
+ if (dataTypes.contains(WebsiteDataType::DiskCache) && !isNonPersistentStore)
+ processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
+
+ return processAccessType;
+}
+
+static ProcessAccessType computeWebProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
+{
+ UNUSED_PARAM(isNonPersistentStore);
+
+ ProcessAccessType processAccessType = ProcessAccessType::None;
+
+ if (dataTypes.contains(WebsiteDataType::MemoryCache))
+ return ProcessAccessType::OnlyIfLaunched;
+
+ return processAccessType;
+}
+
+void WebsiteDataStore::fetchData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, std::function<void (Vector<WebsiteDataRecord>)> completionHandler)
+{
+ struct CallbackAggregator final : ThreadSafeRefCounted<CallbackAggregator> {
+ explicit CallbackAggregator(OptionSet<WebsiteDataFetchOption> fetchOptions, std::function<void (Vector<WebsiteDataRecord>)> completionHandler)
+ : fetchOptions(fetchOptions)
+ , completionHandler(WTFMove(completionHandler))
+ {
+ }
+
+ ~CallbackAggregator()
+ {
+ ASSERT(!pendingCallbacks);
+ }
+
+ void addPendingCallback()
+ {
+ pendingCallbacks++;
+ }
+
+ void removePendingCallback(WebsiteData websiteData)
+ {
+ ASSERT(pendingCallbacks);
+ --pendingCallbacks;
+
+ for (auto& entry : websiteData.entries) {
+ auto displayName = WebsiteDataRecord::displayNameForOrigin(entry.origin);
+ if (!displayName)
+ continue;
+
+ auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
+ if (!record.displayName)
+ record.displayName = WTFMove(displayName);
+
+ record.add(entry.type, entry.origin);
+
+ if (fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes)) {
+ if (!record.size)
+ record.size = WebsiteDataRecord::Size { 0, { } };
+
+ record.size->totalSize += entry.size;
+ record.size->typeSizes.add(static_cast<unsigned>(entry.type), 0).iterator->value += entry.size;
+ }
+ }
+
+ for (auto& hostName : websiteData.hostNamesWithCookies) {
+ auto displayName = WebsiteDataRecord::displayNameForCookieHostName(hostName);
+ if (!displayName)
+ continue;
+
+ auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
+ if (!record.displayName)
+ record.displayName = WTFMove(displayName);
+
+ record.addCookieHostName(hostName);
+ }
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ for (auto& hostName : websiteData.hostNamesWithPluginData) {
+ auto displayName = WebsiteDataRecord::displayNameForPluginDataHostName(hostName);
+ if (!displayName)
+ continue;
+
+ auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
+ if (!record.displayName)
+ record.displayName = WTFMove(displayName);
+
+ record.addPluginDataHostName(hostName);
+ }
+#endif
+
+ callIfNeeded();
+ }
+
+ void callIfNeeded()
+ {
+ if (pendingCallbacks)
+ return;
+
+ RunLoop::main().dispatch([callbackAggregator = makeRef(*this)]() mutable {
+
+ WTF::Vector<WebsiteDataRecord> records;
+ records.reserveInitialCapacity(callbackAggregator->m_websiteDataRecords.size());
+
+ for (auto& record : callbackAggregator->m_websiteDataRecords.values())
+ records.uncheckedAppend(WTFMove(record));
+
+ callbackAggregator->completionHandler(WTFMove(records));
+ });
+ }
+
+ const OptionSet<WebsiteDataFetchOption> fetchOptions;
+
+ unsigned pendingCallbacks = 0;
+ std::function<void (Vector<WebsiteDataRecord>)> completionHandler;
+
+ HashMap<String, WebsiteDataRecord> m_websiteDataRecords;
+ };
+
+ RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(fetchOptions, WTFMove(completionHandler)));
+
+#if ENABLE(VIDEO)
+ if (dataTypes.contains(WebsiteDataType::DiskCache)) {
+ callbackAggregator->addPendingCallback();
+ m_queue->dispatch([fetchOptions, mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
+ // FIXME: Make HTMLMediaElement::originsInMediaCache return a collection of SecurityOriginDatas.
+ HashSet<RefPtr<WebCore::SecurityOrigin>> origins = WebCore::HTMLMediaElement::originsInMediaCache(mediaCacheDirectory);
+ WebsiteData websiteData;
+
+ for (auto& origin : origins) {
+ WebsiteData::Entry entry { WebCore::SecurityOriginData::fromSecurityOrigin(*origin), WebsiteDataType::DiskCache, 0 };
+ websiteData.entries.append(WTFMove(entry));
+ }
+
+ RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ });
+ }
+#endif
+
+ auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
+ if (networkProcessAccessType != ProcessAccessType::None) {
+ for (auto& processPool : processPools()) {
+ switch (networkProcessAccessType) {
+ case ProcessAccessType::OnlyIfLaunched:
+ if (!processPool->networkProcess())
+ continue;
+ break;
+
+ case ProcessAccessType::Launch:
+ processPool->ensureNetworkProcess();
+ break;
+
+ case ProcessAccessType::None:
+ ASSERT_NOT_REACHED();
+ }
+
+ callbackAggregator->addPendingCallback();
+ processPool->networkProcess()->fetchWebsiteData(m_sessionID, dataTypes, fetchOptions, [callbackAggregator, processPool](WebsiteData websiteData) {
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ }
+ }
+
+ auto webProcessAccessType = computeWebProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
+ if (webProcessAccessType != ProcessAccessType::None) {
+ for (auto& process : processes()) {
+ switch (webProcessAccessType) {
+ case ProcessAccessType::OnlyIfLaunched:
+ if (!process->canSendMessage())
+ continue;
+ break;
+
+ case ProcessAccessType::Launch:
+ // FIXME: Handle this.
+ ASSERT_NOT_REACHED();
+ break;
+
+ case ProcessAccessType::None:
+ ASSERT_NOT_REACHED();
+ }
+
+ callbackAggregator->addPendingCallback();
+ process->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator](WebsiteData websiteData) {
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ }
+ }
+
+ if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
+ callbackAggregator->addPendingCallback();
+
+ m_storageManager->getSessionStorageOrigins([callbackAggregator](HashSet<WebCore::SecurityOriginData>&& origins) {
+ WebsiteData websiteData;
+
+ while (!origins.isEmpty())
+ websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::SessionStorage, 0 });
+
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
+ callbackAggregator->addPendingCallback();
+
+ m_storageManager->getLocalStorageOrigins([callbackAggregator](HashSet<WebCore::SecurityOriginData>&& origins) {
+ WebsiteData websiteData;
+
+ while (!origins.isEmpty())
+ websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::LocalStorage, 0 });
+
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
+ callbackAggregator->addPendingCallback();
+
+ m_queue->dispatch([fetchOptions, applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
+ auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
+
+ WebsiteData websiteData;
+
+ HashSet<RefPtr<WebCore::SecurityOrigin>> origins;
+ // FIXME: getOriginsWithCache should return a collection of SecurityOriginDatas.
+ storage->getOriginsWithCache(origins);
+
+ for (auto& origin : origins) {
+ uint64_t size = fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes) ? storage->diskUsageForOrigin(*origin) : 0;
+ WebsiteData::Entry entry { WebCore::SecurityOriginData::fromSecurityOrigin(*origin), WebsiteDataType::OfflineWebApplicationCache, size };
+
+ websiteData.entries.append(WTFMove(entry));
+ }
+
+ RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
+ callbackAggregator->addPendingCallback();
+
+ m_queue->dispatch([webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy(), callbackAggregator] {
+ auto origins = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->origins();
+ RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
+ WebsiteData websiteData;
+ for (auto& origin : origins)
+ websiteData.entries.append(WebsiteData::Entry { WTFMove(origin), WebsiteDataType::WebSQLDatabases, 0 });
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ });
+ }
+
+#if ENABLE(DATABASE_PROCESS)
+ if (dataTypes.contains(WebsiteDataType::IndexedDBDatabases) && isPersistent()) {
+ for (auto& processPool : processPools()) {
+ processPool->ensureDatabaseProcess();
+
+ callbackAggregator->addPendingCallback();
+ processPool->databaseProcess()->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator, processPool](WebsiteData websiteData) {
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ }
+ }
+#endif
+
+ if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
+ callbackAggregator->addPendingCallback();
+
+ m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator] {
+ auto origins = mediaKeyOrigins(mediaKeysStorageDirectory);
+
+ RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
+ WebsiteData websiteData;
+ for (auto& origin : origins)
+ websiteData.entries.append(WebsiteData::Entry { origin, WebsiteDataType::MediaKeys, 0 });
+
+ callbackAggregator->removePendingCallback(WTFMove(websiteData));
+ });
+ });
+ }
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
+ class State {
+ public:
+ static void fetchData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
+ {
+ new State(WTFMove(callbackAggregator), WTFMove(plugins));
+ }
+
+ private:
+ State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
+ : m_callbackAggregator(WTFMove(callbackAggregator))
+ , m_plugins(WTFMove(plugins))
+ {
+ m_callbackAggregator->addPendingCallback();
+
+ fetchWebsiteDataForNextPlugin();
+ }
+
+ ~State()
+ {
+ ASSERT(m_plugins.isEmpty());
+ }
+
+ void fetchWebsiteDataForNextPlugin()
+ {
+ if (m_plugins.isEmpty()) {
+ WebsiteData websiteData;
+ websiteData.hostNamesWithPluginData = WTFMove(m_hostNames);
+
+ m_callbackAggregator->removePendingCallback(WTFMove(websiteData));
+
+ delete this;
+ return;
+ }
+
+ auto plugin = m_plugins.takeLast();
+ PluginProcessManager::singleton().fetchWebsiteData(plugin, [this](Vector<String> hostNames) {
+ for (auto& hostName : hostNames)
+ m_hostNames.add(WTFMove(hostName));
+ fetchWebsiteDataForNextPlugin();
+ });
+ }
+
+ Ref<CallbackAggregator> m_callbackAggregator;
+ Vector<PluginModuleInfo> m_plugins;
+ HashSet<String> m_hostNames;
+ };
+
+ State::fetchData(*callbackAggregator, plugins());
+ }
+#endif
+
+ callbackAggregator->callIfNeeded();
+}
+
+void WebsiteDataStore::fetchDataForTopPrivatelyOwnedDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<String>& topPrivatelyOwnedDomains, std::function<void(Vector<WebsiteDataRecord>)> completionHandler)
+{
+ fetchData(dataTypes, fetchOptions, [topPrivatelyOwnedDomains, completionHandler, this](auto existingDataRecords) {
+ Vector<WebsiteDataRecord> matchingDataRecords;
+ Vector<String> domainsWithDataRecords;
+ for (auto& dataRecord : existingDataRecords) {
+ bool dataRecordAdded;
+ for (auto& dataRecordOriginData : dataRecord.origins) {
+ dataRecordAdded = false;
+ String dataRecordHost = dataRecordOriginData.securityOrigin().get().host();
+ for (auto& topPrivatelyOwnedDomain : topPrivatelyOwnedDomains) {
+ if (dataRecordHost.endsWithIgnoringASCIICase(topPrivatelyOwnedDomain)) {
+ auto suffixStart = dataRecordHost.length() - topPrivatelyOwnedDomain.length();
+ if (!suffixStart || dataRecordHost[suffixStart - 1] == '.') {
+ matchingDataRecords.append(dataRecord);
+ domainsWithDataRecords.append(topPrivatelyOwnedDomain);
+ dataRecordAdded = true;
+ break;
+ }
+ }
+ }
+ if (dataRecordAdded)
+ break;
+ }
+ }
+ completionHandler(matchingDataRecords);
+ });
+}
+
+static ProcessAccessType computeNetworkProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
+{
+ ProcessAccessType processAccessType = ProcessAccessType::None;
+
+ if (dataTypes.contains(WebsiteDataType::Cookies)) {
+ if (isNonPersistentStore)
+ processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
+ else
+ processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
+ }
+
+ if (dataTypes.contains(WebsiteDataType::DiskCache) && !isNonPersistentStore)
+ processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
+
+ if (dataTypes.contains(WebsiteDataType::HSTSCache))
+ processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
+
+ return processAccessType;
+}
+
+static ProcessAccessType computeWebProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
+{
+ UNUSED_PARAM(isNonPersistentStore);
+
+ ProcessAccessType processAccessType = ProcessAccessType::None;
+
+ if (dataTypes.contains(WebsiteDataType::MemoryCache))
+ processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
+
+ return processAccessType;
+}
+
+void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, std::chrono::system_clock::time_point modifiedSince, std::function<void ()> completionHandler)
+{
+ struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
+ explicit CallbackAggregator (std::function<void ()> completionHandler)
+ : completionHandler(WTFMove(completionHandler))
+ {
+ }
+
+ void addPendingCallback()
+ {
+ pendingCallbacks++;
+ }
+
+ void removePendingCallback()
+ {
+ ASSERT(pendingCallbacks);
+ --pendingCallbacks;
+
+ callIfNeeded();
+ }
+
+ void callIfNeeded()
+ {
+ if (!pendingCallbacks)
+ RunLoop::main().dispatch(WTFMove(completionHandler));
+ }
+
+ unsigned pendingCallbacks = 0;
+ std::function<void()> completionHandler;
+ };
+
+ RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
+
+#if ENABLE(VIDEO)
+ if (dataTypes.contains(WebsiteDataType::DiskCache)) {
+ callbackAggregator->addPendingCallback();
+ m_queue->dispatch([modifiedSince, mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
+ WebCore::HTMLMediaElement::clearMediaCache(mediaCacheDirectory, modifiedSince);
+
+ WTF::RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+ }
+#endif
+
+ auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
+ if (networkProcessAccessType != ProcessAccessType::None) {
+ for (auto& processPool : processPools()) {
+ switch (networkProcessAccessType) {
+ case ProcessAccessType::OnlyIfLaunched:
+ if (!processPool->networkProcess())
+ continue;
+ break;
+
+ case ProcessAccessType::Launch:
+ processPool->ensureNetworkProcess();
+ break;
+
+ case ProcessAccessType::None:
+ ASSERT_NOT_REACHED();
+ }
+
+ callbackAggregator->addPendingCallback();
+ processPool->networkProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+ }
+
+ auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
+ if (webProcessAccessType != ProcessAccessType::None) {
+ for (auto& process : processes()) {
+ switch (webProcessAccessType) {
+ case ProcessAccessType::OnlyIfLaunched:
+ if (!process->canSendMessage())
+ continue;
+ break;
+
+ case ProcessAccessType::Launch:
+ // FIXME: Handle this.
+ ASSERT_NOT_REACHED();
+ break;
+
+ case ProcessAccessType::None:
+ ASSERT_NOT_REACHED();
+ }
+
+ callbackAggregator->addPendingCallback();
+ process->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+ }
+
+ if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
+ callbackAggregator->addPendingCallback();
+
+ m_storageManager->deleteSessionStorageOrigins([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
+ callbackAggregator->addPendingCallback();
+
+ m_storageManager->deleteLocalStorageOriginsModifiedSince(modifiedSince, [callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
+ callbackAggregator->addPendingCallback();
+
+ m_queue->dispatch([applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
+ auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
+
+ storage->deleteAllCaches();
+
+ WTF::RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
+ callbackAggregator->addPendingCallback();
+
+ m_queue->dispatch([webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy(), callbackAggregator, modifiedSince] {
+ WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->deleteDatabasesModifiedSince(modifiedSince);
+
+ RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+ }
+
+#if ENABLE(DATABASE_PROCESS)
+ if (dataTypes.contains(WebsiteDataType::IndexedDBDatabases) && isPersistent()) {
+ for (auto& processPool : processPools()) {
+ processPool->ensureDatabaseProcess();
+
+ callbackAggregator->addPendingCallback();
+ processPool->databaseProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+ }
+#endif
+
+ if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
+ callbackAggregator->addPendingCallback();
+
+ m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator, modifiedSince] {
+ removeMediaKeys(mediaKeysStorageDirectory, modifiedSince);
+
+ RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::SearchFieldRecentSearches) && isPersistent()) {
+ callbackAggregator->addPendingCallback();
+
+ m_queue->dispatch([modifiedSince, callbackAggregator] {
+ platformRemoveRecentSearches(modifiedSince);
+
+ RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+ }
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
+ class State {
+ public:
+ static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, std::chrono::system_clock::time_point modifiedSince)
+ {
+ new State(WTFMove(callbackAggregator), WTFMove(plugins), modifiedSince);
+ }
+
+ private:
+ State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, std::chrono::system_clock::time_point modifiedSince)
+ : m_callbackAggregator(WTFMove(callbackAggregator))
+ , m_plugins(WTFMove(plugins))
+ , m_modifiedSince(modifiedSince)
+ {
+ m_callbackAggregator->addPendingCallback();
+
+ deleteWebsiteDataForNextPlugin();
+ }
+
+ ~State()
+ {
+ ASSERT(m_plugins.isEmpty());
+ }
+
+ void deleteWebsiteDataForNextPlugin()
+ {
+ if (m_plugins.isEmpty()) {
+ m_callbackAggregator->removePendingCallback();
+
+ delete this;
+ return;
+ }
+
+ auto plugin = m_plugins.takeLast();
+ PluginProcessManager::singleton().deleteWebsiteData(plugin, m_modifiedSince, [this] {
+ deleteWebsiteDataForNextPlugin();
+ });
+ }
+
+ Ref<CallbackAggregator> m_callbackAggregator;
+ Vector<PluginModuleInfo> m_plugins;
+ std::chrono::system_clock::time_point m_modifiedSince;
+ };
+
+ State::deleteData(*callbackAggregator, plugins(), modifiedSince);
+ }
+#endif
+
+ // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
+ callbackAggregator->callIfNeeded();
+}
+
+void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, const Vector<WebsiteDataRecord>& dataRecords, std::function<void ()> completionHandler)
+{
+ Vector<WebCore::SecurityOriginData> origins;
+
+ for (const auto& dataRecord : dataRecords) {
+ for (auto& origin : dataRecord.origins)
+ origins.append(origin);
+ }
+
+ struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
+ explicit CallbackAggregator (std::function<void ()> completionHandler)
+ : completionHandler(WTFMove(completionHandler))
+ {
+ }
+
+ void addPendingCallback()
+ {
+ pendingCallbacks++;
+ }
+
+ void removePendingCallback()
+ {
+ ASSERT(pendingCallbacks);
+ --pendingCallbacks;
+
+ callIfNeeded();
+ }
+
+ void callIfNeeded()
+ {
+ if (!pendingCallbacks)
+ RunLoop::main().dispatch(WTFMove(completionHandler));
+ }
+
+ unsigned pendingCallbacks = 0;
+ std::function<void()> completionHandler;
+ };
+
+ RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
+
+ if (dataTypes.contains(WebsiteDataType::DiskCache)) {
+ HashSet<WebCore::SecurityOriginData> origins;
+ for (const auto& dataRecord : dataRecords) {
+ for (const auto& origin : dataRecord.origins)
+ origins.add(origin);
+ }
+
+#if ENABLE(VIDEO)
+ callbackAggregator->addPendingCallback();
+ m_queue->dispatch([origins = WTFMove(origins), mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
+
+ // FIXME: Move SecurityOrigin::toRawString to SecurityOriginData and
+ // make HTMLMediaElement::clearMediaCacheForOrigins take SecurityOriginData.
+ HashSet<RefPtr<WebCore::SecurityOrigin>> securityOrigins;
+ for (auto& origin : origins)
+ securityOrigins.add(origin.securityOrigin());
+ WebCore::HTMLMediaElement::clearMediaCacheForOrigins(mediaCacheDirectory, securityOrigins);
+
+ WTF::RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+#endif
+ }
+
+ auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
+ if (networkProcessAccessType != ProcessAccessType::None) {
+ for (auto& processPool : processPools()) {
+ switch (networkProcessAccessType) {
+ case ProcessAccessType::OnlyIfLaunched:
+ if (!processPool->networkProcess())
+ continue;
+ break;
+
+ case ProcessAccessType::Launch:
+ processPool->ensureNetworkProcess();
+ break;
+
+ case ProcessAccessType::None:
+ ASSERT_NOT_REACHED();
+ }
+
+ Vector<String> cookieHostNames;
+ for (const auto& dataRecord : dataRecords) {
+ for (auto& hostName : dataRecord.cookieHostNames)
+ cookieHostNames.append(hostName);
+ }
+
+ callbackAggregator->addPendingCallback();
+ processPool->networkProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, cookieHostNames, [callbackAggregator, processPool] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+ }
+
+ auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
+ if (webProcessAccessType != ProcessAccessType::None) {
+ for (auto& process : processes()) {
+ switch (webProcessAccessType) {
+ case ProcessAccessType::OnlyIfLaunched:
+ if (!process->canSendMessage())
+ continue;
+ break;
+
+ case ProcessAccessType::Launch:
+ // FIXME: Handle this.
+ ASSERT_NOT_REACHED();
+ break;
+
+ case ProcessAccessType::None:
+ ASSERT_NOT_REACHED();
+ }
+
+ callbackAggregator->addPendingCallback();
+
+ process->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+ }
+
+ if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
+ callbackAggregator->addPendingCallback();
+
+ m_storageManager->deleteSessionStorageEntriesForOrigins(origins, [callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
+ callbackAggregator->addPendingCallback();
+
+ m_storageManager->deleteLocalStorageEntriesForOrigins(origins, [callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
+ HashSet<WebCore::SecurityOriginData> origins;
+ for (const auto& dataRecord : dataRecords) {
+ for (const auto& origin : dataRecord.origins)
+ origins.add(origin);
+ }
+
+ callbackAggregator->addPendingCallback();
+ m_queue->dispatch([origins = WTFMove(origins), applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
+ auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
+
+ for (const auto& origin : origins)
+ storage->deleteCacheForOrigin(origin.securityOrigin());
+
+ WTF::RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+ }
+
+ if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
+ HashSet<WebCore::SecurityOriginData> origins;
+ for (const auto& dataRecord : dataRecords) {
+ for (const auto& origin : dataRecord.origins)
+ origins.add(origin);
+ }
+
+ callbackAggregator->addPendingCallback();
+ m_queue->dispatch([origins = WTFMove(origins), callbackAggregator, webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy()] {
+ auto databaseTracker = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory);
+ for (auto& origin : origins)
+ databaseTracker->deleteOrigin(origin);
+ RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+ }
+
+#if ENABLE(DATABASE_PROCESS)
+ if (dataTypes.contains(WebsiteDataType::IndexedDBDatabases) && isPersistent()) {
+ for (auto& processPool : processPools()) {
+ processPool->ensureDatabaseProcess();
+
+ callbackAggregator->addPendingCallback();
+ processPool->databaseProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator, processPool] {
+ callbackAggregator->removePendingCallback();
+ });
+ }
+ }
+#endif
+
+ if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
+ HashSet<WebCore::SecurityOriginData> origins;
+ for (const auto& dataRecord : dataRecords) {
+ for (const auto& origin : dataRecord.origins)
+ origins.add(origin);
+ }
+
+ callbackAggregator->addPendingCallback();
+ m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator, origins = WTFMove(origins)] {
+
+ removeMediaKeys(mediaKeysStorageDirectory, origins);
+
+ RunLoop::main().dispatch([callbackAggregator] {
+ callbackAggregator->removePendingCallback();
+ });
+ });
+ }
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
+ Vector<String> hostNames;
+ for (const auto& dataRecord : dataRecords) {
+ for (const auto& hostName : dataRecord.pluginDataHostNames)
+ hostNames.append(hostName);
+ }
+
+
+ class State {
+ public:
+ static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
+ {
+ new State(WTFMove(callbackAggregator), WTFMove(plugins), WTFMove(hostNames));
+ }
+
+ private:
+ State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
+ : m_callbackAggregator(WTFMove(callbackAggregator))
+ , m_plugins(WTFMove(plugins))
+ , m_hostNames(WTFMove(hostNames))
+ {
+ m_callbackAggregator->addPendingCallback();
+
+ deleteWebsiteDataForNextPlugin();
+ }
+
+ ~State()
+ {
+ ASSERT(m_plugins.isEmpty());
+ }
+
+ void deleteWebsiteDataForNextPlugin()
+ {
+ if (m_plugins.isEmpty()) {
+ m_callbackAggregator->removePendingCallback();
+
+ delete this;
+ return;
+ }
+
+ auto plugin = m_plugins.takeLast();
+ PluginProcessManager::singleton().deleteWebsiteDataForHostNames(plugin, m_hostNames, [this] {
+ deleteWebsiteDataForNextPlugin();
+ });
+ }
+
+ Ref<CallbackAggregator> m_callbackAggregator;
+ Vector<PluginModuleInfo> m_plugins;
+ Vector<String> m_hostNames;
+ };
+
+ State::deleteData(*callbackAggregator, plugins(), WTFMove(hostNames));
+ }
+#endif
+
+ // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
+ callbackAggregator->callIfNeeded();
+}
+
+void WebsiteDataStore::removeDataForTopPrivatelyOwnedDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<String>& topPrivatelyOwnedDomains, std::function<void()> completionHandler)
+{
+ fetchDataForTopPrivatelyOwnedDomains(dataTypes, fetchOptions, topPrivatelyOwnedDomains, [dataTypes, completionHandler, this](auto websiteDataRecords) {
+ this->removeData(dataTypes, websiteDataRecords, [completionHandler]() {
+ completionHandler();
+ });
+ });
+}
+
+void WebsiteDataStore::webPageWasAdded(WebPageProxy& webPageProxy)
+{
+ if (m_storageManager)
+ m_storageManager->createSessionStorageNamespace(webPageProxy.pageID(), std::numeric_limits<unsigned>::max());
+}
+
+void WebsiteDataStore::webPageWasRemoved(WebPageProxy& webPageProxy)
+{
+ if (m_storageManager)
+ m_storageManager->destroySessionStorageNamespace(webPageProxy.pageID());
+}
+
+void WebsiteDataStore::webProcessWillOpenConnection(WebProcessProxy& webProcessProxy, IPC::Connection& connection)
+{
+ if (m_storageManager)
+ m_storageManager->processWillOpenConnection(webProcessProxy, connection);
+
+ if (m_resourceLoadStatistics)
+ m_resourceLoadStatistics->processWillOpenConnection(webProcessProxy, connection);
+}
+
+void WebsiteDataStore::webPageWillOpenConnection(WebPageProxy& webPageProxy, IPC::Connection& connection)
+{
+ if (m_storageManager)
+ m_storageManager->setAllowedSessionStorageNamespaceConnection(webPageProxy.pageID(), &connection);
+}
+
+void WebsiteDataStore::webPageDidCloseConnection(WebPageProxy& webPageProxy, IPC::Connection&)
+{
+ if (m_storageManager)
+ m_storageManager->setAllowedSessionStorageNamespaceConnection(webPageProxy.pageID(), nullptr);
+}
+
+void WebsiteDataStore::webProcessDidCloseConnection(WebProcessProxy& webProcessProxy, IPC::Connection& connection)
+{
+ if (m_resourceLoadStatistics)
+ m_resourceLoadStatistics->processDidCloseConnection(webProcessProxy, connection);
+
+ if (m_storageManager)
+ m_storageManager->processDidCloseConnection(webProcessProxy, connection);
+}
+
+HashSet<RefPtr<WebProcessPool>> WebsiteDataStore::processPools() const
+{
+ HashSet<RefPtr<WebProcessPool>> processPools;
+ for (auto& process : processes())
+ processPools.add(&process->processPool());
+
+ if (processPools.isEmpty()) {
+ // Check if we're one of the legacy data stores.
+ for (auto& processPool : WebProcessPool::allProcessPools()) {
+ if (auto dataStore = processPool->websiteDataStore()) {
+ if (&dataStore->websiteDataStore() == this) {
+ processPools.add(processPool);
+ break;
+ }
+ }
+ }
+ }
+
+ if (processPools.isEmpty()) {
+ auto processPool = WebProcessPool::create(API::ProcessPoolConfiguration::createWithWebsiteDataStoreConfiguration(m_configuration));
+ processPools.add(processPool.ptr());
+ }
+
+ return processPools;
+}
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+Vector<PluginModuleInfo> WebsiteDataStore::plugins() const
+{
+ Vector<PluginModuleInfo> plugins;
+
+ for (auto& processPool : processPools()) {
+ for (auto& plugin : processPool->pluginInfoStore().plugins())
+ plugins.append(plugin);
+ }
+
+ return plugins;
+}
+#endif
+
+static String computeMediaKeyFile(const String& mediaKeyDirectory)
+{
+ return WebCore::pathByAppendingComponent(mediaKeyDirectory, "SecureStop.plist");
+}
+
+Vector<WebCore::SecurityOriginData> WebsiteDataStore::mediaKeyOrigins(const String& mediaKeysStorageDirectory)
+{
+ ASSERT(!mediaKeysStorageDirectory.isEmpty());
+
+ Vector<WebCore::SecurityOriginData> origins;
+
+ for (const auto& originPath : WebCore::listDirectory(mediaKeysStorageDirectory, "*")) {
+ auto mediaKeyFile = computeMediaKeyFile(originPath);
+ if (!WebCore::fileExists(mediaKeyFile))
+ continue;
+
+ auto mediaKeyIdentifier = WebCore::pathGetFileName(originPath);
+
+ if (auto securityOrigin = WebCore::SecurityOriginData::fromDatabaseIdentifier(mediaKeyIdentifier))
+ origins.append(*securityOrigin);
+ }
+
+ return origins;
+}
+
+void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, std::chrono::system_clock::time_point modifiedSince)
+{
+ ASSERT(!mediaKeysStorageDirectory.isEmpty());
+
+ for (const auto& mediaKeyDirectory : WebCore::listDirectory(mediaKeysStorageDirectory, "*")) {
+ auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
+
+ time_t modificationTime;
+ if (!WebCore::getFileModificationTime(mediaKeyFile, modificationTime))
+ continue;
+
+ if (std::chrono::system_clock::from_time_t(modificationTime) < modifiedSince)
+ continue;
+
+ WebCore::deleteFile(mediaKeyFile);
+ WebCore::deleteEmptyDirectory(mediaKeyDirectory);
+ }
+}
+
+void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, const HashSet<WebCore::SecurityOriginData>& origins)
+{
+ ASSERT(!mediaKeysStorageDirectory.isEmpty());
+
+ for (const auto& origin : origins) {
+ auto mediaKeyDirectory = WebCore::pathByAppendingComponent(mediaKeysStorageDirectory, origin.databaseIdentifier());
+ auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
+
+ WebCore::deleteFile(mediaKeyFile);
+ WebCore::deleteEmptyDirectory(mediaKeyDirectory);
+ }
+}
+
+bool WebsiteDataStore::resourceLoadStatisticsEnabled() const
+{
+ return m_resourceLoadStatistics ? m_resourceLoadStatistics->resourceLoadStatisticsEnabled() : false;
+}
+
+void WebsiteDataStore::setResourceLoadStatisticsEnabled(bool enabled)
+{
+ if (!m_resourceLoadStatistics)
+ return;
+
+ if (enabled == resourceLoadStatisticsEnabled())
+ return;
+
+ m_resourceLoadStatistics->setResourceLoadStatisticsEnabled(enabled);
+
+ for (auto& processPool : WebProcessPool::allProcessPools()) {
+ processPool->setResourceLoadStatisticsEnabled(enabled);
+ processPool->sendToAllProcesses(Messages::WebProcess::SetResourceLoadStatisticsEnabled(enabled));
+ }
+}
+
+void WebsiteDataStore::registerSharedResourceLoadObserver()
+{
+ if (!m_resourceLoadStatistics)
+ return;
+
+ m_resourceLoadStatistics->registerSharedResourceLoadObserver();
+}
+
+}
diff --git a/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.h b/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.h
new file mode 100644
index 000000000..cba299d0b
--- /dev/null
+++ b/Source/WebKit2/UIProcess/WebsiteData/WebsiteDataStore.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "WebProcessLifetimeObserver.h"
+#include <WebCore/SecurityOriginData.h>
+#include <WebCore/SecurityOriginHash.h>
+#include <WebCore/SessionID.h>
+#include <functional>
+#include <wtf/HashSet.h>
+#include <wtf/OptionSet.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebCore {
+class SecurityOrigin;
+}
+
+namespace WebKit {
+
+class StorageManager;
+class WebPageProxy;
+class WebProcessPool;
+class WebResourceLoadStatisticsStore;
+enum class WebsiteDataFetchOption;
+enum class WebsiteDataType;
+struct WebsiteDataRecord;
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+struct PluginModuleInfo;
+#endif
+
+class WebsiteDataStore : public RefCounted<WebsiteDataStore>, public WebProcessLifetimeObserver {
+public:
+ struct Configuration {
+ String networkCacheDirectory;
+ String applicationCacheDirectory;
+ String applicationCacheFlatFileSubdirectoryName;
+
+ String mediaCacheDirectory;
+ String webSQLDatabaseDirectory;
+ String localStorageDirectory;
+ String mediaKeysStorageDirectory;
+ String resourceLoadStatisticsDirectory;
+ };
+ static Ref<WebsiteDataStore> createNonPersistent();
+ static Ref<WebsiteDataStore> create(Configuration);
+ virtual ~WebsiteDataStore();
+
+ uint64_t identifier() const { return m_identifier; }
+
+ bool isPersistent() const { return !m_sessionID.isEphemeral(); }
+ WebCore::SessionID sessionID() const { return m_sessionID; }
+
+ bool resourceLoadStatisticsEnabled() const;
+ void setResourceLoadStatisticsEnabled(bool);
+ void registerSharedResourceLoadObserver();
+
+ static void cloneSessionData(WebPageProxy& sourcePage, WebPageProxy& newPage);
+
+ void fetchData(OptionSet<WebsiteDataType>, OptionSet<WebsiteDataFetchOption>, std::function<void (Vector<WebsiteDataRecord>)> completionHandler);
+ void fetchDataForTopPrivatelyOwnedDomains(OptionSet<WebsiteDataType>, OptionSet<WebsiteDataFetchOption>, const Vector<String>& topPrivatelyOwnedDomains, std::function<void(Vector<WebsiteDataRecord>)> completionHandler);
+ void removeData(OptionSet<WebsiteDataType>, std::chrono::system_clock::time_point modifiedSince, std::function<void ()> completionHandler);
+ void removeData(OptionSet<WebsiteDataType>, const Vector<WebsiteDataRecord>&, std::function<void ()> completionHandler);
+ void removeDataForTopPrivatelyOwnedDomains(OptionSet<WebsiteDataType>, OptionSet<WebsiteDataFetchOption>, const Vector<String>& topPrivatelyOwnedDomains, std::function<void()> completionHandler);
+
+ StorageManager* storageManager() { return m_storageManager.get(); }
+
+private:
+ explicit WebsiteDataStore(WebCore::SessionID);
+ explicit WebsiteDataStore(Configuration);
+
+ // WebProcessLifetimeObserver.
+ void webPageWasAdded(WebPageProxy&) override;
+ void webPageWasRemoved(WebPageProxy&) override;
+ void webProcessWillOpenConnection(WebProcessProxy&, IPC::Connection&) override;
+ void webPageWillOpenConnection(WebPageProxy&, IPC::Connection&) override;
+ void webPageDidCloseConnection(WebPageProxy&, IPC::Connection&) override;
+ void webProcessDidCloseConnection(WebProcessProxy&, IPC::Connection&) override;
+
+ void platformInitialize();
+ void platformDestroy();
+ static void platformRemoveRecentSearches(std::chrono::system_clock::time_point);
+
+ HashSet<RefPtr<WebProcessPool>> processPools() const;
+
+#if ENABLE(NETSCAPE_PLUGIN_API)
+ Vector<PluginModuleInfo> plugins() const;
+#endif
+
+ static Vector<WebCore::SecurityOriginData> mediaKeyOrigins(const String& mediaKeysStorageDirectory);
+ static void removeMediaKeys(const String& mediaKeysStorageDirectory, std::chrono::system_clock::time_point modifiedSince);
+ static void removeMediaKeys(const String& mediaKeysStorageDirectory, const HashSet<WebCore::SecurityOriginData>&);
+
+ const uint64_t m_identifier;
+ const WebCore::SessionID m_sessionID;
+
+ const Configuration m_configuration;
+
+ const RefPtr<StorageManager> m_storageManager;
+ const RefPtr<WebResourceLoadStatisticsStore> m_resourceLoadStatistics;
+
+ Ref<WorkQueue> m_queue;
+};
+
+}
diff --git a/Source/WebKit2/UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp b/Source/WebKit2/UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp
new file mode 100644
index 000000000..76956fd75
--- /dev/null
+++ b/Source/WebKit2/UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 University of Szeged. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebsiteDataStore.h"
+
+namespace WebKit {
+
+void WebsiteDataStore::platformInitialize()
+{
+}
+
+void WebsiteDataStore::platformDestroy()
+{
+}
+
+} // namespace WebKit