2 * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "WebsiteDataStore.h"
29 #include "APIProcessPoolConfiguration.h"
30 #include "APIWebsiteDataRecord.h"
31 #include "NetworkProcessMessages.h"
32 #include "StorageManager.h"
33 #include "StorageProcessCreationParameters.h"
34 #include "WebCookieManagerProxy.h"
35 #include "WebProcessMessages.h"
36 #include "WebProcessPool.h"
37 #include "WebResourceLoadStatisticsStore.h"
38 #include "WebResourceLoadStatisticsStoreMessages.h"
39 #include "WebsiteData.h"
40 #include "WebsiteDataStoreParameters.h"
41 #include <WebCore/ApplicationCacheStorage.h>
42 #include <WebCore/DatabaseTracker.h>
43 #include <WebCore/FileSystem.h>
44 #include <WebCore/HTMLMediaElement.h>
45 #include <WebCore/OriginLock.h>
46 #include <WebCore/SecurityOrigin.h>
47 #include <WebCore/SecurityOriginData.h>
48 #include <wtf/CompletionHandler.h>
49 #include <wtf/CrossThreadCopier.h>
50 #include <wtf/RunLoop.h>
52 #if ENABLE(NETSCAPE_PLUGIN_API)
53 #include "PluginProcessManager.h"
58 static HashMap<PAL::SessionID, WebsiteDataStore*>& nonDefaultDataStores()
60 RELEASE_ASSERT(isMainThread());
61 static NeverDestroyed<HashMap<PAL::SessionID, WebsiteDataStore*>> map;
65 Ref<WebsiteDataStore> WebsiteDataStore::createNonPersistent()
67 return adoptRef(*new WebsiteDataStore(PAL::SessionID::generateEphemeralSessionID()));
70 Ref<WebsiteDataStore> WebsiteDataStore::create(Configuration configuration, PAL::SessionID sessionID)
72 return adoptRef(*new WebsiteDataStore(WTFMove(configuration), sessionID));
75 WebsiteDataStore::WebsiteDataStore(Configuration configuration, PAL::SessionID sessionID)
76 : m_sessionID(sessionID)
77 , m_configuration(WTFMove(configuration))
78 , m_storageManager(StorageManager::create(m_configuration.localStorageDirectory))
79 , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
81 maybeRegisterWithSessionIDMap();
85 WebsiteDataStore::WebsiteDataStore(PAL::SessionID sessionID)
86 : m_sessionID(sessionID)
88 , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
90 maybeRegisterWithSessionIDMap();
94 WebsiteDataStore::~WebsiteDataStore()
98 if (m_sessionID.isValid() && m_sessionID != PAL::SessionID::defaultSessionID()) {
99 ASSERT(nonDefaultDataStores().get(m_sessionID) == this);
100 nonDefaultDataStores().remove(m_sessionID);
101 for (auto& processPool : WebProcessPool::allProcessPools())
102 processPool->sendToNetworkingProcess(Messages::NetworkProcess::DestroySession(m_sessionID));
106 void WebsiteDataStore::maybeRegisterWithSessionIDMap()
108 if (m_sessionID.isValid() && m_sessionID != PAL::SessionID::defaultSessionID()) {
109 auto result = nonDefaultDataStores().add(m_sessionID, this);
110 ASSERT_UNUSED(result, result.isNewEntry);
114 WebsiteDataStore* WebsiteDataStore::existingNonDefaultDataStoreForSessionID(PAL::SessionID sessionID)
116 return sessionID.isValid() && sessionID != PAL::SessionID::defaultSessionID() ? nonDefaultDataStores().get(sessionID) : nullptr;
119 WebProcessPool* WebsiteDataStore::processPoolForCookieStorageOperations()
121 auto pools = processPools(1, false);
122 return pools.isEmpty() ? nullptr : pools.begin()->get();
125 void WebsiteDataStore::resolveDirectoriesIfNecessary()
127 if (m_hasResolvedDirectories)
129 m_hasResolvedDirectories = true;
131 // Resolve directory paths.
132 if (!m_configuration.applicationCacheDirectory.isEmpty())
133 m_resolvedConfiguration.applicationCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.applicationCacheDirectory);
134 if (!m_configuration.mediaCacheDirectory.isEmpty())
135 m_resolvedConfiguration.mediaCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.mediaCacheDirectory);
136 if (!m_configuration.mediaKeysStorageDirectory.isEmpty())
137 m_resolvedConfiguration.mediaKeysStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.mediaKeysStorageDirectory);
138 if (!m_configuration.webSQLDatabaseDirectory.isEmpty())
139 m_resolvedConfiguration.webSQLDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.webSQLDatabaseDirectory);
140 if (!m_configuration.indexedDBDatabaseDirectory.isEmpty())
141 m_resolvedConfiguration.indexedDBDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.indexedDBDatabaseDirectory);
142 if (!m_configuration.serviceWorkerRegistrationDirectory.isEmpty())
143 m_resolvedConfiguration.serviceWorkerRegistrationDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.serviceWorkerRegistrationDirectory);
144 if (!m_configuration.javaScriptConfigurationDirectory.isEmpty())
145 m_resolvedConfiguration.javaScriptConfigurationDirectory = resolvePathForSandboxExtension(m_configuration.javaScriptConfigurationDirectory);
146 if (!m_configuration.cacheStorageDirectory.isEmpty() && m_resolvedConfiguration.cacheStorageDirectory.isEmpty())
147 m_resolvedConfiguration.cacheStorageDirectory = resolvePathForSandboxExtension(m_configuration.cacheStorageDirectory);
149 // Resolve directories for file paths.
150 if (!m_configuration.cookieStorageFile.isEmpty()) {
151 m_resolvedConfiguration.cookieStorageFile = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebCore::FileSystem::directoryName(m_configuration.cookieStorageFile));
152 m_resolvedConfiguration.cookieStorageFile = WebCore::FileSystem::pathByAppendingComponent(m_resolvedConfiguration.cookieStorageFile, WebCore::FileSystem::pathGetFileName(m_configuration.cookieStorageFile));
156 void WebsiteDataStore::cloneSessionData(WebPageProxy& sourcePage, WebPageProxy& newPage)
158 auto& sourceDataStore = sourcePage.websiteDataStore();
159 auto& newDataStore = newPage.websiteDataStore();
161 // FIXME: Handle this.
162 if (&sourceDataStore != &newDataStore)
165 if (!sourceDataStore.m_storageManager)
168 sourceDataStore.m_storageManager->cloneSessionStorageNamespace(sourcePage.pageID(), newPage.pageID());
171 enum class ProcessAccessType {
177 static ProcessAccessType computeNetworkProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
179 ProcessAccessType processAccessType = ProcessAccessType::None;
181 if (dataTypes.contains(WebsiteDataType::Cookies)) {
182 if (isNonPersistentStore)
183 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
185 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
188 if (dataTypes.contains(WebsiteDataType::DiskCache) && !isNonPersistentStore)
189 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
191 if (dataTypes.contains(WebsiteDataType::DOMCache))
192 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
194 return processAccessType;
197 static ProcessAccessType computeWebProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
199 UNUSED_PARAM(isNonPersistentStore);
201 ProcessAccessType processAccessType = ProcessAccessType::None;
203 if (dataTypes.contains(WebsiteDataType::MemoryCache))
204 return ProcessAccessType::OnlyIfLaunched;
206 return processAccessType;
209 void WebsiteDataStore::fetchData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void(Vector<WebsiteDataRecord>)>&& completionHandler)
211 fetchDataAndApply(dataTypes, fetchOptions, nullptr, WTFMove(completionHandler));
214 void WebsiteDataStore::fetchDataAndApply(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply)
216 struct CallbackAggregator final : ThreadSafeRefCounted<CallbackAggregator> {
217 explicit CallbackAggregator(OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply)
218 : fetchOptions(fetchOptions)
219 , queue(WTFMove(queue))
220 , apply(WTFMove(apply))
224 ~CallbackAggregator()
226 ASSERT(!pendingCallbacks);
229 void addPendingCallback()
234 void removePendingCallback(WebsiteData websiteData)
236 ASSERT(pendingCallbacks);
239 for (auto& entry : websiteData.entries) {
240 auto displayName = WebsiteDataRecord::displayNameForOrigin(entry.origin);
244 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
245 if (!record.displayName)
246 record.displayName = WTFMove(displayName);
248 record.add(entry.type, entry.origin);
250 if (fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes)) {
252 record.size = WebsiteDataRecord::Size { 0, { } };
254 record.size->totalSize += entry.size;
255 record.size->typeSizes.add(static_cast<unsigned>(entry.type), 0).iterator->value += entry.size;
259 for (auto& hostName : websiteData.hostNamesWithCookies) {
260 auto displayName = WebsiteDataRecord::displayNameForCookieHostName(hostName);
264 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
265 if (!record.displayName)
266 record.displayName = WTFMove(displayName);
268 record.addCookieHostName(hostName);
271 #if ENABLE(NETSCAPE_PLUGIN_API)
272 for (auto& hostName : websiteData.hostNamesWithPluginData) {
273 auto displayName = WebsiteDataRecord::displayNameForPluginDataHostName(hostName);
277 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
278 if (!record.displayName)
279 record.displayName = WTFMove(displayName);
281 record.addPluginDataHostName(hostName);
285 for (auto& origin : websiteData.originsWithCredentials) {
286 auto& record = m_websiteDataRecords.add(origin, WebsiteDataRecord { }).iterator->value;
288 record.addOriginWithCredential(origin);
296 if (pendingCallbacks)
299 Vector<WebsiteDataRecord> records;
300 records.reserveInitialCapacity(m_websiteDataRecords.size());
301 for (auto& record : m_websiteDataRecords.values())
302 records.uncheckedAppend(WTFMove(record));
304 auto processRecords = [apply = WTFMove(apply), records = WTFMove(records)] () mutable {
305 apply(WTFMove(records));
309 queue->dispatch(WTFMove(processRecords));
311 RunLoop::main().dispatch(WTFMove(processRecords));
314 const OptionSet<WebsiteDataFetchOption> fetchOptions;
316 unsigned pendingCallbacks = 0;
317 RefPtr<WorkQueue> queue;
318 Function<void(Vector<WebsiteDataRecord>)> apply;
320 HashMap<String, WebsiteDataRecord> m_websiteDataRecords;
323 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(fetchOptions, WTFMove(queue), WTFMove(apply)));
326 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
327 callbackAggregator->addPendingCallback();
328 m_queue->dispatch([mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
329 // FIXME: Make HTMLMediaElement::originsInMediaCache return a collection of SecurityOriginDatas.
330 HashSet<RefPtr<WebCore::SecurityOrigin>> origins = WebCore::HTMLMediaElement::originsInMediaCache(mediaCacheDirectory);
331 WebsiteData websiteData;
333 for (auto& origin : origins) {
334 WebsiteData::Entry entry { WebCore::SecurityOriginData::fromSecurityOrigin(*origin), WebsiteDataType::DiskCache, 0 };
335 websiteData.entries.append(WTFMove(entry));
338 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
339 callbackAggregator->removePendingCallback(WTFMove(websiteData));
345 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
346 if (networkProcessAccessType != ProcessAccessType::None) {
347 for (auto& processPool : processPools()) {
348 switch (networkProcessAccessType) {
349 case ProcessAccessType::OnlyIfLaunched:
350 if (!processPool->networkProcess())
354 case ProcessAccessType::Launch:
355 processPool->ensureNetworkProcess(this);
358 case ProcessAccessType::None:
359 ASSERT_NOT_REACHED();
362 callbackAggregator->addPendingCallback();
363 processPool->networkProcess()->fetchWebsiteData(m_sessionID, dataTypes, fetchOptions, [callbackAggregator, processPool](WebsiteData websiteData) {
364 callbackAggregator->removePendingCallback(WTFMove(websiteData));
369 auto webProcessAccessType = computeWebProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
370 if (webProcessAccessType != ProcessAccessType::None) {
371 for (auto& process : processes()) {
372 switch (webProcessAccessType) {
373 case ProcessAccessType::OnlyIfLaunched:
374 if (!process->canSendMessage())
378 case ProcessAccessType::Launch:
379 // FIXME: Handle this.
380 ASSERT_NOT_REACHED();
383 case ProcessAccessType::None:
384 ASSERT_NOT_REACHED();
387 callbackAggregator->addPendingCallback();
388 process->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator](WebsiteData websiteData) {
389 callbackAggregator->removePendingCallback(WTFMove(websiteData));
394 if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
395 callbackAggregator->addPendingCallback();
397 m_storageManager->getSessionStorageOrigins([callbackAggregator](HashSet<WebCore::SecurityOriginData>&& origins) {
398 WebsiteData websiteData;
400 while (!origins.isEmpty())
401 websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::SessionStorage, 0 });
403 callbackAggregator->removePendingCallback(WTFMove(websiteData));
407 if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
408 callbackAggregator->addPendingCallback();
410 m_storageManager->getLocalStorageOrigins([callbackAggregator](HashSet<WebCore::SecurityOriginData>&& origins) {
411 WebsiteData websiteData;
413 while (!origins.isEmpty())
414 websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::LocalStorage, 0 });
416 callbackAggregator->removePendingCallback(WTFMove(websiteData));
420 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
421 callbackAggregator->addPendingCallback();
423 m_queue->dispatch([fetchOptions, applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
424 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
426 WebsiteData websiteData;
428 HashSet<RefPtr<WebCore::SecurityOrigin>> origins;
429 // FIXME: getOriginsWithCache should return a collection of SecurityOriginDatas.
430 storage->getOriginsWithCache(origins);
432 for (auto& origin : origins) {
433 uint64_t size = fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes) ? storage->diskUsageForOrigin(*origin) : 0;
434 WebsiteData::Entry entry { WebCore::SecurityOriginData::fromSecurityOrigin(*origin), WebsiteDataType::OfflineWebApplicationCache, size };
436 websiteData.entries.append(WTFMove(entry));
439 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
440 callbackAggregator->removePendingCallback(WTFMove(websiteData));
445 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
446 callbackAggregator->addPendingCallback();
448 m_queue->dispatch([webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy(), callbackAggregator] {
449 auto origins = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->origins();
450 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
451 WebsiteData websiteData;
452 for (auto& origin : origins)
453 websiteData.entries.append(WebsiteData::Entry { WTFMove(origin), WebsiteDataType::WebSQLDatabases, 0 });
454 callbackAggregator->removePendingCallback(WTFMove(websiteData));
459 if ((dataTypes.contains(WebsiteDataType::IndexedDBDatabases)
460 #if ENABLE(SERVICE_WORKER)
461 || dataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)
463 ) && isPersistent()) {
464 for (auto& processPool : processPools()) {
465 processPool->ensureStorageProcessAndWebsiteDataStore(this);
467 callbackAggregator->addPendingCallback();
468 processPool->storageProcess()->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator, processPool](WebsiteData websiteData) {
469 callbackAggregator->removePendingCallback(WTFMove(websiteData));
474 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
475 callbackAggregator->addPendingCallback();
477 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator] {
478 auto origins = mediaKeyOrigins(mediaKeysStorageDirectory);
480 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
481 WebsiteData websiteData;
482 for (auto& origin : origins)
483 websiteData.entries.append(WebsiteData::Entry { origin, WebsiteDataType::MediaKeys, 0 });
485 callbackAggregator->removePendingCallback(WTFMove(websiteData));
490 #if ENABLE(NETSCAPE_PLUGIN_API)
491 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
494 static void fetchData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
496 new State(WTFMove(callbackAggregator), WTFMove(plugins));
500 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
501 : m_callbackAggregator(WTFMove(callbackAggregator))
502 , m_plugins(WTFMove(plugins))
504 m_callbackAggregator->addPendingCallback();
506 fetchWebsiteDataForNextPlugin();
511 ASSERT(m_plugins.isEmpty());
514 void fetchWebsiteDataForNextPlugin()
516 if (m_plugins.isEmpty()) {
517 WebsiteData websiteData;
518 websiteData.hostNamesWithPluginData = WTFMove(m_hostNames);
520 m_callbackAggregator->removePendingCallback(WTFMove(websiteData));
526 auto plugin = m_plugins.takeLast();
527 PluginProcessManager::singleton().fetchWebsiteData(plugin, m_callbackAggregator->fetchOptions, [this](Vector<String> hostNames) {
528 for (auto& hostName : hostNames)
529 m_hostNames.add(WTFMove(hostName));
530 fetchWebsiteDataForNextPlugin();
534 Ref<CallbackAggregator> m_callbackAggregator;
535 Vector<PluginModuleInfo> m_plugins;
536 HashSet<String> m_hostNames;
539 State::fetchData(*callbackAggregator, plugins());
543 callbackAggregator->callIfNeeded();
546 void WebsiteDataStore::fetchDataForTopPrivatelyControlledDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<String>& topPrivatelyControlledDomains, Function<void(Vector<WebsiteDataRecord>&&, HashSet<String>&&)>&& completionHandler)
548 fetchDataAndApply(dataTypes, fetchOptions, m_queue.copyRef(), [topPrivatelyControlledDomains = crossThreadCopy(topPrivatelyControlledDomains), completionHandler = WTFMove(completionHandler)] (auto&& existingDataRecords) mutable {
549 ASSERT(!RunLoop::isMain());
551 Vector<WebsiteDataRecord> matchingDataRecords;
552 HashSet<String> domainsWithMatchingDataRecords;
553 for (auto&& dataRecord : existingDataRecords) {
554 for (auto& topPrivatelyControlledDomain : topPrivatelyControlledDomains) {
555 if (dataRecord.matchesTopPrivatelyControlledDomain(topPrivatelyControlledDomain)) {
556 matchingDataRecords.append(WTFMove(dataRecord));
557 domainsWithMatchingDataRecords.add(topPrivatelyControlledDomain.isolatedCopy());
562 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), matchingDataRecords = WTFMove(matchingDataRecords), domainsWithMatchingDataRecords = WTFMove(domainsWithMatchingDataRecords)] () mutable {
563 completionHandler(WTFMove(matchingDataRecords), WTFMove(domainsWithMatchingDataRecords));
568 void WebsiteDataStore::topPrivatelyControlledDomainsWithWebsiteData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void(HashSet<String>&&)>&& completionHandler)
570 fetchData(dataTypes, fetchOptions, [completionHandler = WTFMove(completionHandler), protectedThis = makeRef(*this)](auto&& existingDataRecords) {
571 HashSet<String> domainsWithDataRecords;
572 for (auto&& dataRecord : existingDataRecords) {
573 String domain = dataRecord.topPrivatelyControlledDomain();
574 if (domain.isEmpty())
576 domainsWithDataRecords.add(WTFMove(domain));
578 completionHandler(WTFMove(domainsWithDataRecords));
582 static ProcessAccessType computeNetworkProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
584 ProcessAccessType processAccessType = ProcessAccessType::None;
586 if (dataTypes.contains(WebsiteDataType::Cookies)) {
587 if (isNonPersistentStore)
588 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
590 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
593 if (dataTypes.contains(WebsiteDataType::DiskCache) && !isNonPersistentStore)
594 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
596 if (dataTypes.contains(WebsiteDataType::HSTSCache))
597 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
599 if (dataTypes.contains(WebsiteDataType::Credentials))
600 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
602 if (dataTypes.contains(WebsiteDataType::DOMCache))
603 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
605 return processAccessType;
608 static ProcessAccessType computeWebProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
610 UNUSED_PARAM(isNonPersistentStore);
612 ProcessAccessType processAccessType = ProcessAccessType::None;
614 if (dataTypes.contains(WebsiteDataType::MemoryCache))
615 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
617 if (dataTypes.contains(WebsiteDataType::Credentials))
618 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
620 return processAccessType;
623 void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, std::chrono::system_clock::time_point modifiedSince, Function<void()>&& completionHandler)
625 struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
626 explicit CallbackAggregator(Function<void()>&& completionHandler)
627 : completionHandler(WTFMove(completionHandler))
631 void addPendingCallback()
636 void removePendingCallback()
638 ASSERT(pendingCallbacks);
646 if (!pendingCallbacks)
647 RunLoop::main().dispatch(WTFMove(completionHandler));
650 unsigned pendingCallbacks = 0;
651 Function<void()> completionHandler;
654 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
657 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
658 callbackAggregator->addPendingCallback();
659 m_queue->dispatch([modifiedSince, mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
660 WebCore::HTMLMediaElement::clearMediaCache(mediaCacheDirectory, modifiedSince);
662 WTF::RunLoop::main().dispatch([callbackAggregator] {
663 callbackAggregator->removePendingCallback();
669 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
670 if (networkProcessAccessType != ProcessAccessType::None) {
671 for (auto& processPool : processPools()) {
672 switch (networkProcessAccessType) {
673 case ProcessAccessType::OnlyIfLaunched:
674 if (!processPool->networkProcess())
678 case ProcessAccessType::Launch:
679 processPool->ensureNetworkProcess(this);
682 case ProcessAccessType::None:
683 ASSERT_NOT_REACHED();
686 callbackAggregator->addPendingCallback();
687 processPool->networkProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
688 callbackAggregator->removePendingCallback();
693 auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
694 if (webProcessAccessType != ProcessAccessType::None) {
695 for (auto& process : processes()) {
696 switch (webProcessAccessType) {
697 case ProcessAccessType::OnlyIfLaunched:
698 if (!process->canSendMessage())
702 case ProcessAccessType::Launch:
703 // FIXME: Handle this.
704 ASSERT_NOT_REACHED();
707 case ProcessAccessType::None:
708 ASSERT_NOT_REACHED();
711 callbackAggregator->addPendingCallback();
712 process->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] {
713 callbackAggregator->removePendingCallback();
718 if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
719 callbackAggregator->addPendingCallback();
721 m_storageManager->deleteSessionStorageOrigins([callbackAggregator] {
722 callbackAggregator->removePendingCallback();
726 if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
727 callbackAggregator->addPendingCallback();
729 m_storageManager->deleteLocalStorageOriginsModifiedSince(modifiedSince, [callbackAggregator] {
730 callbackAggregator->removePendingCallback();
734 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
735 callbackAggregator->addPendingCallback();
737 m_queue->dispatch([applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
738 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
740 storage->deleteAllCaches();
742 WTF::RunLoop::main().dispatch([callbackAggregator] {
743 callbackAggregator->removePendingCallback();
748 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
749 callbackAggregator->addPendingCallback();
751 m_queue->dispatch([webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy(), callbackAggregator, modifiedSince] {
752 WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->deleteDatabasesModifiedSince(modifiedSince);
754 RunLoop::main().dispatch([callbackAggregator] {
755 callbackAggregator->removePendingCallback();
760 if ((dataTypes.contains(WebsiteDataType::IndexedDBDatabases)
761 #if ENABLE(SERVICE_WORKER)
762 || dataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)
764 ) && isPersistent()) {
765 for (auto& processPool : processPools()) {
766 processPool->ensureStorageProcessAndWebsiteDataStore(this);
768 callbackAggregator->addPendingCallback();
769 processPool->storageProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
770 callbackAggregator->removePendingCallback();
775 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
776 callbackAggregator->addPendingCallback();
778 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator, modifiedSince] {
779 removeMediaKeys(mediaKeysStorageDirectory, modifiedSince);
781 RunLoop::main().dispatch([callbackAggregator] {
782 callbackAggregator->removePendingCallback();
787 if (dataTypes.contains(WebsiteDataType::SearchFieldRecentSearches) && isPersistent()) {
788 callbackAggregator->addPendingCallback();
790 m_queue->dispatch([modifiedSince, callbackAggregator] {
791 platformRemoveRecentSearches(modifiedSince);
793 RunLoop::main().dispatch([callbackAggregator] {
794 callbackAggregator->removePendingCallback();
799 #if ENABLE(NETSCAPE_PLUGIN_API)
800 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
803 static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, std::chrono::system_clock::time_point modifiedSince)
805 new State(WTFMove(callbackAggregator), WTFMove(plugins), modifiedSince);
809 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, std::chrono::system_clock::time_point modifiedSince)
810 : m_callbackAggregator(WTFMove(callbackAggregator))
811 , m_plugins(WTFMove(plugins))
812 , m_modifiedSince(modifiedSince)
814 m_callbackAggregator->addPendingCallback();
816 deleteWebsiteDataForNextPlugin();
821 ASSERT(m_plugins.isEmpty());
824 void deleteWebsiteDataForNextPlugin()
826 if (m_plugins.isEmpty()) {
827 m_callbackAggregator->removePendingCallback();
833 auto plugin = m_plugins.takeLast();
834 PluginProcessManager::singleton().deleteWebsiteData(plugin, m_modifiedSince, [this] {
835 deleteWebsiteDataForNextPlugin();
839 Ref<CallbackAggregator> m_callbackAggregator;
840 Vector<PluginModuleInfo> m_plugins;
841 std::chrono::system_clock::time_point m_modifiedSince;
844 State::deleteData(*callbackAggregator, plugins(), modifiedSince);
848 // FIXME <rdar://problem/33491222>; scheduleClearInMemoryAndPersistent does not have a completion handler,
849 // so the completion handler for this removeData() call can be called prematurely.
850 if (dataTypes.contains(WebsiteDataType::ResourceLoadStatistics) && m_resourceLoadStatistics) {
851 auto deletedTypesRaw = dataTypes.toRaw();
852 auto monitoredTypesRaw = WebResourceLoadStatisticsStore::monitoredDataTypes().toRaw();
854 // If we are deleting all of the data types that the resource load statistics store monitors
855 // we do not need to re-grandfather old data.
856 if ((monitoredTypesRaw & deletedTypesRaw) == monitoredTypesRaw)
857 m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince, WebResourceLoadStatisticsStore::ShouldGrandfather::No);
859 m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince, WebResourceLoadStatisticsStore::ShouldGrandfather::Yes);
861 clearResourceLoadStatisticsInWebProcesses();
864 // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
865 callbackAggregator->callIfNeeded();
868 void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, const Vector<WebsiteDataRecord>& dataRecords, Function<void()>&& completionHandler)
870 Vector<WebCore::SecurityOriginData> origins;
872 for (const auto& dataRecord : dataRecords) {
873 for (auto& origin : dataRecord.origins)
874 origins.append(origin);
877 struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
878 explicit CallbackAggregator(Function<void()>&& completionHandler)
879 : completionHandler(WTFMove(completionHandler))
883 void addPendingCallback()
888 void removePendingCallback()
890 ASSERT(pendingCallbacks);
898 if (!pendingCallbacks)
899 RunLoop::main().dispatch(WTFMove(completionHandler));
902 unsigned pendingCallbacks = 0;
903 Function<void()> completionHandler;
906 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
908 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
909 HashSet<WebCore::SecurityOriginData> origins;
910 for (const auto& dataRecord : dataRecords) {
911 for (const auto& origin : dataRecord.origins)
916 callbackAggregator->addPendingCallback();
917 m_queue->dispatch([origins = WTFMove(origins), mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
919 // FIXME: Move SecurityOrigin::toRawString to SecurityOriginData and
920 // make HTMLMediaElement::clearMediaCacheForOrigins take SecurityOriginData.
921 HashSet<RefPtr<WebCore::SecurityOrigin>> securityOrigins;
922 for (auto& origin : origins)
923 securityOrigins.add(origin.securityOrigin());
924 WebCore::HTMLMediaElement::clearMediaCacheForOrigins(mediaCacheDirectory, securityOrigins);
926 WTF::RunLoop::main().dispatch([callbackAggregator] {
927 callbackAggregator->removePendingCallback();
933 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
934 if (networkProcessAccessType != ProcessAccessType::None) {
935 for (auto& processPool : processPools()) {
936 switch (networkProcessAccessType) {
937 case ProcessAccessType::OnlyIfLaunched:
938 if (!processPool->networkProcess())
942 case ProcessAccessType::Launch:
943 processPool->ensureNetworkProcess(this);
946 case ProcessAccessType::None:
947 ASSERT_NOT_REACHED();
950 Vector<String> cookieHostNames;
951 for (const auto& dataRecord : dataRecords) {
952 for (auto& hostName : dataRecord.cookieHostNames)
953 cookieHostNames.append(hostName);
956 callbackAggregator->addPendingCallback();
957 processPool->networkProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, cookieHostNames, [callbackAggregator, processPool] {
958 callbackAggregator->removePendingCallback();
963 auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
964 if (webProcessAccessType != ProcessAccessType::None) {
965 for (auto& process : processes()) {
966 switch (webProcessAccessType) {
967 case ProcessAccessType::OnlyIfLaunched:
968 if (!process->canSendMessage())
972 case ProcessAccessType::Launch:
973 // FIXME: Handle this.
974 ASSERT_NOT_REACHED();
977 case ProcessAccessType::None:
978 ASSERT_NOT_REACHED();
981 callbackAggregator->addPendingCallback();
983 process->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator] {
984 callbackAggregator->removePendingCallback();
989 if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
990 callbackAggregator->addPendingCallback();
992 m_storageManager->deleteSessionStorageEntriesForOrigins(origins, [callbackAggregator] {
993 callbackAggregator->removePendingCallback();
997 if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
998 callbackAggregator->addPendingCallback();
1000 m_storageManager->deleteLocalStorageEntriesForOrigins(origins, [callbackAggregator] {
1001 callbackAggregator->removePendingCallback();
1005 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
1006 HashSet<WebCore::SecurityOriginData> origins;
1007 for (const auto& dataRecord : dataRecords) {
1008 for (const auto& origin : dataRecord.origins)
1009 origins.add(origin);
1012 callbackAggregator->addPendingCallback();
1013 m_queue->dispatch([origins = WTFMove(origins), applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
1014 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
1016 for (const auto& origin : origins)
1017 storage->deleteCacheForOrigin(origin.securityOrigin());
1019 WTF::RunLoop::main().dispatch([callbackAggregator] {
1020 callbackAggregator->removePendingCallback();
1025 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
1026 HashSet<WebCore::SecurityOriginData> origins;
1027 for (const auto& dataRecord : dataRecords) {
1028 for (const auto& origin : dataRecord.origins)
1029 origins.add(origin);
1032 callbackAggregator->addPendingCallback();
1033 m_queue->dispatch([origins = WTFMove(origins), callbackAggregator, webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy()] {
1034 auto databaseTracker = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory);
1035 for (auto& origin : origins)
1036 databaseTracker->deleteOrigin(origin);
1037 RunLoop::main().dispatch([callbackAggregator] {
1038 callbackAggregator->removePendingCallback();
1043 if ((dataTypes.contains(WebsiteDataType::IndexedDBDatabases)
1044 #if ENABLE(SERVICE_WORKER)
1045 || dataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)
1047 ) && isPersistent()) {
1048 for (auto& processPool : processPools()) {
1049 processPool->ensureStorageProcessAndWebsiteDataStore(this);
1051 callbackAggregator->addPendingCallback();
1052 processPool->storageProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator, processPool] {
1053 callbackAggregator->removePendingCallback();
1058 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
1059 HashSet<WebCore::SecurityOriginData> origins;
1060 for (const auto& dataRecord : dataRecords) {
1061 for (const auto& origin : dataRecord.origins)
1062 origins.add(origin);
1065 callbackAggregator->addPendingCallback();
1066 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator, origins = WTFMove(origins)] {
1068 removeMediaKeys(mediaKeysStorageDirectory, origins);
1070 RunLoop::main().dispatch([callbackAggregator] {
1071 callbackAggregator->removePendingCallback();
1076 #if ENABLE(NETSCAPE_PLUGIN_API)
1077 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
1078 Vector<String> hostNames;
1079 for (const auto& dataRecord : dataRecords) {
1080 for (const auto& hostName : dataRecord.pluginDataHostNames)
1081 hostNames.append(hostName);
1087 static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1089 new State(WTFMove(callbackAggregator), WTFMove(plugins), WTFMove(hostNames));
1093 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1094 : m_callbackAggregator(WTFMove(callbackAggregator))
1095 , m_plugins(WTFMove(plugins))
1096 , m_hostNames(WTFMove(hostNames))
1098 m_callbackAggregator->addPendingCallback();
1100 deleteWebsiteDataForNextPlugin();
1105 ASSERT(m_plugins.isEmpty());
1108 void deleteWebsiteDataForNextPlugin()
1110 if (m_plugins.isEmpty()) {
1111 m_callbackAggregator->removePendingCallback();
1117 auto plugin = m_plugins.takeLast();
1118 PluginProcessManager::singleton().deleteWebsiteDataForHostNames(plugin, m_hostNames, [this] {
1119 deleteWebsiteDataForNextPlugin();
1123 Ref<CallbackAggregator> m_callbackAggregator;
1124 Vector<PluginModuleInfo> m_plugins;
1125 Vector<String> m_hostNames;
1128 if (!hostNames.isEmpty())
1129 State::deleteData(*callbackAggregator, plugins(), WTFMove(hostNames));
1133 // FIXME <rdar://problem/33491222>; scheduleClearInMemoryAndPersistent does not have a completion handler,
1134 // so the completion handler for this removeData() call can be called prematurely.
1135 if (dataTypes.contains(WebsiteDataType::ResourceLoadStatistics) && m_resourceLoadStatistics) {
1136 auto deletedTypesRaw = dataTypes.toRaw();
1137 auto monitoredTypesRaw = WebResourceLoadStatisticsStore::monitoredDataTypes().toRaw();
1139 // If we are deleting all of the data types that the resource load statistics store monitors
1140 // we do not need to re-grandfather old data.
1141 if ((monitoredTypesRaw & deletedTypesRaw) == monitoredTypesRaw)
1142 m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(WebResourceLoadStatisticsStore::ShouldGrandfather::No);
1144 m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(WebResourceLoadStatisticsStore::ShouldGrandfather::Yes);
1146 clearResourceLoadStatisticsInWebProcesses();
1149 // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
1150 callbackAggregator->callIfNeeded();
1153 void WebsiteDataStore::removeDataForTopPrivatelyControlledDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<String>& topPrivatelyControlledDomains, Function<void(HashSet<String>&&)>&& completionHandler)
1155 fetchDataForTopPrivatelyControlledDomains(dataTypes, fetchOptions, topPrivatelyControlledDomains, [dataTypes, completionHandler = WTFMove(completionHandler), this, protectedThis = makeRef(*this)](Vector<WebsiteDataRecord>&& websiteDataRecords, HashSet<String>&& domainsWithDataRecords) mutable {
1156 this->removeData(dataTypes, websiteDataRecords, [domainsWithDataRecords = WTFMove(domainsWithDataRecords), completionHandler = WTFMove(completionHandler)]() mutable {
1157 completionHandler(WTFMove(domainsWithDataRecords));
1162 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1163 void WebsiteDataStore::updatePrevalentDomainsToPartitionOrBlockCookies(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst shouldClearFirst)
1165 for (auto& processPool : processPools())
1166 processPool->sendToNetworkingProcess(Messages::NetworkProcess::UpdatePrevalentDomainsToPartitionOrBlockCookies(m_sessionID, domainsToPartition, domainsToBlock, domainsToNeitherPartitionNorBlock, shouldClearFirst == ShouldClearFirst::Yes));
1169 void WebsiteDataStore::updateStorageAccessForPrevalentDomainsHandler(const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, bool value, WTF::CompletionHandler<void(bool wasGranted)>&& callback)
1171 for (auto& processPool : processPools())
1172 processPool->networkProcess()->updateStorageAccessForPrevalentDomains(m_sessionID, resourceDomain, firstPartyDomain, frameID, pageID, value, WTFMove(callback));
1175 void WebsiteDataStore::removePrevalentDomains(const Vector<String>& domains)
1177 for (auto& processPool : processPools())
1178 processPool->sendToNetworkingProcess(Messages::NetworkProcess::RemovePrevalentDomains(m_sessionID, domains));
1182 void WebsiteDataStore::networkProcessDidCrash()
1184 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1185 if (m_resourceLoadStatistics)
1186 m_resourceLoadStatistics->scheduleCookiePartitioningStateReset();
1190 void WebsiteDataStore::webPageWasAdded(WebPageProxy& webPageProxy)
1192 if (m_storageManager)
1193 m_storageManager->createSessionStorageNamespace(webPageProxy.pageID(), std::numeric_limits<unsigned>::max());
1196 void WebsiteDataStore::webPageWasRemoved(WebPageProxy& webPageProxy)
1198 if (m_storageManager)
1199 m_storageManager->destroySessionStorageNamespace(webPageProxy.pageID());
1202 void WebsiteDataStore::webProcessWillOpenConnection(WebProcessProxy& webProcessProxy, IPC::Connection& connection)
1204 if (m_storageManager)
1205 m_storageManager->processWillOpenConnection(webProcessProxy, connection);
1207 if (m_resourceLoadStatistics)
1208 m_resourceLoadStatistics->processWillOpenConnection(webProcessProxy, connection);
1211 void WebsiteDataStore::webPageWillOpenConnection(WebPageProxy& webPageProxy, IPC::Connection& connection)
1213 if (m_storageManager)
1214 m_storageManager->setAllowedSessionStorageNamespaceConnection(webPageProxy.pageID(), &connection);
1217 void WebsiteDataStore::webPageDidCloseConnection(WebPageProxy& webPageProxy, IPC::Connection&)
1219 if (m_storageManager)
1220 m_storageManager->setAllowedSessionStorageNamespaceConnection(webPageProxy.pageID(), nullptr);
1223 void WebsiteDataStore::webProcessDidCloseConnection(WebProcessProxy& webProcessProxy, IPC::Connection& connection)
1225 if (m_resourceLoadStatistics)
1226 m_resourceLoadStatistics->processDidCloseConnection(webProcessProxy, connection);
1228 if (m_storageManager)
1229 m_storageManager->processDidCloseConnection(webProcessProxy, connection);
1232 bool WebsiteDataStore::isAssociatedProcessPool(WebProcessPool& processPool) const
1234 if (auto* processPoolDataStore = processPool.websiteDataStore())
1235 return &processPoolDataStore->websiteDataStore() == this;
1239 HashSet<RefPtr<WebProcessPool>> WebsiteDataStore::processPools(size_t count, bool ensureAPoolExists) const
1241 HashSet<RefPtr<WebProcessPool>> processPools;
1242 for (auto& process : processes())
1243 processPools.add(&process->processPool());
1245 if (processPools.isEmpty()) {
1246 // Check if we're one of the legacy data stores.
1247 for (auto& processPool : WebProcessPool::allProcessPools()) {
1248 if (!isAssociatedProcessPool(*processPool))
1251 processPools.add(processPool);
1253 if (processPools.size() == count)
1258 if (processPools.isEmpty() && count && ensureAPoolExists) {
1259 auto processPool = WebProcessPool::create(API::ProcessPoolConfiguration::createWithWebsiteDataStoreConfiguration(m_configuration));
1260 processPools.add(processPool.ptr());
1263 return processPools;
1266 #if ENABLE(NETSCAPE_PLUGIN_API)
1267 Vector<PluginModuleInfo> WebsiteDataStore::plugins() const
1269 Vector<PluginModuleInfo> plugins;
1271 for (auto& processPool : processPools()) {
1272 for (auto& plugin : processPool->pluginInfoStore().plugins())
1273 plugins.append(plugin);
1280 static String computeMediaKeyFile(const String& mediaKeyDirectory)
1282 return WebCore::FileSystem::pathByAppendingComponent(mediaKeyDirectory, "SecureStop.plist");
1285 Vector<WebCore::SecurityOriginData> WebsiteDataStore::mediaKeyOrigins(const String& mediaKeysStorageDirectory)
1287 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1289 Vector<WebCore::SecurityOriginData> origins;
1291 for (const auto& originPath : WebCore::FileSystem::listDirectory(mediaKeysStorageDirectory, "*")) {
1292 auto mediaKeyFile = computeMediaKeyFile(originPath);
1293 if (!WebCore::FileSystem::fileExists(mediaKeyFile))
1296 auto mediaKeyIdentifier = WebCore::FileSystem::pathGetFileName(originPath);
1298 if (auto securityOrigin = WebCore::SecurityOriginData::fromDatabaseIdentifier(mediaKeyIdentifier))
1299 origins.append(*securityOrigin);
1305 void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, std::chrono::system_clock::time_point modifiedSince)
1307 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1309 for (const auto& mediaKeyDirectory : WebCore::FileSystem::listDirectory(mediaKeysStorageDirectory, "*")) {
1310 auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1312 time_t modificationTime;
1313 if (!WebCore::FileSystem::getFileModificationTime(mediaKeyFile, modificationTime))
1316 if (std::chrono::system_clock::from_time_t(modificationTime) < modifiedSince)
1319 WebCore::FileSystem::deleteFile(mediaKeyFile);
1320 WebCore::FileSystem::deleteEmptyDirectory(mediaKeyDirectory);
1324 void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, const HashSet<WebCore::SecurityOriginData>& origins)
1326 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1328 for (const auto& origin : origins) {
1329 auto mediaKeyDirectory = WebCore::FileSystem::pathByAppendingComponent(mediaKeysStorageDirectory, origin.databaseIdentifier());
1330 auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1332 WebCore::FileSystem::deleteFile(mediaKeyFile);
1333 WebCore::FileSystem::deleteEmptyDirectory(mediaKeyDirectory);
1337 bool WebsiteDataStore::resourceLoadStatisticsEnabled() const
1339 return !!m_resourceLoadStatistics;
1342 void WebsiteDataStore::setResourceLoadStatisticsEnabled(bool enabled)
1344 if (enabled == resourceLoadStatisticsEnabled())
1348 ASSERT(!m_resourceLoadStatistics);
1349 enableResourceLoadStatisticsAndSetTestingCallback(nullptr);
1353 m_resourceLoadStatistics = nullptr;
1355 auto existingProcessPools = processPools(std::numeric_limits<size_t>::max(), false);
1356 for (auto& processPool : existingProcessPools)
1357 processPool->setResourceLoadStatisticsEnabled(false);
1360 void WebsiteDataStore::enableResourceLoadStatisticsAndSetTestingCallback(Function<void (const String&)>&& callback)
1362 if (m_resourceLoadStatistics) {
1363 m_resourceLoadStatistics->setStatisticsTestingCallback(WTFMove(callback));
1367 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1368 m_resourceLoadStatistics = WebResourceLoadStatisticsStore::create(m_configuration.resourceLoadStatisticsDirectory, WTFMove(callback), [this] (const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst shouldClearFirst) {
1369 updatePrevalentDomainsToPartitionOrBlockCookies(domainsToPartition, domainsToBlock, domainsToNeitherPartitionNorBlock, shouldClearFirst);
1370 }, [this, protectedThis = makeRef(*this)] (const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, bool value, WTF::Function<void(bool wasGranted)>&& callback) {
1371 updateStorageAccessForPrevalentDomainsHandler(resourceDomain, firstPartyDomain, frameID, pageID, value, WTFMove(callback));
1372 }, [this, protectedThis = makeRef(*this)] (const Vector<String>& domainsToRemove) {
1373 removePrevalentDomains(domainsToRemove);
1376 m_resourceLoadStatistics = WebResourceLoadStatisticsStore::create(m_configuration.resourceLoadStatisticsDirectory, WTFMove(callback));
1379 for (auto& processPool : processPools())
1380 processPool->setResourceLoadStatisticsEnabled(true);
1383 void WebsiteDataStore::clearResourceLoadStatisticsInWebProcesses()
1385 if (!resourceLoadStatisticsEnabled())
1388 for (auto& processPool : processPools())
1389 processPool->clearResourceLoadStatistics();
1392 StorageProcessCreationParameters WebsiteDataStore::storageProcessParameters()
1394 resolveDirectoriesIfNecessary();
1396 StorageProcessCreationParameters parameters;
1398 parameters.sessionID = m_sessionID;
1400 #if ENABLE(INDEXED_DATABASE)
1401 parameters.indexedDatabaseDirectory = resolvedIndexedDatabaseDirectory();
1402 if (!parameters.indexedDatabaseDirectory.isEmpty())
1403 SandboxExtension::createHandleForReadWriteDirectory(parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
1405 #if ENABLE(SERVICE_WORKER)
1406 parameters.serviceWorkerRegistrationDirectory = resolvedServiceWorkerRegistrationDirectory();
1407 if (!parameters.serviceWorkerRegistrationDirectory.isEmpty())
1408 SandboxExtension::createHandleForReadWriteDirectory(parameters.serviceWorkerRegistrationDirectory, parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
1414 Vector<WebCore::Cookie> WebsiteDataStore::pendingCookies() const
1416 return copyToVector(m_pendingCookies);
1419 void WebsiteDataStore::addPendingCookie(const WebCore::Cookie& cookie)
1421 m_pendingCookies.add(cookie);
1424 void WebsiteDataStore::removePendingCookie(const WebCore::Cookie& cookie)
1426 m_pendingCookies.remove(cookie);
1429 void WebsiteDataStore::hasStorageAccess(String&& subFrameHost, String&& topFrameHost, WTF::CompletionHandler<void (bool)>&& callback)
1431 if (!resourceLoadStatisticsEnabled()) {
1436 m_resourceLoadStatistics->hasStorageAccess(WTFMove(subFrameHost), WTFMove(topFrameHost), WTFMove(callback));
1439 void WebsiteDataStore::requestStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void (bool)>&& callback)
1441 if (!resourceLoadStatisticsEnabled()) {
1446 m_resourceLoadStatistics->requestStorageAccess(WTFMove(subFrameHost), WTFMove(topFrameHost), frameID, pageID, WTFMove(callback));
1449 #if !PLATFORM(COCOA)
1450 WebsiteDataStoreParameters WebsiteDataStore::parameters()
1452 // FIXME: Implement cookies.
1453 WebsiteDataStoreParameters parameters;
1454 parameters.networkSessionParameters.sessionID = m_sessionID;