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/CrossThreadCopier.h>
49 #include <wtf/RunLoop.h>
51 #if ENABLE(NETSCAPE_PLUGIN_API)
52 #include "PluginProcessManager.h"
57 Ref<WebsiteDataStore> WebsiteDataStore::createNonPersistent()
59 return adoptRef(*new WebsiteDataStore(PAL::SessionID::generateEphemeralSessionID()));
62 Ref<WebsiteDataStore> WebsiteDataStore::create(Configuration configuration, PAL::SessionID sessionID)
64 return adoptRef(*new WebsiteDataStore(WTFMove(configuration), sessionID));
67 WebsiteDataStore::WebsiteDataStore(Configuration configuration, PAL::SessionID sessionID)
68 : m_sessionID(sessionID)
69 , m_configuration(WTFMove(configuration))
70 , m_storageManager(StorageManager::create(m_configuration.localStorageDirectory))
71 , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
76 WebsiteDataStore::WebsiteDataStore(PAL::SessionID sessionID)
77 : m_sessionID(sessionID)
79 , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
84 WebsiteDataStore::~WebsiteDataStore()
88 if (m_sessionID.isValid() && m_sessionID != PAL::SessionID::defaultSessionID()) {
89 for (auto& processPool : WebProcessPool::allProcessPools())
90 processPool->sendToNetworkingProcess(Messages::NetworkProcess::DestroySession(m_sessionID));
94 WebProcessPool* WebsiteDataStore::processPoolForCookieStorageOperations()
96 auto pools = processPools(1, false);
97 return pools.isEmpty() ? nullptr : pools.begin()->get();
100 void WebsiteDataStore::resolveDirectoriesIfNecessary()
102 if (m_hasResolvedDirectories)
104 m_hasResolvedDirectories = true;
106 // Resolve directory paths.
107 if (!m_configuration.applicationCacheDirectory.isEmpty())
108 m_resolvedConfiguration.applicationCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.applicationCacheDirectory);
109 if (!m_configuration.mediaCacheDirectory.isEmpty())
110 m_resolvedConfiguration.mediaCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.mediaCacheDirectory);
111 if (!m_configuration.mediaKeysStorageDirectory.isEmpty())
112 m_resolvedConfiguration.mediaKeysStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.mediaKeysStorageDirectory);
113 if (!m_configuration.webSQLDatabaseDirectory.isEmpty())
114 m_resolvedConfiguration.webSQLDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.webSQLDatabaseDirectory);
116 if (!m_configuration.indexedDBDatabaseDirectory.isEmpty())
117 m_resolvedConfiguration.indexedDBDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.indexedDBDatabaseDirectory);
119 if (!m_configuration.javaScriptConfigurationDirectory.isEmpty())
120 m_resolvedConfiguration.javaScriptConfigurationDirectory = resolvePathForSandboxExtension(m_configuration.javaScriptConfigurationDirectory);
122 // Resolve directories for file paths.
123 if (!m_configuration.cookieStorageFile.isEmpty()) {
124 m_resolvedConfiguration.cookieStorageFile = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebCore::directoryName(m_configuration.cookieStorageFile));
125 m_resolvedConfiguration.cookieStorageFile = WebCore::pathByAppendingComponent(m_resolvedConfiguration.cookieStorageFile, WebCore::pathGetFileName(m_configuration.cookieStorageFile));
129 void WebsiteDataStore::cloneSessionData(WebPageProxy& sourcePage, WebPageProxy& newPage)
131 auto& sourceDataStore = sourcePage.websiteDataStore();
132 auto& newDataStore = newPage.websiteDataStore();
134 // FIXME: Handle this.
135 if (&sourceDataStore != &newDataStore)
138 if (!sourceDataStore.m_storageManager)
141 sourceDataStore.m_storageManager->cloneSessionStorageNamespace(sourcePage.pageID(), newPage.pageID());
144 enum class ProcessAccessType {
150 static ProcessAccessType computeNetworkProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
152 ProcessAccessType processAccessType = ProcessAccessType::None;
154 if (dataTypes.contains(WebsiteDataType::Cookies)) {
155 if (isNonPersistentStore)
156 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
158 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
161 if (dataTypes.contains(WebsiteDataType::DiskCache) && !isNonPersistentStore)
162 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
164 return processAccessType;
167 static ProcessAccessType computeWebProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
169 UNUSED_PARAM(isNonPersistentStore);
171 ProcessAccessType processAccessType = ProcessAccessType::None;
173 if (dataTypes.contains(WebsiteDataType::MemoryCache))
174 return ProcessAccessType::OnlyIfLaunched;
176 return processAccessType;
179 void WebsiteDataStore::fetchData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void(Vector<WebsiteDataRecord>)>&& completionHandler)
181 fetchDataAndApply(dataTypes, fetchOptions, nullptr, WTFMove(completionHandler));
184 void WebsiteDataStore::fetchDataAndApply(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply)
186 struct CallbackAggregator final : ThreadSafeRefCounted<CallbackAggregator> {
187 explicit CallbackAggregator(OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply)
188 : fetchOptions(fetchOptions)
189 , queue(WTFMove(queue))
190 , apply(WTFMove(apply))
194 ~CallbackAggregator()
196 ASSERT(!pendingCallbacks);
199 void addPendingCallback()
204 void removePendingCallback(WebsiteData websiteData)
206 ASSERT(pendingCallbacks);
209 for (auto& entry : websiteData.entries) {
210 auto displayName = WebsiteDataRecord::displayNameForOrigin(entry.origin);
214 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
215 if (!record.displayName)
216 record.displayName = WTFMove(displayName);
218 record.add(entry.type, entry.origin);
220 if (fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes)) {
222 record.size = WebsiteDataRecord::Size { 0, { } };
224 record.size->totalSize += entry.size;
225 record.size->typeSizes.add(static_cast<unsigned>(entry.type), 0).iterator->value += entry.size;
229 for (auto& hostName : websiteData.hostNamesWithCookies) {
230 auto displayName = WebsiteDataRecord::displayNameForCookieHostName(hostName);
234 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
235 if (!record.displayName)
236 record.displayName = WTFMove(displayName);
238 record.addCookieHostName(hostName);
241 #if ENABLE(NETSCAPE_PLUGIN_API)
242 for (auto& hostName : websiteData.hostNamesWithPluginData) {
243 auto displayName = WebsiteDataRecord::displayNameForPluginDataHostName(hostName);
247 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
248 if (!record.displayName)
249 record.displayName = WTFMove(displayName);
251 record.addPluginDataHostName(hostName);
255 for (auto& origin : websiteData.originsWithCredentials) {
256 auto& record = m_websiteDataRecords.add(origin, WebsiteDataRecord { }).iterator->value;
258 record.addOriginWithCredential(origin);
266 if (pendingCallbacks)
269 Vector<WebsiteDataRecord> records;
270 records.reserveInitialCapacity(m_websiteDataRecords.size());
271 for (auto& record : m_websiteDataRecords.values())
272 records.uncheckedAppend(WTFMove(record));
274 auto processRecords = [apply = WTFMove(apply), records = WTFMove(records)] () mutable {
275 apply(WTFMove(records));
279 queue->dispatch(WTFMove(processRecords));
281 RunLoop::main().dispatch(WTFMove(processRecords));
284 const OptionSet<WebsiteDataFetchOption> fetchOptions;
286 unsigned pendingCallbacks = 0;
287 RefPtr<WorkQueue> queue;
288 Function<void(Vector<WebsiteDataRecord>)> apply;
290 HashMap<String, WebsiteDataRecord> m_websiteDataRecords;
293 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(fetchOptions, WTFMove(queue), WTFMove(apply)));
296 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
297 callbackAggregator->addPendingCallback();
298 m_queue->dispatch([mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
299 // FIXME: Make HTMLMediaElement::originsInMediaCache return a collection of SecurityOriginDatas.
300 HashSet<RefPtr<WebCore::SecurityOrigin>> origins = WebCore::HTMLMediaElement::originsInMediaCache(mediaCacheDirectory);
301 WebsiteData websiteData;
303 for (auto& origin : origins) {
304 WebsiteData::Entry entry { WebCore::SecurityOriginData::fromSecurityOrigin(*origin), WebsiteDataType::DiskCache, 0 };
305 websiteData.entries.append(WTFMove(entry));
308 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
309 callbackAggregator->removePendingCallback(WTFMove(websiteData));
315 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
316 if (networkProcessAccessType != ProcessAccessType::None) {
317 for (auto& processPool : processPools()) {
318 switch (networkProcessAccessType) {
319 case ProcessAccessType::OnlyIfLaunched:
320 if (!processPool->networkProcess())
324 case ProcessAccessType::Launch:
325 processPool->ensureNetworkProcess(this);
328 case ProcessAccessType::None:
329 ASSERT_NOT_REACHED();
332 callbackAggregator->addPendingCallback();
333 processPool->networkProcess()->fetchWebsiteData(m_sessionID, dataTypes, fetchOptions, [callbackAggregator, processPool](WebsiteData websiteData) {
334 callbackAggregator->removePendingCallback(WTFMove(websiteData));
339 auto webProcessAccessType = computeWebProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
340 if (webProcessAccessType != ProcessAccessType::None) {
341 for (auto& process : processes()) {
342 switch (webProcessAccessType) {
343 case ProcessAccessType::OnlyIfLaunched:
344 if (!process->canSendMessage())
348 case ProcessAccessType::Launch:
349 // FIXME: Handle this.
350 ASSERT_NOT_REACHED();
353 case ProcessAccessType::None:
354 ASSERT_NOT_REACHED();
357 callbackAggregator->addPendingCallback();
358 process->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator](WebsiteData websiteData) {
359 callbackAggregator->removePendingCallback(WTFMove(websiteData));
364 if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
365 callbackAggregator->addPendingCallback();
367 m_storageManager->getSessionStorageOrigins([callbackAggregator](HashSet<WebCore::SecurityOriginData>&& origins) {
368 WebsiteData websiteData;
370 while (!origins.isEmpty())
371 websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::SessionStorage, 0 });
373 callbackAggregator->removePendingCallback(WTFMove(websiteData));
377 if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
378 callbackAggregator->addPendingCallback();
380 m_storageManager->getLocalStorageOrigins([callbackAggregator](HashSet<WebCore::SecurityOriginData>&& origins) {
381 WebsiteData websiteData;
383 while (!origins.isEmpty())
384 websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::LocalStorage, 0 });
386 callbackAggregator->removePendingCallback(WTFMove(websiteData));
390 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
391 callbackAggregator->addPendingCallback();
393 m_queue->dispatch([fetchOptions, applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
394 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
396 WebsiteData websiteData;
398 HashSet<RefPtr<WebCore::SecurityOrigin>> origins;
399 // FIXME: getOriginsWithCache should return a collection of SecurityOriginDatas.
400 storage->getOriginsWithCache(origins);
402 for (auto& origin : origins) {
403 uint64_t size = fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes) ? storage->diskUsageForOrigin(*origin) : 0;
404 WebsiteData::Entry entry { WebCore::SecurityOriginData::fromSecurityOrigin(*origin), WebsiteDataType::OfflineWebApplicationCache, size };
406 websiteData.entries.append(WTFMove(entry));
409 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
410 callbackAggregator->removePendingCallback(WTFMove(websiteData));
415 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
416 callbackAggregator->addPendingCallback();
418 m_queue->dispatch([webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy(), callbackAggregator] {
419 auto origins = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->origins();
420 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
421 WebsiteData websiteData;
422 for (auto& origin : origins)
423 websiteData.entries.append(WebsiteData::Entry { WTFMove(origin), WebsiteDataType::WebSQLDatabases, 0 });
424 callbackAggregator->removePendingCallback(WTFMove(websiteData));
429 if (dataTypes.contains(WebsiteDataType::IndexedDBDatabases) && isPersistent()) {
430 for (auto& processPool : processPools()) {
431 processPool->ensureStorageProcessAndWebsiteDataStore(this);
433 callbackAggregator->addPendingCallback();
434 processPool->storageProcess()->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator, processPool](WebsiteData websiteData) {
435 callbackAggregator->removePendingCallback(WTFMove(websiteData));
440 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
441 callbackAggregator->addPendingCallback();
443 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator] {
444 auto origins = mediaKeyOrigins(mediaKeysStorageDirectory);
446 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
447 WebsiteData websiteData;
448 for (auto& origin : origins)
449 websiteData.entries.append(WebsiteData::Entry { origin, WebsiteDataType::MediaKeys, 0 });
451 callbackAggregator->removePendingCallback(WTFMove(websiteData));
456 #if ENABLE(NETSCAPE_PLUGIN_API)
457 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
460 static void fetchData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
462 new State(WTFMove(callbackAggregator), WTFMove(plugins));
466 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
467 : m_callbackAggregator(WTFMove(callbackAggregator))
468 , m_plugins(WTFMove(plugins))
470 m_callbackAggregator->addPendingCallback();
472 fetchWebsiteDataForNextPlugin();
477 ASSERT(m_plugins.isEmpty());
480 void fetchWebsiteDataForNextPlugin()
482 if (m_plugins.isEmpty()) {
483 WebsiteData websiteData;
484 websiteData.hostNamesWithPluginData = WTFMove(m_hostNames);
486 m_callbackAggregator->removePendingCallback(WTFMove(websiteData));
492 auto plugin = m_plugins.takeLast();
493 PluginProcessManager::singleton().fetchWebsiteData(plugin, [this](Vector<String> hostNames) {
494 for (auto& hostName : hostNames)
495 m_hostNames.add(WTFMove(hostName));
496 fetchWebsiteDataForNextPlugin();
500 Ref<CallbackAggregator> m_callbackAggregator;
501 Vector<PluginModuleInfo> m_plugins;
502 HashSet<String> m_hostNames;
505 State::fetchData(*callbackAggregator, plugins());
509 callbackAggregator->callIfNeeded();
512 void WebsiteDataStore::fetchDataForTopPrivatelyControlledDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<String>& topPrivatelyControlledDomains, Function<void(Vector<WebsiteDataRecord>&&, HashSet<String>&&)>&& completionHandler)
514 fetchDataAndApply(dataTypes, fetchOptions, m_queue.copyRef(), [topPrivatelyControlledDomains = crossThreadCopy(topPrivatelyControlledDomains), completionHandler = WTFMove(completionHandler)] (auto&& existingDataRecords) mutable {
515 ASSERT(!RunLoop::isMain());
517 Vector<WebsiteDataRecord> matchingDataRecords;
518 HashSet<String> domainsWithMatchingDataRecords;
519 for (auto&& dataRecord : existingDataRecords) {
520 for (auto& topPrivatelyControlledDomain : topPrivatelyControlledDomains) {
521 if (dataRecord.matchesTopPrivatelyControlledDomain(topPrivatelyControlledDomain)) {
522 matchingDataRecords.append(WTFMove(dataRecord));
523 domainsWithMatchingDataRecords.add(topPrivatelyControlledDomain.isolatedCopy());
528 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), matchingDataRecords = WTFMove(matchingDataRecords), domainsWithMatchingDataRecords = WTFMove(domainsWithMatchingDataRecords)] () mutable {
529 completionHandler(WTFMove(matchingDataRecords), WTFMove(domainsWithMatchingDataRecords));
534 void WebsiteDataStore::topPrivatelyControlledDomainsWithWebsiteData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void(HashSet<String>&&)>&& completionHandler)
536 fetchData(dataTypes, fetchOptions, [completionHandler = WTFMove(completionHandler), protectedThis = makeRef(*this)](auto&& existingDataRecords) {
537 HashSet<String> domainsWithDataRecords;
538 for (auto&& dataRecord : existingDataRecords) {
539 String domain = dataRecord.topPrivatelyControlledDomain();
540 if (domain.isEmpty())
542 domainsWithDataRecords.add(WTFMove(domain));
544 completionHandler(WTFMove(domainsWithDataRecords));
548 static ProcessAccessType computeNetworkProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
550 ProcessAccessType processAccessType = ProcessAccessType::None;
552 if (dataTypes.contains(WebsiteDataType::Cookies)) {
553 if (isNonPersistentStore)
554 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
556 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
559 if (dataTypes.contains(WebsiteDataType::DiskCache) && !isNonPersistentStore)
560 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
562 if (dataTypes.contains(WebsiteDataType::HSTSCache))
563 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
565 if (dataTypes.contains(WebsiteDataType::Credentials))
566 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
568 return processAccessType;
571 static ProcessAccessType computeWebProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
573 UNUSED_PARAM(isNonPersistentStore);
575 ProcessAccessType processAccessType = ProcessAccessType::None;
577 if (dataTypes.contains(WebsiteDataType::MemoryCache))
578 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
580 if (dataTypes.contains(WebsiteDataType::Credentials))
581 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
583 return processAccessType;
586 void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, std::chrono::system_clock::time_point modifiedSince, Function<void()>&& completionHandler)
588 struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
589 explicit CallbackAggregator(Function<void()>&& completionHandler)
590 : completionHandler(WTFMove(completionHandler))
594 void addPendingCallback()
599 void removePendingCallback()
601 ASSERT(pendingCallbacks);
609 if (!pendingCallbacks)
610 RunLoop::main().dispatch(WTFMove(completionHandler));
613 unsigned pendingCallbacks = 0;
614 Function<void()> completionHandler;
617 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
620 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
621 callbackAggregator->addPendingCallback();
622 m_queue->dispatch([modifiedSince, mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
623 WebCore::HTMLMediaElement::clearMediaCache(mediaCacheDirectory, modifiedSince);
625 WTF::RunLoop::main().dispatch([callbackAggregator] {
626 callbackAggregator->removePendingCallback();
632 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
633 if (networkProcessAccessType != ProcessAccessType::None) {
634 for (auto& processPool : processPools()) {
635 switch (networkProcessAccessType) {
636 case ProcessAccessType::OnlyIfLaunched:
637 if (!processPool->networkProcess())
641 case ProcessAccessType::Launch:
642 processPool->ensureNetworkProcess(this);
645 case ProcessAccessType::None:
646 ASSERT_NOT_REACHED();
649 callbackAggregator->addPendingCallback();
650 processPool->networkProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
651 callbackAggregator->removePendingCallback();
656 auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
657 if (webProcessAccessType != ProcessAccessType::None) {
658 for (auto& process : processes()) {
659 switch (webProcessAccessType) {
660 case ProcessAccessType::OnlyIfLaunched:
661 if (!process->canSendMessage())
665 case ProcessAccessType::Launch:
666 // FIXME: Handle this.
667 ASSERT_NOT_REACHED();
670 case ProcessAccessType::None:
671 ASSERT_NOT_REACHED();
674 callbackAggregator->addPendingCallback();
675 process->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] {
676 callbackAggregator->removePendingCallback();
681 if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
682 callbackAggregator->addPendingCallback();
684 m_storageManager->deleteSessionStorageOrigins([callbackAggregator] {
685 callbackAggregator->removePendingCallback();
689 if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
690 callbackAggregator->addPendingCallback();
692 m_storageManager->deleteLocalStorageOriginsModifiedSince(modifiedSince, [callbackAggregator] {
693 callbackAggregator->removePendingCallback();
697 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
698 callbackAggregator->addPendingCallback();
700 m_queue->dispatch([applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
701 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
703 storage->deleteAllCaches();
705 WTF::RunLoop::main().dispatch([callbackAggregator] {
706 callbackAggregator->removePendingCallback();
711 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
712 callbackAggregator->addPendingCallback();
714 m_queue->dispatch([webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy(), callbackAggregator, modifiedSince] {
715 WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->deleteDatabasesModifiedSince(modifiedSince);
717 RunLoop::main().dispatch([callbackAggregator] {
718 callbackAggregator->removePendingCallback();
723 if (dataTypes.contains(WebsiteDataType::IndexedDBDatabases) && isPersistent()) {
724 for (auto& processPool : processPools()) {
725 processPool->ensureStorageProcessAndWebsiteDataStore(this);
727 callbackAggregator->addPendingCallback();
728 processPool->storageProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
729 callbackAggregator->removePendingCallback();
734 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
735 callbackAggregator->addPendingCallback();
737 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator, modifiedSince] {
738 removeMediaKeys(mediaKeysStorageDirectory, modifiedSince);
740 RunLoop::main().dispatch([callbackAggregator] {
741 callbackAggregator->removePendingCallback();
746 if (dataTypes.contains(WebsiteDataType::SearchFieldRecentSearches) && isPersistent()) {
747 callbackAggregator->addPendingCallback();
749 m_queue->dispatch([modifiedSince, callbackAggregator] {
750 platformRemoveRecentSearches(modifiedSince);
752 RunLoop::main().dispatch([callbackAggregator] {
753 callbackAggregator->removePendingCallback();
758 #if ENABLE(NETSCAPE_PLUGIN_API)
759 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
762 static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, std::chrono::system_clock::time_point modifiedSince)
764 new State(WTFMove(callbackAggregator), WTFMove(plugins), modifiedSince);
768 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, std::chrono::system_clock::time_point modifiedSince)
769 : m_callbackAggregator(WTFMove(callbackAggregator))
770 , m_plugins(WTFMove(plugins))
771 , m_modifiedSince(modifiedSince)
773 m_callbackAggregator->addPendingCallback();
775 deleteWebsiteDataForNextPlugin();
780 ASSERT(m_plugins.isEmpty());
783 void deleteWebsiteDataForNextPlugin()
785 if (m_plugins.isEmpty()) {
786 m_callbackAggregator->removePendingCallback();
792 auto plugin = m_plugins.takeLast();
793 PluginProcessManager::singleton().deleteWebsiteData(plugin, m_modifiedSince, [this] {
794 deleteWebsiteDataForNextPlugin();
798 Ref<CallbackAggregator> m_callbackAggregator;
799 Vector<PluginModuleInfo> m_plugins;
800 std::chrono::system_clock::time_point m_modifiedSince;
803 State::deleteData(*callbackAggregator, plugins(), modifiedSince);
807 // FIXME <rdar://problem/33491222>; scheduleClearInMemoryAndPersistent does not have a completion handler,
808 // so the completion handler for this removeData() call can be called prematurely.
809 if (dataTypes.contains(WebsiteDataType::ResourceLoadStatistics) && m_resourceLoadStatistics) {
810 auto deletedTypesRaw = dataTypes.toRaw();
811 auto monitoredTypesRaw = WebResourceLoadStatisticsStore::monitoredDataTypes().toRaw();
813 // If we are deleting all of the data types that the resource load statistics store monitors
814 // we do not need to re-grandfather old data.
815 if ((monitoredTypesRaw & deletedTypesRaw) == monitoredTypesRaw)
816 m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince, WebResourceLoadStatisticsStore::ShouldGrandfather::No);
818 m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince, WebResourceLoadStatisticsStore::ShouldGrandfather::Yes);
820 clearResourceLoadStatisticsInWebProcesses();
823 // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
824 callbackAggregator->callIfNeeded();
827 void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, const Vector<WebsiteDataRecord>& dataRecords, Function<void()>&& completionHandler)
829 Vector<WebCore::SecurityOriginData> origins;
831 for (const auto& dataRecord : dataRecords) {
832 for (auto& origin : dataRecord.origins)
833 origins.append(origin);
836 struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
837 explicit CallbackAggregator(Function<void()>&& completionHandler)
838 : completionHandler(WTFMove(completionHandler))
842 void addPendingCallback()
847 void removePendingCallback()
849 ASSERT(pendingCallbacks);
857 if (!pendingCallbacks)
858 RunLoop::main().dispatch(WTFMove(completionHandler));
861 unsigned pendingCallbacks = 0;
862 Function<void()> completionHandler;
865 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
867 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
868 HashSet<WebCore::SecurityOriginData> origins;
869 for (const auto& dataRecord : dataRecords) {
870 for (const auto& origin : dataRecord.origins)
875 callbackAggregator->addPendingCallback();
876 m_queue->dispatch([origins = WTFMove(origins), mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
878 // FIXME: Move SecurityOrigin::toRawString to SecurityOriginData and
879 // make HTMLMediaElement::clearMediaCacheForOrigins take SecurityOriginData.
880 HashSet<RefPtr<WebCore::SecurityOrigin>> securityOrigins;
881 for (auto& origin : origins)
882 securityOrigins.add(origin.securityOrigin());
883 WebCore::HTMLMediaElement::clearMediaCacheForOrigins(mediaCacheDirectory, securityOrigins);
885 WTF::RunLoop::main().dispatch([callbackAggregator] {
886 callbackAggregator->removePendingCallback();
892 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
893 if (networkProcessAccessType != ProcessAccessType::None) {
894 for (auto& processPool : processPools()) {
895 switch (networkProcessAccessType) {
896 case ProcessAccessType::OnlyIfLaunched:
897 if (!processPool->networkProcess())
901 case ProcessAccessType::Launch:
902 processPool->ensureNetworkProcess(this);
905 case ProcessAccessType::None:
906 ASSERT_NOT_REACHED();
909 Vector<String> cookieHostNames;
910 for (const auto& dataRecord : dataRecords) {
911 for (auto& hostName : dataRecord.cookieHostNames)
912 cookieHostNames.append(hostName);
915 callbackAggregator->addPendingCallback();
916 processPool->networkProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, cookieHostNames, [callbackAggregator, processPool] {
917 callbackAggregator->removePendingCallback();
922 auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
923 if (webProcessAccessType != ProcessAccessType::None) {
924 for (auto& process : processes()) {
925 switch (webProcessAccessType) {
926 case ProcessAccessType::OnlyIfLaunched:
927 if (!process->canSendMessage())
931 case ProcessAccessType::Launch:
932 // FIXME: Handle this.
933 ASSERT_NOT_REACHED();
936 case ProcessAccessType::None:
937 ASSERT_NOT_REACHED();
940 callbackAggregator->addPendingCallback();
942 process->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator] {
943 callbackAggregator->removePendingCallback();
948 if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
949 callbackAggregator->addPendingCallback();
951 m_storageManager->deleteSessionStorageEntriesForOrigins(origins, [callbackAggregator] {
952 callbackAggregator->removePendingCallback();
956 if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
957 callbackAggregator->addPendingCallback();
959 m_storageManager->deleteLocalStorageEntriesForOrigins(origins, [callbackAggregator] {
960 callbackAggregator->removePendingCallback();
964 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
965 HashSet<WebCore::SecurityOriginData> origins;
966 for (const auto& dataRecord : dataRecords) {
967 for (const auto& origin : dataRecord.origins)
971 callbackAggregator->addPendingCallback();
972 m_queue->dispatch([origins = WTFMove(origins), applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
973 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
975 for (const auto& origin : origins)
976 storage->deleteCacheForOrigin(origin.securityOrigin());
978 WTF::RunLoop::main().dispatch([callbackAggregator] {
979 callbackAggregator->removePendingCallback();
984 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
985 HashSet<WebCore::SecurityOriginData> origins;
986 for (const auto& dataRecord : dataRecords) {
987 for (const auto& origin : dataRecord.origins)
991 callbackAggregator->addPendingCallback();
992 m_queue->dispatch([origins = WTFMove(origins), callbackAggregator, webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy()] {
993 auto databaseTracker = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory);
994 for (auto& origin : origins)
995 databaseTracker->deleteOrigin(origin);
996 RunLoop::main().dispatch([callbackAggregator] {
997 callbackAggregator->removePendingCallback();
1002 if (dataTypes.contains(WebsiteDataType::IndexedDBDatabases) && isPersistent()) {
1003 for (auto& processPool : processPools()) {
1004 processPool->ensureStorageProcessAndWebsiteDataStore(this);
1006 callbackAggregator->addPendingCallback();
1007 processPool->storageProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator, processPool] {
1008 callbackAggregator->removePendingCallback();
1013 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
1014 HashSet<WebCore::SecurityOriginData> origins;
1015 for (const auto& dataRecord : dataRecords) {
1016 for (const auto& origin : dataRecord.origins)
1017 origins.add(origin);
1020 callbackAggregator->addPendingCallback();
1021 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator, origins = WTFMove(origins)] {
1023 removeMediaKeys(mediaKeysStorageDirectory, origins);
1025 RunLoop::main().dispatch([callbackAggregator] {
1026 callbackAggregator->removePendingCallback();
1031 #if ENABLE(NETSCAPE_PLUGIN_API)
1032 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
1033 Vector<String> hostNames;
1034 for (const auto& dataRecord : dataRecords) {
1035 for (const auto& hostName : dataRecord.pluginDataHostNames)
1036 hostNames.append(hostName);
1042 static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1044 new State(WTFMove(callbackAggregator), WTFMove(plugins), WTFMove(hostNames));
1048 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1049 : m_callbackAggregator(WTFMove(callbackAggregator))
1050 , m_plugins(WTFMove(plugins))
1051 , m_hostNames(WTFMove(hostNames))
1053 m_callbackAggregator->addPendingCallback();
1055 deleteWebsiteDataForNextPlugin();
1060 ASSERT(m_plugins.isEmpty());
1063 void deleteWebsiteDataForNextPlugin()
1065 if (m_plugins.isEmpty()) {
1066 m_callbackAggregator->removePendingCallback();
1072 auto plugin = m_plugins.takeLast();
1073 PluginProcessManager::singleton().deleteWebsiteDataForHostNames(plugin, m_hostNames, [this] {
1074 deleteWebsiteDataForNextPlugin();
1078 Ref<CallbackAggregator> m_callbackAggregator;
1079 Vector<PluginModuleInfo> m_plugins;
1080 Vector<String> m_hostNames;
1083 State::deleteData(*callbackAggregator, plugins(), WTFMove(hostNames));
1087 // FIXME <rdar://problem/33491222>; scheduleClearInMemoryAndPersistent does not have a completion handler,
1088 // so the completion handler for this removeData() call can be called prematurely.
1089 if (dataTypes.contains(WebsiteDataType::ResourceLoadStatistics) && m_resourceLoadStatistics) {
1090 auto deletedTypesRaw = dataTypes.toRaw();
1091 auto monitoredTypesRaw = WebResourceLoadStatisticsStore::monitoredDataTypes().toRaw();
1093 // If we are deleting all of the data types that the resource load statistics store monitors
1094 // we do not need to re-grandfather old data.
1095 if ((monitoredTypesRaw & deletedTypesRaw) == monitoredTypesRaw)
1096 m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(WebResourceLoadStatisticsStore::ShouldGrandfather::No);
1098 m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(WebResourceLoadStatisticsStore::ShouldGrandfather::Yes);
1100 clearResourceLoadStatisticsInWebProcesses();
1103 // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
1104 callbackAggregator->callIfNeeded();
1107 void WebsiteDataStore::removeDataForTopPrivatelyControlledDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<String>& topPrivatelyControlledDomains, Function<void(HashSet<String>&&)>&& completionHandler)
1109 fetchDataForTopPrivatelyControlledDomains(dataTypes, fetchOptions, topPrivatelyControlledDomains, [dataTypes, completionHandler = WTFMove(completionHandler), this, protectedThis = makeRef(*this)](Vector<WebsiteDataRecord>&& websiteDataRecords, HashSet<String>&& domainsWithDataRecords) mutable {
1110 this->removeData(dataTypes, websiteDataRecords, [domainsWithDataRecords = WTFMove(domainsWithDataRecords), completionHandler = WTFMove(completionHandler)]() mutable {
1111 completionHandler(WTFMove(domainsWithDataRecords));
1116 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1117 void WebsiteDataStore::updatePrevalentDomainsWithAndWithoutInteraction(const Vector<String>& domainsWithInteraction, const Vector<String>& domainsWithoutInteraction, ShouldClearFirst shouldClearFirst)
1119 for (auto& processPool : processPools())
1120 processPool->sendToNetworkingProcess(Messages::NetworkProcess::UpdatePrevalentDomainsWithAndWithoutInteraction(m_sessionID, domainsWithInteraction, domainsWithoutInteraction, shouldClearFirst == ShouldClearFirst::Yes));
1123 void WebsiteDataStore::removePrevalentDomains(const Vector<String>& domains)
1125 for (auto& processPool : processPools())
1126 processPool->sendToNetworkingProcess(Messages::NetworkProcess::RemovePrevalentDomains(m_sessionID, domains));
1130 void WebsiteDataStore::networkProcessDidCrash()
1132 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1133 if (m_resourceLoadStatistics)
1134 m_resourceLoadStatistics->scheduleCookiePartitioningStateReset();
1138 void WebsiteDataStore::webPageWasAdded(WebPageProxy& webPageProxy)
1140 if (m_storageManager)
1141 m_storageManager->createSessionStorageNamespace(webPageProxy.pageID(), std::numeric_limits<unsigned>::max());
1144 void WebsiteDataStore::webPageWasRemoved(WebPageProxy& webPageProxy)
1146 if (m_storageManager)
1147 m_storageManager->destroySessionStorageNamespace(webPageProxy.pageID());
1150 void WebsiteDataStore::webProcessWillOpenConnection(WebProcessProxy& webProcessProxy, IPC::Connection& connection)
1152 if (m_storageManager)
1153 m_storageManager->processWillOpenConnection(webProcessProxy, connection);
1155 if (m_resourceLoadStatistics)
1156 m_resourceLoadStatistics->processWillOpenConnection(webProcessProxy, connection);
1159 void WebsiteDataStore::webPageWillOpenConnection(WebPageProxy& webPageProxy, IPC::Connection& connection)
1161 if (m_storageManager)
1162 m_storageManager->setAllowedSessionStorageNamespaceConnection(webPageProxy.pageID(), &connection);
1165 void WebsiteDataStore::webPageDidCloseConnection(WebPageProxy& webPageProxy, IPC::Connection&)
1167 if (m_storageManager)
1168 m_storageManager->setAllowedSessionStorageNamespaceConnection(webPageProxy.pageID(), nullptr);
1171 void WebsiteDataStore::webProcessDidCloseConnection(WebProcessProxy& webProcessProxy, IPC::Connection& connection)
1173 if (m_resourceLoadStatistics)
1174 m_resourceLoadStatistics->processDidCloseConnection(webProcessProxy, connection);
1176 if (m_storageManager)
1177 m_storageManager->processDidCloseConnection(webProcessProxy, connection);
1180 bool WebsiteDataStore::isAssociatedProcessPool(WebProcessPool& processPool) const
1182 return &processPool.websiteDataStore().websiteDataStore() == this;
1185 HashSet<RefPtr<WebProcessPool>> WebsiteDataStore::processPools(size_t count, bool ensureAPoolExists) const
1187 HashSet<RefPtr<WebProcessPool>> processPools;
1188 for (auto& process : processes())
1189 processPools.add(&process->processPool());
1191 if (processPools.isEmpty()) {
1192 // Check if we're one of the legacy data stores.
1193 for (auto& processPool : WebProcessPool::allProcessPools()) {
1194 if (!isAssociatedProcessPool(*processPool))
1197 processPools.add(processPool);
1199 if (processPools.size() == count)
1204 if (processPools.isEmpty() && count && ensureAPoolExists) {
1205 auto processPool = WebProcessPool::create(API::ProcessPoolConfiguration::createWithWebsiteDataStoreConfiguration(m_configuration));
1206 processPools.add(processPool.ptr());
1209 return processPools;
1212 #if ENABLE(NETSCAPE_PLUGIN_API)
1213 Vector<PluginModuleInfo> WebsiteDataStore::plugins() const
1215 Vector<PluginModuleInfo> plugins;
1217 for (auto& processPool : processPools()) {
1218 for (auto& plugin : processPool->pluginInfoStore().plugins())
1219 plugins.append(plugin);
1226 static String computeMediaKeyFile(const String& mediaKeyDirectory)
1228 return WebCore::pathByAppendingComponent(mediaKeyDirectory, "SecureStop.plist");
1231 Vector<WebCore::SecurityOriginData> WebsiteDataStore::mediaKeyOrigins(const String& mediaKeysStorageDirectory)
1233 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1235 Vector<WebCore::SecurityOriginData> origins;
1237 for (const auto& originPath : WebCore::listDirectory(mediaKeysStorageDirectory, "*")) {
1238 auto mediaKeyFile = computeMediaKeyFile(originPath);
1239 if (!WebCore::fileExists(mediaKeyFile))
1242 auto mediaKeyIdentifier = WebCore::pathGetFileName(originPath);
1244 if (auto securityOrigin = WebCore::SecurityOriginData::fromDatabaseIdentifier(mediaKeyIdentifier))
1245 origins.append(*securityOrigin);
1251 void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, std::chrono::system_clock::time_point modifiedSince)
1253 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1255 for (const auto& mediaKeyDirectory : WebCore::listDirectory(mediaKeysStorageDirectory, "*")) {
1256 auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1258 time_t modificationTime;
1259 if (!WebCore::getFileModificationTime(mediaKeyFile, modificationTime))
1262 if (std::chrono::system_clock::from_time_t(modificationTime) < modifiedSince)
1265 WebCore::deleteFile(mediaKeyFile);
1266 WebCore::deleteEmptyDirectory(mediaKeyDirectory);
1270 void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, const HashSet<WebCore::SecurityOriginData>& origins)
1272 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1274 for (const auto& origin : origins) {
1275 auto mediaKeyDirectory = WebCore::pathByAppendingComponent(mediaKeysStorageDirectory, origin.databaseIdentifier());
1276 auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1278 WebCore::deleteFile(mediaKeyFile);
1279 WebCore::deleteEmptyDirectory(mediaKeyDirectory);
1283 bool WebsiteDataStore::resourceLoadStatisticsEnabled() const
1285 return !!m_resourceLoadStatistics;
1288 void WebsiteDataStore::setResourceLoadStatisticsEnabled(bool enabled)
1290 if (enabled == resourceLoadStatisticsEnabled())
1294 ASSERT(!m_resourceLoadStatistics);
1295 enableResourceLoadStatisticsAndSetTestingCallback(nullptr);
1299 m_resourceLoadStatistics = nullptr;
1300 for (auto& processPool : processPools())
1301 processPool->setResourceLoadStatisticsEnabled(false);
1304 void WebsiteDataStore::enableResourceLoadStatisticsAndSetTestingCallback(Function<void (const String&)>&& callback)
1306 if (m_resourceLoadStatistics) {
1307 m_resourceLoadStatistics->setStatisticsTestingCallback(WTFMove(callback));
1311 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1312 m_resourceLoadStatistics = WebResourceLoadStatisticsStore::create(m_configuration.resourceLoadStatisticsDirectory, WTFMove(callback), [this] (const Vector<String>& domainsWithInteraction, const Vector<String>& domainsWithoutInteraction, ShouldClearFirst shouldClearFirst) {
1313 updatePrevalentDomainsWithAndWithoutInteraction(domainsWithInteraction, domainsWithoutInteraction, shouldClearFirst);
1314 }, [this] (const Vector<String>& domainsToRemove) {
1315 removePrevalentDomains(domainsToRemove);
1318 m_resourceLoadStatistics = WebResourceLoadStatisticsStore::create(m_configuration.resourceLoadStatisticsDirectory, WTFMove(callback));
1321 for (auto& processPool : processPools())
1322 processPool->setResourceLoadStatisticsEnabled(true);
1325 void WebsiteDataStore::clearResourceLoadStatisticsInWebProcesses()
1327 if (!resourceLoadStatisticsEnabled())
1330 for (auto& processPool : processPools())
1331 processPool->clearResourceLoadStatistics();
1334 StorageProcessCreationParameters WebsiteDataStore::storageProcessParameters()
1336 resolveDirectoriesIfNecessary();
1338 StorageProcessCreationParameters parameters;
1340 parameters.sessionID = m_sessionID;
1342 #if ENABLE(INDEXED_DATABASE)
1343 parameters.indexedDatabaseDirectory = resolvedIndexedDatabaseDirectory();
1344 if (!parameters.indexedDatabaseDirectory.isEmpty())
1345 SandboxExtension::createHandleForReadWriteDirectory(parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
1351 Vector<WebCore::Cookie> WebsiteDataStore::pendingCookies() const
1353 Vector<WebCore::Cookie> cookies;
1354 copyToVector(m_pendingCookies, cookies);
1358 void WebsiteDataStore::addPendingCookie(const WebCore::Cookie& cookie)
1360 m_pendingCookies.add(cookie);
1363 void WebsiteDataStore::removePendingCookie(const WebCore::Cookie& cookie)
1365 m_pendingCookies.remove(cookie);
1368 #if !PLATFORM(COCOA)
1369 WebsiteDataStoreParameters WebsiteDataStore::parameters()
1371 // FIXME: Implement cookies.
1372 WebsiteDataStoreParameters parameters;
1373 parameters.sessionID = m_sessionID;