0f9e9ac044739d935a528281e754a86da26a8605
[WebKit-https.git] / Source / WebKit / UIProcess / WebsiteData / WebsiteDataStore.cpp
1 /*
2  * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "WebsiteDataStore.h"
28
29 #include "APIProcessPoolConfiguration.h"
30 #include "APIWebsiteDataRecord.h"
31 #include "APIWebsiteDataStore.h"
32 #include "NetworkProcessMessages.h"
33 #include "StorageManager.h"
34 #include "StorageProcessCreationParameters.h"
35 #include "WebCookieManagerProxy.h"
36 #include "WebProcessMessages.h"
37 #include "WebProcessPool.h"
38 #include "WebResourceLoadStatisticsStore.h"
39 #include "WebResourceLoadStatisticsStoreMessages.h"
40 #include "WebsiteData.h"
41 #include "WebsiteDataStoreParameters.h"
42 #include <WebCore/ApplicationCacheStorage.h>
43 #include <WebCore/DatabaseTracker.h>
44 #include <WebCore/FileSystem.h>
45 #include <WebCore/HTMLMediaElement.h>
46 #include <WebCore/OriginLock.h>
47 #include <WebCore/SecurityOrigin.h>
48 #include <WebCore/SecurityOriginData.h>
49 #include <wtf/CompletionHandler.h>
50 #include <wtf/CrossThreadCopier.h>
51 #include <wtf/RunLoop.h>
52
53 #if ENABLE(NETSCAPE_PLUGIN_API)
54 #include "PluginProcessManager.h"
55 #endif
56
57 namespace WebKit {
58
59 static bool allowsWebsiteDataRecordsForAllOrigins;
60 void WebsiteDataStore::allowWebsiteDataRecordsForAllOrigins()
61 {
62     allowsWebsiteDataRecordsForAllOrigins = true;
63 }
64
65 static HashMap<PAL::SessionID, WebsiteDataStore*>& nonDefaultDataStores()
66 {
67     RELEASE_ASSERT(isUIThread());
68     static NeverDestroyed<HashMap<PAL::SessionID, WebsiteDataStore*>> map;
69     return map;
70 }
71
72 Ref<WebsiteDataStore> WebsiteDataStore::createNonPersistent()
73 {
74     return adoptRef(*new WebsiteDataStore(PAL::SessionID::generateEphemeralSessionID()));
75 }
76
77 Ref<WebsiteDataStore> WebsiteDataStore::create(Configuration configuration, PAL::SessionID sessionID)
78 {
79     return adoptRef(*new WebsiteDataStore(WTFMove(configuration), sessionID));
80 }
81
82 WebsiteDataStore::Configuration::Configuration()
83     : resourceLoadStatisticsDirectory(API::WebsiteDataStore::defaultResourceLoadStatisticsDirectory())
84 {
85 }
86
87 WebsiteDataStore::WebsiteDataStore(Configuration configuration, PAL::SessionID sessionID)
88     : m_sessionID(sessionID)
89     , m_configuration(WTFMove(configuration))
90     , m_storageManager(StorageManager::create(m_configuration.localStorageDirectory))
91     , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
92 {
93     maybeRegisterWithSessionIDMap();
94     platformInitialize();
95 }
96
97 WebsiteDataStore::WebsiteDataStore(PAL::SessionID sessionID)
98     : m_sessionID(sessionID)
99     , m_configuration()
100     , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
101 {
102     maybeRegisterWithSessionIDMap();
103     platformInitialize();
104 }
105
106 WebsiteDataStore::~WebsiteDataStore()
107 {
108     platformDestroy();
109
110     if (m_sessionID.isValid() && m_sessionID != PAL::SessionID::defaultSessionID()) {
111         ASSERT(nonDefaultDataStores().get(m_sessionID) == this);
112         nonDefaultDataStores().remove(m_sessionID);
113         for (auto& processPool : WebProcessPool::allProcessPools())
114             processPool->sendToNetworkingProcess(Messages::NetworkProcess::DestroySession(m_sessionID));
115     }
116 }
117
118 void WebsiteDataStore::maybeRegisterWithSessionIDMap()
119 {
120     if (m_sessionID.isValid() && m_sessionID != PAL::SessionID::defaultSessionID()) {
121         auto result = nonDefaultDataStores().add(m_sessionID, this);
122         ASSERT_UNUSED(result, result.isNewEntry);
123     }
124 }
125
126 WebsiteDataStore* WebsiteDataStore::existingNonDefaultDataStoreForSessionID(PAL::SessionID sessionID)
127 {
128     return sessionID.isValid() && sessionID != PAL::SessionID::defaultSessionID() ? nonDefaultDataStores().get(sessionID) : nullptr;
129 }
130
131 WebProcessPool* WebsiteDataStore::processPoolForCookieStorageOperations()
132 {
133     auto pools = processPools(1, false);
134     return pools.isEmpty() ? nullptr : pools.begin()->get();
135 }
136
137 void WebsiteDataStore::resolveDirectoriesIfNecessary()
138 {
139     if (m_hasResolvedDirectories)
140         return;
141     m_hasResolvedDirectories = true;
142
143     // Resolve directory paths.
144     if (!m_configuration.applicationCacheDirectory.isEmpty())
145         m_resolvedConfiguration.applicationCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.applicationCacheDirectory);
146     if (!m_configuration.mediaCacheDirectory.isEmpty())
147         m_resolvedConfiguration.mediaCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.mediaCacheDirectory);
148     if (!m_configuration.mediaKeysStorageDirectory.isEmpty())
149         m_resolvedConfiguration.mediaKeysStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.mediaKeysStorageDirectory);
150     if (!m_configuration.webSQLDatabaseDirectory.isEmpty())
151         m_resolvedConfiguration.webSQLDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.webSQLDatabaseDirectory);
152     if (!m_configuration.indexedDBDatabaseDirectory.isEmpty())
153         m_resolvedConfiguration.indexedDBDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.indexedDBDatabaseDirectory);
154     if (!m_configuration.serviceWorkerRegistrationDirectory.isEmpty() && m_resolvedConfiguration.serviceWorkerRegistrationDirectory.isEmpty())
155         m_resolvedConfiguration.serviceWorkerRegistrationDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration.serviceWorkerRegistrationDirectory);
156     if (!m_configuration.javaScriptConfigurationDirectory.isEmpty())
157         m_resolvedConfiguration.javaScriptConfigurationDirectory = resolvePathForSandboxExtension(m_configuration.javaScriptConfigurationDirectory);
158     if (!m_configuration.cacheStorageDirectory.isEmpty() && m_resolvedConfiguration.cacheStorageDirectory.isEmpty())
159         m_resolvedConfiguration.cacheStorageDirectory = resolvePathForSandboxExtension(m_configuration.cacheStorageDirectory);
160
161     // Resolve directories for file paths.
162     if (!m_configuration.cookieStorageFile.isEmpty()) {
163         m_resolvedConfiguration.cookieStorageFile = resolveAndCreateReadWriteDirectoryForSandboxExtension(WebCore::FileSystem::directoryName(m_configuration.cookieStorageFile));
164         m_resolvedConfiguration.cookieStorageFile = WebCore::FileSystem::pathByAppendingComponent(m_resolvedConfiguration.cookieStorageFile, WebCore::FileSystem::pathGetFileName(m_configuration.cookieStorageFile));
165     }
166 }
167
168 void WebsiteDataStore::cloneSessionData(WebPageProxy& sourcePage, WebPageProxy& newPage)
169 {
170     auto& sourceDataStore = sourcePage.websiteDataStore();
171     auto& newDataStore = newPage.websiteDataStore();
172
173     // FIXME: Handle this.
174     if (&sourceDataStore != &newDataStore)
175         return;
176
177     if (!sourceDataStore.m_storageManager)
178         return;
179
180     sourceDataStore.m_storageManager->cloneSessionStorageNamespace(sourcePage.pageID(), newPage.pageID());
181 }
182
183 enum class ProcessAccessType {
184     None,
185     OnlyIfLaunched,
186     Launch,
187 };
188
189 static ProcessAccessType computeNetworkProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
190 {
191     ProcessAccessType processAccessType = ProcessAccessType::None;
192
193     if (dataTypes.contains(WebsiteDataType::Cookies)) {
194         if (isNonPersistentStore)
195             processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
196         else
197             processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
198     }
199
200     if (dataTypes.contains(WebsiteDataType::DiskCache) && !isNonPersistentStore)
201         processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
202
203     if (dataTypes.contains(WebsiteDataType::DOMCache))
204         processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
205
206     return processAccessType;
207 }
208
209 static ProcessAccessType computeWebProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
210 {
211     UNUSED_PARAM(isNonPersistentStore);
212
213     ProcessAccessType processAccessType = ProcessAccessType::None;
214
215     if (dataTypes.contains(WebsiteDataType::MemoryCache))
216         return ProcessAccessType::OnlyIfLaunched;
217
218     return processAccessType;
219 }
220
221 void WebsiteDataStore::fetchData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void(Vector<WebsiteDataRecord>)>&& completionHandler)
222 {
223     fetchDataAndApply(dataTypes, fetchOptions, nullptr, WTFMove(completionHandler));
224 }
225
226 void WebsiteDataStore::fetchDataAndApply(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply)
227 {
228     struct CallbackAggregator final : ThreadSafeRefCounted<CallbackAggregator> {
229         explicit CallbackAggregator(OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply)
230             : fetchOptions(fetchOptions)
231             , queue(WTFMove(queue))
232             , apply(WTFMove(apply))
233         {
234         }
235
236         ~CallbackAggregator()
237         {
238             ASSERT(!pendingCallbacks);
239         }
240
241         void addPendingCallback()
242         {
243             pendingCallbacks++;
244         }
245
246         void removePendingCallback(WebsiteData websiteData)
247         {
248             ASSERT(pendingCallbacks);
249             --pendingCallbacks;
250
251             for (auto& entry : websiteData.entries) {
252                 auto displayName = WebsiteDataRecord::displayNameForOrigin(entry.origin);
253                 if (!displayName) {
254                     if (!allowsWebsiteDataRecordsForAllOrigins)
255                         continue;
256
257                     displayName = makeString(entry.origin.protocol, " ", entry.origin.host);
258                 }
259
260                 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
261                 if (!record.displayName)
262                     record.displayName = WTFMove(displayName);
263
264                 record.add(entry.type, entry.origin);
265
266                 if (fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes)) {
267                     if (!record.size)
268                         record.size = WebsiteDataRecord::Size { 0, { } };
269
270                     record.size->totalSize += entry.size;
271                     record.size->typeSizes.add(static_cast<unsigned>(entry.type), 0).iterator->value += entry.size;
272                 }
273             }
274
275             for (auto& hostName : websiteData.hostNamesWithCookies) {
276                 auto displayName = WebsiteDataRecord::displayNameForCookieHostName(hostName);
277                 if (!displayName)
278                     continue;
279
280                 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
281                 if (!record.displayName)
282                     record.displayName = WTFMove(displayName);
283
284                 record.addCookieHostName(hostName);
285             }
286
287 #if ENABLE(NETSCAPE_PLUGIN_API)
288             for (auto& hostName : websiteData.hostNamesWithPluginData) {
289                 auto displayName = WebsiteDataRecord::displayNameForPluginDataHostName(hostName);
290                 if (!displayName)
291                     continue;
292
293                 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
294                 if (!record.displayName)
295                     record.displayName = WTFMove(displayName);
296
297                 record.addPluginDataHostName(hostName);
298             }
299 #endif
300
301             for (auto& origin : websiteData.originsWithCredentials) {
302                 auto& record = m_websiteDataRecords.add(origin, WebsiteDataRecord { }).iterator->value;
303                 
304                 record.addOriginWithCredential(origin);
305             }
306
307             callIfNeeded();
308         }
309
310         void callIfNeeded()
311         {
312             if (pendingCallbacks)
313                 return;
314
315             Vector<WebsiteDataRecord> records;
316             records.reserveInitialCapacity(m_websiteDataRecords.size());
317             for (auto& record : m_websiteDataRecords.values())
318                 records.uncheckedAppend(WTFMove(record));
319
320             auto processRecords = [apply = WTFMove(apply), records = WTFMove(records)] () mutable {
321                 apply(WTFMove(records));
322             };
323
324             if (queue)
325                 queue->dispatch(WTFMove(processRecords));
326             else
327                 RunLoop::main().dispatch(WTFMove(processRecords));
328         }
329
330         const OptionSet<WebsiteDataFetchOption> fetchOptions;
331
332         unsigned pendingCallbacks = 0;
333         RefPtr<WorkQueue> queue;
334         Function<void(Vector<WebsiteDataRecord>)> apply;
335
336         HashMap<String, WebsiteDataRecord> m_websiteDataRecords;
337     };
338
339     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(fetchOptions, WTFMove(queue), WTFMove(apply)));
340
341 #if ENABLE(VIDEO)
342     if (dataTypes.contains(WebsiteDataType::DiskCache)) {
343         callbackAggregator->addPendingCallback();
344         m_queue->dispatch([mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
345             // FIXME: Make HTMLMediaElement::originsInMediaCache return a collection of SecurityOriginDatas.
346             HashSet<RefPtr<WebCore::SecurityOrigin>> origins = WebCore::HTMLMediaElement::originsInMediaCache(mediaCacheDirectory);
347             WebsiteData websiteData;
348             
349             for (auto& origin : origins) {
350                 WebsiteData::Entry entry { origin->data(), WebsiteDataType::DiskCache, 0 };
351                 websiteData.entries.append(WTFMove(entry));
352             }
353             
354             RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
355                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
356             });
357         });
358     }
359 #endif
360
361     auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
362     if (networkProcessAccessType != ProcessAccessType::None) {
363         for (auto& processPool : processPools()) {
364             switch (networkProcessAccessType) {
365             case ProcessAccessType::OnlyIfLaunched:
366                 if (!processPool->networkProcess())
367                     continue;
368                 break;
369
370             case ProcessAccessType::Launch:
371                 processPool->ensureNetworkProcess(this);
372                 break;
373
374             case ProcessAccessType::None:
375                 ASSERT_NOT_REACHED();
376             }
377
378             callbackAggregator->addPendingCallback();
379             processPool->networkProcess()->fetchWebsiteData(m_sessionID, dataTypes, fetchOptions, [callbackAggregator, processPool](WebsiteData websiteData) {
380                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
381             });
382         }
383     }
384
385     auto webProcessAccessType = computeWebProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
386     if (webProcessAccessType != ProcessAccessType::None) {
387         for (auto& process : processes()) {
388             switch (webProcessAccessType) {
389             case ProcessAccessType::OnlyIfLaunched:
390                 if (!process->canSendMessage())
391                     continue;
392                 break;
393
394             case ProcessAccessType::Launch:
395                 // FIXME: Handle this.
396                 ASSERT_NOT_REACHED();
397                 break;
398
399             case ProcessAccessType::None:
400                 ASSERT_NOT_REACHED();
401             }
402
403             callbackAggregator->addPendingCallback();
404             process->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator](WebsiteData websiteData) {
405                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
406             });
407         }
408     }
409
410     if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
411         callbackAggregator->addPendingCallback();
412
413         m_storageManager->getSessionStorageOrigins([callbackAggregator](HashSet<WebCore::SecurityOriginData>&& origins) {
414             WebsiteData websiteData;
415
416             while (!origins.isEmpty())
417                 websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::SessionStorage, 0 });
418
419             callbackAggregator->removePendingCallback(WTFMove(websiteData));
420         });
421     }
422
423     if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
424         callbackAggregator->addPendingCallback();
425
426         m_storageManager->getLocalStorageOrigins([callbackAggregator](HashSet<WebCore::SecurityOriginData>&& origins) {
427             WebsiteData websiteData;
428
429             while (!origins.isEmpty())
430                 websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::LocalStorage, 0 });
431
432             callbackAggregator->removePendingCallback(WTFMove(websiteData));
433         });
434     }
435
436     if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
437         callbackAggregator->addPendingCallback();
438
439         m_queue->dispatch([fetchOptions, applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
440             auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
441
442             WebsiteData websiteData;
443
444             HashSet<RefPtr<WebCore::SecurityOrigin>> origins;
445             // FIXME: getOriginsWithCache should return a collection of SecurityOriginDatas.
446             storage->getOriginsWithCache(origins);
447
448             for (auto& origin : origins) {
449                 uint64_t size = fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes) ? storage->diskUsageForOrigin(*origin) : 0;
450                 WebsiteData::Entry entry { origin->data(), WebsiteDataType::OfflineWebApplicationCache, size };
451
452                 websiteData.entries.append(WTFMove(entry));
453             }
454
455             RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
456                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
457             });
458         });
459     }
460
461     if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
462         callbackAggregator->addPendingCallback();
463
464         m_queue->dispatch([webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy(), callbackAggregator] {
465             auto origins = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->origins();
466             RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
467                 WebsiteData websiteData;
468                 for (auto& origin : origins)
469                     websiteData.entries.append(WebsiteData::Entry { WTFMove(origin), WebsiteDataType::WebSQLDatabases, 0 });
470                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
471             });
472         });
473     }
474
475     if ((dataTypes.contains(WebsiteDataType::IndexedDBDatabases)
476 #if ENABLE(SERVICE_WORKER)
477         || dataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)
478 #endif
479         ) && isPersistent()) {
480         for (auto& processPool : processPools()) {
481             processPool->ensureStorageProcessAndWebsiteDataStore(this);
482
483             callbackAggregator->addPendingCallback();
484             processPool->storageProcess()->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator, processPool](WebsiteData websiteData) {
485                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
486             });
487         }
488     }
489
490     if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
491         callbackAggregator->addPendingCallback();
492
493         m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator] {
494             auto origins = mediaKeyOrigins(mediaKeysStorageDirectory);
495
496             RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
497                 WebsiteData websiteData;
498                 for (auto& origin : origins)
499                     websiteData.entries.append(WebsiteData::Entry { origin, WebsiteDataType::MediaKeys, 0 });
500
501                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
502             });
503         });
504     }
505
506 #if ENABLE(NETSCAPE_PLUGIN_API)
507     if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
508         class State {
509         public:
510             static void fetchData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
511             {
512                 new State(WTFMove(callbackAggregator), WTFMove(plugins));
513             }
514
515         private:
516             State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
517                 : m_callbackAggregator(WTFMove(callbackAggregator))
518                 , m_plugins(WTFMove(plugins))
519             {
520                 m_callbackAggregator->addPendingCallback();
521
522                 fetchWebsiteDataForNextPlugin();
523             }
524
525             ~State()
526             {
527                 ASSERT(m_plugins.isEmpty());
528             }
529
530             void fetchWebsiteDataForNextPlugin()
531             {
532                 if (m_plugins.isEmpty()) {
533                     WebsiteData websiteData;
534                     websiteData.hostNamesWithPluginData = WTFMove(m_hostNames);
535
536                     m_callbackAggregator->removePendingCallback(WTFMove(websiteData));
537
538                     delete this;
539                     return;
540                 }
541
542                 auto plugin = m_plugins.takeLast();
543                 PluginProcessManager::singleton().fetchWebsiteData(plugin, m_callbackAggregator->fetchOptions, [this](Vector<String> hostNames) {
544                     for (auto& hostName : hostNames)
545                         m_hostNames.add(WTFMove(hostName));
546                     fetchWebsiteDataForNextPlugin();
547                 });
548             }
549
550             Ref<CallbackAggregator> m_callbackAggregator;
551             Vector<PluginModuleInfo> m_plugins;
552             HashSet<String> m_hostNames;
553         };
554
555         State::fetchData(*callbackAggregator, plugins());
556     }
557 #endif
558
559     callbackAggregator->callIfNeeded();
560 }
561
562 void WebsiteDataStore::fetchDataForTopPrivatelyControlledDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<String>& topPrivatelyControlledDomains, Function<void(Vector<WebsiteDataRecord>&&, HashSet<String>&&)>&& completionHandler)
563 {
564     fetchDataAndApply(dataTypes, fetchOptions, m_queue.copyRef(), [topPrivatelyControlledDomains = crossThreadCopy(topPrivatelyControlledDomains), completionHandler = WTFMove(completionHandler)] (auto&& existingDataRecords) mutable {
565         ASSERT(!RunLoop::isMain());
566
567         Vector<WebsiteDataRecord> matchingDataRecords;
568         HashSet<String> domainsWithMatchingDataRecords;
569         for (auto&& dataRecord : existingDataRecords) {
570             for (auto& topPrivatelyControlledDomain : topPrivatelyControlledDomains) {
571                 if (dataRecord.matchesTopPrivatelyControlledDomain(topPrivatelyControlledDomain)) {
572                     matchingDataRecords.append(WTFMove(dataRecord));
573                     domainsWithMatchingDataRecords.add(topPrivatelyControlledDomain.isolatedCopy());
574                     break;
575                 }
576             }
577         }
578         RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), matchingDataRecords = WTFMove(matchingDataRecords), domainsWithMatchingDataRecords = WTFMove(domainsWithMatchingDataRecords)] () mutable {
579             completionHandler(WTFMove(matchingDataRecords), WTFMove(domainsWithMatchingDataRecords));
580         });
581     });
582 }
583     
584 void WebsiteDataStore::topPrivatelyControlledDomainsWithWebsiteData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void(HashSet<String>&&)>&& completionHandler)
585 {
586     fetchData(dataTypes, fetchOptions, [completionHandler = WTFMove(completionHandler), protectedThis = makeRef(*this)](auto&& existingDataRecords) {
587         HashSet<String> domainsWithDataRecords;
588         for (auto&& dataRecord : existingDataRecords) {
589             String domain = dataRecord.topPrivatelyControlledDomain();
590             if (domain.isEmpty())
591                 continue;
592             domainsWithDataRecords.add(WTFMove(domain));
593         }
594         completionHandler(WTFMove(domainsWithDataRecords));
595     });
596 }
597
598 static ProcessAccessType computeNetworkProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
599 {
600     ProcessAccessType processAccessType = ProcessAccessType::None;
601
602     if (dataTypes.contains(WebsiteDataType::Cookies)) {
603         if (isNonPersistentStore)
604             processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
605         else
606             processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
607     }
608
609     if (dataTypes.contains(WebsiteDataType::DiskCache) && !isNonPersistentStore)
610         processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
611
612     if (dataTypes.contains(WebsiteDataType::HSTSCache))
613         processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
614
615     if (dataTypes.contains(WebsiteDataType::Credentials))
616         processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
617
618     if (dataTypes.contains(WebsiteDataType::DOMCache))
619         processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
620
621     return processAccessType;
622 }
623
624 static ProcessAccessType computeWebProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
625 {
626     UNUSED_PARAM(isNonPersistentStore);
627
628     ProcessAccessType processAccessType = ProcessAccessType::None;
629
630     if (dataTypes.contains(WebsiteDataType::MemoryCache))
631         processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
632
633     if (dataTypes.contains(WebsiteDataType::Credentials))
634         processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
635
636     return processAccessType;
637 }
638
639 void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, WallTime modifiedSince, Function<void()>&& completionHandler)
640 {
641     struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
642         explicit CallbackAggregator(Function<void()>&& completionHandler)
643             : completionHandler(WTFMove(completionHandler))
644         {
645         }
646
647         void addPendingCallback()
648         {
649             pendingCallbacks++;
650         }
651
652         void removePendingCallback()
653         {
654             ASSERT(pendingCallbacks);
655             --pendingCallbacks;
656
657             callIfNeeded();
658         }
659
660         void callIfNeeded()
661         {
662             if (!pendingCallbacks)
663                 RunLoop::main().dispatch(WTFMove(completionHandler));
664         }
665
666         unsigned pendingCallbacks = 0;
667         Function<void()> completionHandler;
668     };
669
670     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
671
672 #if ENABLE(VIDEO)
673     if (dataTypes.contains(WebsiteDataType::DiskCache)) {
674         callbackAggregator->addPendingCallback();
675         m_queue->dispatch([modifiedSince, mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
676             WebCore::HTMLMediaElement::clearMediaCache(mediaCacheDirectory, modifiedSince);
677             
678             WTF::RunLoop::main().dispatch([callbackAggregator] {
679                 callbackAggregator->removePendingCallback();
680             });
681         });
682     }
683 #endif
684
685     auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
686     if (networkProcessAccessType != ProcessAccessType::None) {
687         for (auto& processPool : processPools()) {
688             switch (networkProcessAccessType) {
689             case ProcessAccessType::OnlyIfLaunched:
690                 if (!processPool->networkProcess())
691                     continue;
692                 break;
693
694             case ProcessAccessType::Launch:
695                 processPool->ensureNetworkProcess(this);
696                 break;
697
698             case ProcessAccessType::None:
699                 ASSERT_NOT_REACHED();
700             }
701
702             callbackAggregator->addPendingCallback();
703             processPool->networkProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
704                 callbackAggregator->removePendingCallback();
705             });
706         }
707     }
708
709     auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
710     if (webProcessAccessType != ProcessAccessType::None) {
711         for (auto& process : processes()) {
712             switch (webProcessAccessType) {
713             case ProcessAccessType::OnlyIfLaunched:
714                 if (!process->canSendMessage())
715                     continue;
716                 break;
717
718             case ProcessAccessType::Launch:
719                 // FIXME: Handle this.
720                 ASSERT_NOT_REACHED();
721                 break;
722
723             case ProcessAccessType::None:
724                 ASSERT_NOT_REACHED();
725             }
726
727             callbackAggregator->addPendingCallback();
728             process->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] {
729                 callbackAggregator->removePendingCallback();
730             });
731         }
732     }
733
734     if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
735         callbackAggregator->addPendingCallback();
736
737         m_storageManager->deleteSessionStorageOrigins([callbackAggregator] {
738             callbackAggregator->removePendingCallback();
739         });
740     }
741
742     if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
743         callbackAggregator->addPendingCallback();
744
745         m_storageManager->deleteLocalStorageOriginsModifiedSince(modifiedSince, [callbackAggregator] {
746             callbackAggregator->removePendingCallback();
747         });
748     }
749
750     if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
751         callbackAggregator->addPendingCallback();
752
753         m_queue->dispatch([applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
754             auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
755
756             storage->deleteAllCaches();
757
758             WTF::RunLoop::main().dispatch([callbackAggregator] {
759                 callbackAggregator->removePendingCallback();
760             });
761         });
762     }
763
764     if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
765         callbackAggregator->addPendingCallback();
766
767         m_queue->dispatch([webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy(), callbackAggregator, modifiedSince] {
768             WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->deleteDatabasesModifiedSince(modifiedSince);
769
770             RunLoop::main().dispatch([callbackAggregator] {
771                 callbackAggregator->removePendingCallback();
772             });
773         });
774     }
775
776     if ((dataTypes.contains(WebsiteDataType::IndexedDBDatabases)
777 #if ENABLE(SERVICE_WORKER)
778         || dataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)
779 #endif
780         ) && isPersistent()) {
781         for (auto& processPool : processPools()) {
782             processPool->ensureStorageProcessAndWebsiteDataStore(this);
783
784             callbackAggregator->addPendingCallback();
785             processPool->storageProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
786                 callbackAggregator->removePendingCallback();
787             });
788         }
789     }
790
791     if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
792         callbackAggregator->addPendingCallback();
793
794         m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator, modifiedSince] {
795             removeMediaKeys(mediaKeysStorageDirectory, modifiedSince);
796
797             RunLoop::main().dispatch([callbackAggregator] {
798                 callbackAggregator->removePendingCallback();
799             });
800         });
801     }
802
803     if (dataTypes.contains(WebsiteDataType::SearchFieldRecentSearches) && isPersistent()) {
804         callbackAggregator->addPendingCallback();
805
806         m_queue->dispatch([modifiedSince, callbackAggregator] {
807             platformRemoveRecentSearches(modifiedSince);
808
809             RunLoop::main().dispatch([callbackAggregator] {
810                 callbackAggregator->removePendingCallback();
811             });
812         });
813     }
814
815 #if ENABLE(NETSCAPE_PLUGIN_API)
816     if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
817         class State {
818         public:
819             static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, WallTime modifiedSince)
820             {
821                 new State(WTFMove(callbackAggregator), WTFMove(plugins), modifiedSince);
822             }
823
824         private:
825             State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, WallTime modifiedSince)
826                 : m_callbackAggregator(WTFMove(callbackAggregator))
827                 , m_plugins(WTFMove(plugins))
828                 , m_modifiedSince(modifiedSince)
829             {
830                 m_callbackAggregator->addPendingCallback();
831
832                 deleteWebsiteDataForNextPlugin();
833             }
834
835             ~State()
836             {
837                 ASSERT(m_plugins.isEmpty());
838             }
839
840             void deleteWebsiteDataForNextPlugin()
841             {
842                 if (m_plugins.isEmpty()) {
843                     m_callbackAggregator->removePendingCallback();
844
845                     delete this;
846                     return;
847                 }
848
849                 auto plugin = m_plugins.takeLast();
850                 PluginProcessManager::singleton().deleteWebsiteData(plugin, m_modifiedSince, [this] {
851                     deleteWebsiteDataForNextPlugin();
852                 });
853             }
854
855             Ref<CallbackAggregator> m_callbackAggregator;
856             Vector<PluginModuleInfo> m_plugins;
857             WallTime m_modifiedSince;
858         };
859
860         State::deleteData(*callbackAggregator, plugins(), modifiedSince);
861     }
862 #endif
863
864     if (dataTypes.contains(WebsiteDataType::ResourceLoadStatistics) && m_resourceLoadStatistics) {
865         auto deletedTypesRaw = dataTypes.toRaw();
866         auto monitoredTypesRaw = WebResourceLoadStatisticsStore::monitoredDataTypes().toRaw();
867         
868         // If we are deleting all of the data types that the resource load statistics store monitors
869         // we do not need to re-grandfather old data.
870         callbackAggregator->addPendingCallback();
871         if ((monitoredTypesRaw & deletedTypesRaw) == monitoredTypesRaw)
872             m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince, WebResourceLoadStatisticsStore::ShouldGrandfather::No, [callbackAggregator] {
873                 callbackAggregator->removePendingCallback();
874             });
875         else
876             m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince, WebResourceLoadStatisticsStore::ShouldGrandfather::Yes, [callbackAggregator] {
877                 callbackAggregator->removePendingCallback();
878             });
879
880         callbackAggregator->addPendingCallback();
881         clearResourceLoadStatisticsInWebProcesses([callbackAggregator] {
882             callbackAggregator->removePendingCallback();
883         });
884     }
885
886     // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
887     callbackAggregator->callIfNeeded();
888 }
889
890 void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, const Vector<WebsiteDataRecord>& dataRecords, Function<void()>&& completionHandler)
891 {
892     Vector<WebCore::SecurityOriginData> origins;
893
894     for (const auto& dataRecord : dataRecords) {
895         for (auto& origin : dataRecord.origins)
896             origins.append(origin);
897     }
898
899     struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
900         explicit CallbackAggregator(Function<void()>&& completionHandler)
901             : completionHandler(WTFMove(completionHandler))
902         {
903         }
904
905         void addPendingCallback()
906         {
907             pendingCallbacks++;
908         }
909
910         void removePendingCallback()
911         {
912             ASSERT(pendingCallbacks);
913             --pendingCallbacks;
914
915             callIfNeeded();
916         }
917
918         void callIfNeeded()
919         {
920             if (!pendingCallbacks)
921                 RunLoop::main().dispatch(WTFMove(completionHandler));
922         }
923
924         unsigned pendingCallbacks = 0;
925         Function<void()> completionHandler;
926     };
927
928     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(WTFMove(completionHandler)));
929     
930     if (dataTypes.contains(WebsiteDataType::DiskCache)) {
931         HashSet<WebCore::SecurityOriginData> origins;
932         for (const auto& dataRecord : dataRecords) {
933             for (const auto& origin : dataRecord.origins)
934                 origins.add(origin);
935         }
936         
937 #if ENABLE(VIDEO)
938         callbackAggregator->addPendingCallback();
939         m_queue->dispatch([origins = WTFMove(origins), mediaCacheDirectory = m_configuration.mediaCacheDirectory.isolatedCopy(), callbackAggregator] {
940
941             // FIXME: Move SecurityOrigin::toRawString to SecurityOriginData and
942             // make HTMLMediaElement::clearMediaCacheForOrigins take SecurityOriginData.
943             HashSet<RefPtr<WebCore::SecurityOrigin>> securityOrigins;
944             for (auto& origin : origins)
945                 securityOrigins.add(origin.securityOrigin());
946             WebCore::HTMLMediaElement::clearMediaCacheForOrigins(mediaCacheDirectory, securityOrigins);
947             
948             WTF::RunLoop::main().dispatch([callbackAggregator] {
949                 callbackAggregator->removePendingCallback();
950             });
951         });
952 #endif
953     }
954     
955     auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
956     if (networkProcessAccessType != ProcessAccessType::None) {
957         for (auto& processPool : processPools()) {
958             switch (networkProcessAccessType) {
959             case ProcessAccessType::OnlyIfLaunched:
960                 if (!processPool->networkProcess())
961                     continue;
962                 break;
963
964             case ProcessAccessType::Launch:
965                 processPool->ensureNetworkProcess(this);
966                 break;
967
968             case ProcessAccessType::None:
969                 ASSERT_NOT_REACHED();
970             }
971
972             Vector<String> cookieHostNames;
973             for (const auto& dataRecord : dataRecords) {
974                 for (auto& hostName : dataRecord.cookieHostNames)
975                     cookieHostNames.append(hostName);
976             }
977
978             callbackAggregator->addPendingCallback();
979             processPool->networkProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, cookieHostNames, [callbackAggregator, processPool] {
980                 callbackAggregator->removePendingCallback();
981             });
982         }
983     }
984
985     auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
986     if (webProcessAccessType != ProcessAccessType::None) {
987         for (auto& process : processes()) {
988             switch (webProcessAccessType) {
989             case ProcessAccessType::OnlyIfLaunched:
990                 if (!process->canSendMessage())
991                     continue;
992                 break;
993
994             case ProcessAccessType::Launch:
995                 // FIXME: Handle this.
996                 ASSERT_NOT_REACHED();
997                 break;
998
999             case ProcessAccessType::None:
1000                 ASSERT_NOT_REACHED();
1001             }
1002
1003             callbackAggregator->addPendingCallback();
1004
1005             process->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator] {
1006                 callbackAggregator->removePendingCallback();
1007             });
1008         }
1009     }
1010
1011     if (dataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManager) {
1012         callbackAggregator->addPendingCallback();
1013
1014         m_storageManager->deleteSessionStorageEntriesForOrigins(origins, [callbackAggregator] {
1015             callbackAggregator->removePendingCallback();
1016         });
1017     }
1018
1019     if (dataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManager) {
1020         callbackAggregator->addPendingCallback();
1021
1022         m_storageManager->deleteLocalStorageEntriesForOrigins(origins, [callbackAggregator] {
1023             callbackAggregator->removePendingCallback();
1024         });
1025     }
1026
1027     if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
1028         HashSet<WebCore::SecurityOriginData> origins;
1029         for (const auto& dataRecord : dataRecords) {
1030             for (const auto& origin : dataRecord.origins)
1031                 origins.add(origin);
1032         }
1033
1034         callbackAggregator->addPendingCallback();
1035         m_queue->dispatch([origins = WTFMove(origins), applicationCacheDirectory = m_configuration.applicationCacheDirectory.isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration.applicationCacheFlatFileSubdirectoryName.isolatedCopy(), callbackAggregator] {
1036             auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
1037
1038             for (const auto& origin : origins)
1039                 storage->deleteCacheForOrigin(origin.securityOrigin());
1040
1041             WTF::RunLoop::main().dispatch([callbackAggregator] {
1042                 callbackAggregator->removePendingCallback();
1043             });
1044         });
1045     }
1046
1047     if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
1048         HashSet<WebCore::SecurityOriginData> origins;
1049         for (const auto& dataRecord : dataRecords) {
1050             for (const auto& origin : dataRecord.origins)
1051                 origins.add(origin);
1052         }
1053
1054         callbackAggregator->addPendingCallback();
1055         m_queue->dispatch([origins = WTFMove(origins), callbackAggregator, webSQLDatabaseDirectory = m_configuration.webSQLDatabaseDirectory.isolatedCopy()] {
1056             auto databaseTracker = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory);
1057             for (auto& origin : origins)
1058                 databaseTracker->deleteOrigin(origin);
1059             RunLoop::main().dispatch([callbackAggregator] {
1060                 callbackAggregator->removePendingCallback();
1061             });
1062         });
1063     }
1064
1065     if ((dataTypes.contains(WebsiteDataType::IndexedDBDatabases)
1066 #if ENABLE(SERVICE_WORKER)
1067         || dataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)
1068 #endif
1069         ) && isPersistent()) {
1070         for (auto& processPool : processPools()) {
1071             processPool->ensureStorageProcessAndWebsiteDataStore(this);
1072
1073             callbackAggregator->addPendingCallback();
1074             processPool->storageProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator, processPool] {
1075                 callbackAggregator->removePendingCallback();
1076             });
1077         }
1078     }
1079
1080     if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
1081         HashSet<WebCore::SecurityOriginData> origins;
1082         for (const auto& dataRecord : dataRecords) {
1083             for (const auto& origin : dataRecord.origins)
1084                 origins.add(origin);
1085         }
1086
1087         callbackAggregator->addPendingCallback();
1088         m_queue->dispatch([mediaKeysStorageDirectory = m_configuration.mediaKeysStorageDirectory.isolatedCopy(), callbackAggregator, origins = WTFMove(origins)] {
1089
1090             removeMediaKeys(mediaKeysStorageDirectory, origins);
1091
1092             RunLoop::main().dispatch([callbackAggregator] {
1093                 callbackAggregator->removePendingCallback();
1094             });
1095         });
1096     }
1097
1098 #if ENABLE(NETSCAPE_PLUGIN_API)
1099     if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
1100         Vector<String> hostNames;
1101         for (const auto& dataRecord : dataRecords) {
1102             for (const auto& hostName : dataRecord.pluginDataHostNames)
1103                 hostNames.append(hostName);
1104         }
1105
1106
1107         class State {
1108         public:
1109             static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1110             {
1111                 new State(WTFMove(callbackAggregator), WTFMove(plugins), WTFMove(hostNames));
1112             }
1113
1114         private:
1115             State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1116                 : m_callbackAggregator(WTFMove(callbackAggregator))
1117                 , m_plugins(WTFMove(plugins))
1118                 , m_hostNames(WTFMove(hostNames))
1119             {
1120                 m_callbackAggregator->addPendingCallback();
1121
1122                 deleteWebsiteDataForNextPlugin();
1123             }
1124
1125             ~State()
1126             {
1127                 ASSERT(m_plugins.isEmpty());
1128             }
1129
1130             void deleteWebsiteDataForNextPlugin()
1131             {
1132                 if (m_plugins.isEmpty()) {
1133                     m_callbackAggregator->removePendingCallback();
1134
1135                     delete this;
1136                     return;
1137                 }
1138
1139                 auto plugin = m_plugins.takeLast();
1140                 PluginProcessManager::singleton().deleteWebsiteDataForHostNames(plugin, m_hostNames, [this] {
1141                     deleteWebsiteDataForNextPlugin();
1142                 });
1143             }
1144
1145             Ref<CallbackAggregator> m_callbackAggregator;
1146             Vector<PluginModuleInfo> m_plugins;
1147             Vector<String> m_hostNames;
1148         };
1149
1150         if (!hostNames.isEmpty())
1151             State::deleteData(*callbackAggregator, plugins(), WTFMove(hostNames));
1152     }
1153 #endif
1154
1155     // FIXME <rdar://problem/33491222>; scheduleClearInMemoryAndPersistent does not have a completion handler,
1156     // so the completion handler for this removeData() call can be called prematurely.
1157     if (dataTypes.contains(WebsiteDataType::ResourceLoadStatistics) && m_resourceLoadStatistics) {
1158         auto deletedTypesRaw = dataTypes.toRaw();
1159         auto monitoredTypesRaw = WebResourceLoadStatisticsStore::monitoredDataTypes().toRaw();
1160
1161         // If we are deleting all of the data types that the resource load statistics store monitors
1162         // we do not need to re-grandfather old data.
1163         callbackAggregator->addPendingCallback();
1164         if ((monitoredTypesRaw & deletedTypesRaw) == monitoredTypesRaw)
1165             m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(WebResourceLoadStatisticsStore::ShouldGrandfather::No, [callbackAggregator] {
1166                 callbackAggregator->removePendingCallback();
1167             });
1168         else
1169             m_resourceLoadStatistics->scheduleClearInMemoryAndPersistent(WebResourceLoadStatisticsStore::ShouldGrandfather::Yes, [callbackAggregator] {
1170                 callbackAggregator->removePendingCallback();
1171             });
1172
1173         callbackAggregator->addPendingCallback();
1174         clearResourceLoadStatisticsInWebProcesses([callbackAggregator] {
1175             callbackAggregator->removePendingCallback();
1176         });
1177     }
1178
1179     // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
1180     callbackAggregator->callIfNeeded();
1181 }
1182
1183 void WebsiteDataStore::removeDataForTopPrivatelyControlledDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<String>& topPrivatelyControlledDomains, Function<void(HashSet<String>&&)>&& completionHandler)
1184 {
1185     fetchDataForTopPrivatelyControlledDomains(dataTypes, fetchOptions, topPrivatelyControlledDomains, [dataTypes, completionHandler = WTFMove(completionHandler), this, protectedThis = makeRef(*this)](Vector<WebsiteDataRecord>&& websiteDataRecords, HashSet<String>&& domainsWithDataRecords) mutable {
1186         this->removeData(dataTypes, websiteDataRecords, [domainsWithDataRecords = WTFMove(domainsWithDataRecords), completionHandler = WTFMove(completionHandler)]() mutable {
1187             completionHandler(WTFMove(domainsWithDataRecords));
1188         });
1189     });
1190 }
1191
1192 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1193 void WebsiteDataStore::updatePrevalentDomainsToPartitionOrBlockCookies(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst shouldClearFirst)
1194 {
1195     for (auto& processPool : processPools())
1196         processPool->sendToNetworkingProcess(Messages::NetworkProcess::UpdatePrevalentDomainsToPartitionOrBlockCookies(m_sessionID, domainsToPartition, domainsToBlock, domainsToNeitherPartitionNorBlock, shouldClearFirst == ShouldClearFirst::Yes));
1197 }
1198
1199 void WebsiteDataStore::hasStorageAccessForFrameHandler(const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void(bool hasAccess)>&& callback)
1200 {
1201     for (auto& processPool : processPools())
1202         processPool->networkProcess()->hasStorageAccessForFrame(m_sessionID, resourceDomain, firstPartyDomain, frameID, pageID, WTFMove(callback));
1203 }
1204
1205 void WebsiteDataStore::getAllStorageAccessEntries(CompletionHandler<void(Vector<String>&& domains)>&& callback)
1206 {
1207     for (auto& processPool : processPools())
1208         processPool->networkProcess()->getAllStorageAccessEntries(m_sessionID, WTFMove(callback));
1209 }
1210
1211 void WebsiteDataStore::grantStorageAccessHandler(const String& resourceDomain, const String& firstPartyDomain, std::optional<uint64_t> frameID, uint64_t pageID, WTF::CompletionHandler<void(bool wasGranted)>&& callback)
1212 {
1213     for (auto& processPool : processPools())
1214         processPool->networkProcess()->grantStorageAccess(m_sessionID, resourceDomain, firstPartyDomain, frameID, pageID, WTFMove(callback));
1215 }
1216
1217 void WebsiteDataStore::removeAllStorageAccessHandler()
1218 {
1219     for (auto& processPool : processPools()) {
1220         if (auto networkProcess = processPool->networkProcess())
1221             networkProcess->removeAllStorageAccess(m_sessionID);
1222     }
1223 }
1224
1225 void WebsiteDataStore::removePrevalentDomains(const Vector<String>& domains)
1226 {
1227     for (auto& processPool : processPools())
1228         processPool->sendToNetworkingProcess(Messages::NetworkProcess::RemovePrevalentDomains(m_sessionID, domains));
1229 }
1230
1231 void WebsiteDataStore::hasStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void (bool)>&& callback)
1232 {
1233     if (!resourceLoadStatisticsEnabled()) {
1234         callback(false);
1235         return;
1236     }
1237     
1238     m_resourceLoadStatistics->hasStorageAccess(WTFMove(subFrameHost), WTFMove(topFrameHost), frameID, pageID, WTFMove(callback));
1239 }
1240
1241 void WebsiteDataStore::requestStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void (bool)>&& callback)
1242 {
1243     if (!resourceLoadStatisticsEnabled()) {
1244         callback(false);
1245         return;
1246     }
1247     
1248     m_resourceLoadStatistics->requestStorageAccess(WTFMove(subFrameHost), WTFMove(topFrameHost), frameID, pageID, WTFMove(callback));
1249 }
1250 #endif
1251
1252 void WebsiteDataStore::networkProcessDidCrash()
1253 {
1254 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1255     if (m_resourceLoadStatistics)
1256         m_resourceLoadStatistics->scheduleCookiePartitioningStateReset();
1257 #endif
1258 }
1259
1260 void WebsiteDataStore::webPageWasAdded(WebPageProxy& webPageProxy)
1261 {
1262     if (m_storageManager)
1263         m_storageManager->createSessionStorageNamespace(webPageProxy.pageID(), std::numeric_limits<unsigned>::max());
1264 }
1265
1266 void WebsiteDataStore::webPageWasRemoved(WebPageProxy& webPageProxy)
1267 {
1268     if (m_storageManager)
1269         m_storageManager->destroySessionStorageNamespace(webPageProxy.pageID());
1270 }
1271
1272 void WebsiteDataStore::webProcessWillOpenConnection(WebProcessProxy& webProcessProxy, IPC::Connection& connection)
1273 {
1274     if (m_storageManager)
1275         m_storageManager->processWillOpenConnection(webProcessProxy, connection);
1276
1277     if (m_resourceLoadStatistics)
1278         m_resourceLoadStatistics->processWillOpenConnection(webProcessProxy, connection);
1279 }
1280
1281 void WebsiteDataStore::webPageWillOpenConnection(WebPageProxy& webPageProxy, IPC::Connection& connection)
1282 {
1283     if (m_storageManager)
1284         m_storageManager->setAllowedSessionStorageNamespaceConnection(webPageProxy.pageID(), &connection);
1285 }
1286
1287 void WebsiteDataStore::webPageDidCloseConnection(WebPageProxy& webPageProxy, IPC::Connection&)
1288 {
1289     if (m_storageManager)
1290         m_storageManager->setAllowedSessionStorageNamespaceConnection(webPageProxy.pageID(), nullptr);
1291 }
1292
1293 void WebsiteDataStore::webProcessDidCloseConnection(WebProcessProxy& webProcessProxy, IPC::Connection& connection)
1294 {
1295     if (m_resourceLoadStatistics)
1296         m_resourceLoadStatistics->processDidCloseConnection(webProcessProxy, connection);
1297
1298     if (m_storageManager)
1299         m_storageManager->processDidCloseConnection(webProcessProxy, connection);
1300 }
1301
1302 bool WebsiteDataStore::isAssociatedProcessPool(WebProcessPool& processPool) const
1303 {
1304     if (auto* processPoolDataStore = processPool.websiteDataStore())
1305         return &processPoolDataStore->websiteDataStore() == this;
1306     return false;
1307 }
1308
1309 HashSet<RefPtr<WebProcessPool>> WebsiteDataStore::processPools(size_t count, bool ensureAPoolExists) const
1310 {
1311     HashSet<RefPtr<WebProcessPool>> processPools;
1312     for (auto& process : processes())
1313         processPools.add(&process->processPool());
1314
1315     if (processPools.isEmpty()) {
1316         // Check if we're one of the legacy data stores.
1317         for (auto& processPool : WebProcessPool::allProcessPools()) {
1318             if (!isAssociatedProcessPool(*processPool))
1319                 continue;
1320
1321             processPools.add(processPool);
1322
1323             if (processPools.size() == count)
1324                 break;
1325         }
1326     }
1327
1328     if (processPools.isEmpty() && count && ensureAPoolExists) {
1329         auto processPool = WebProcessPool::create(API::ProcessPoolConfiguration::createWithWebsiteDataStoreConfiguration(m_configuration));
1330         processPools.add(processPool.ptr());
1331     }
1332
1333     return processPools;
1334 }
1335
1336 #if ENABLE(NETSCAPE_PLUGIN_API)
1337 Vector<PluginModuleInfo> WebsiteDataStore::plugins() const
1338 {
1339     Vector<PluginModuleInfo> plugins;
1340
1341     for (auto& processPool : processPools()) {
1342         for (auto& plugin : processPool->pluginInfoStore().plugins())
1343             plugins.append(plugin);
1344     }
1345
1346     return plugins;
1347 }
1348 #endif
1349
1350 static String computeMediaKeyFile(const String& mediaKeyDirectory)
1351 {
1352     return WebCore::FileSystem::pathByAppendingComponent(mediaKeyDirectory, "SecureStop.plist");
1353 }
1354
1355 Vector<WebCore::SecurityOriginData> WebsiteDataStore::mediaKeyOrigins(const String& mediaKeysStorageDirectory)
1356 {
1357     ASSERT(!mediaKeysStorageDirectory.isEmpty());
1358
1359     Vector<WebCore::SecurityOriginData> origins;
1360
1361     for (const auto& originPath : WebCore::FileSystem::listDirectory(mediaKeysStorageDirectory, "*")) {
1362         auto mediaKeyFile = computeMediaKeyFile(originPath);
1363         if (!WebCore::FileSystem::fileExists(mediaKeyFile))
1364             continue;
1365
1366         auto mediaKeyIdentifier = WebCore::FileSystem::pathGetFileName(originPath);
1367
1368         if (auto securityOrigin = WebCore::SecurityOriginData::fromDatabaseIdentifier(mediaKeyIdentifier))
1369             origins.append(*securityOrigin);
1370     }
1371
1372     return origins;
1373 }
1374
1375 void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, WallTime modifiedSince)
1376 {
1377     ASSERT(!mediaKeysStorageDirectory.isEmpty());
1378
1379     for (const auto& mediaKeyDirectory : WebCore::FileSystem::listDirectory(mediaKeysStorageDirectory, "*")) {
1380         auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1381
1382         auto modificationTime = WebCore::FileSystem::getFileModificationTime(mediaKeyFile);
1383         if (!modificationTime)
1384             continue;
1385
1386         if (modificationTime.value() < modifiedSince)
1387             continue;
1388
1389         WebCore::FileSystem::deleteFile(mediaKeyFile);
1390         WebCore::FileSystem::deleteEmptyDirectory(mediaKeyDirectory);
1391     }
1392 }
1393
1394 void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, const HashSet<WebCore::SecurityOriginData>& origins)
1395 {
1396     ASSERT(!mediaKeysStorageDirectory.isEmpty());
1397
1398     for (const auto& origin : origins) {
1399         auto mediaKeyDirectory = WebCore::FileSystem::pathByAppendingComponent(mediaKeysStorageDirectory, origin.databaseIdentifier());
1400         auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1401
1402         WebCore::FileSystem::deleteFile(mediaKeyFile);
1403         WebCore::FileSystem::deleteEmptyDirectory(mediaKeyDirectory);
1404     }
1405 }
1406
1407 bool WebsiteDataStore::resourceLoadStatisticsEnabled() const
1408 {
1409     return !!m_resourceLoadStatistics;
1410 }
1411
1412 void WebsiteDataStore::setResourceLoadStatisticsEnabled(bool enabled)
1413 {
1414     if (enabled == resourceLoadStatisticsEnabled())
1415         return;
1416
1417     if (enabled) {
1418         ASSERT(!m_resourceLoadStatistics);
1419         enableResourceLoadStatisticsAndSetTestingCallback(nullptr);
1420         return;
1421     }
1422
1423     m_resourceLoadStatistics = nullptr;
1424
1425     auto existingProcessPools = processPools(std::numeric_limits<size_t>::max(), false);
1426     for (auto& processPool : existingProcessPools)
1427         processPool->setResourceLoadStatisticsEnabled(false);
1428 }
1429
1430 bool WebsiteDataStore::resourceLoadStatisticsDebugMode() const
1431 {
1432     return m_resourceLoadStatisticsDebugMode;
1433 }
1434
1435 void WebsiteDataStore::setResourceLoadStatisticsDebugMode(bool enabled)
1436 {
1437     m_resourceLoadStatisticsDebugMode = enabled;
1438     m_resourceLoadStatistics->setResourceLoadStatisticsDebugMode(enabled);
1439 }
1440
1441 void WebsiteDataStore::enableResourceLoadStatisticsAndSetTestingCallback(Function<void (const String&)>&& callback)
1442 {
1443     if (m_resourceLoadStatistics) {
1444         m_resourceLoadStatistics->setStatisticsTestingCallback(WTFMove(callback));
1445         return;
1446     }
1447
1448 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
1449     m_resourceLoadStatistics = WebResourceLoadStatisticsStore::create(m_configuration.resourceLoadStatisticsDirectory, WTFMove(callback), m_sessionID.isEphemeral(), [this, protectedThis = makeRef(*this)] (const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst shouldClearFirst) {
1450         updatePrevalentDomainsToPartitionOrBlockCookies(domainsToPartition, domainsToBlock, domainsToNeitherPartitionNorBlock, shouldClearFirst);
1451     }, [this, protectedThis = makeRef(*this)] (const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void(bool hasAccess)>&& callback) {
1452         hasStorageAccessForFrameHandler(resourceDomain, firstPartyDomain, frameID, pageID, WTFMove(callback));
1453     }, [this, protectedThis = makeRef(*this)] (const String& resourceDomain, const String& firstPartyDomain, std::optional<uint64_t> frameID, uint64_t pageID, WTF::CompletionHandler<void(bool wasGranted)>&& callback) {
1454         grantStorageAccessHandler(resourceDomain, firstPartyDomain, frameID, pageID, WTFMove(callback));
1455     }, [this, protectedThis = makeRef(*this)] () {
1456         removeAllStorageAccessHandler();
1457     }, [this, protectedThis = makeRef(*this)] (const Vector<String>& domainsToRemove) {
1458         removePrevalentDomains(domainsToRemove);
1459     });
1460 #else
1461     m_resourceLoadStatistics = WebResourceLoadStatisticsStore::create(m_configuration.resourceLoadStatisticsDirectory, WTFMove(callback), m_sessionID.isEphemeral());
1462 #endif
1463
1464     for (auto& processPool : processPools())
1465         processPool->setResourceLoadStatisticsEnabled(true);
1466 }
1467
1468 void WebsiteDataStore::clearResourceLoadStatisticsInWebProcesses(CompletionHandler<void()>&& callback)
1469 {
1470     if (resourceLoadStatisticsEnabled()) {
1471         for (auto& processPool : processPools())
1472             processPool->clearResourceLoadStatistics();
1473     }
1474     callback();
1475 }
1476
1477 StorageProcessCreationParameters WebsiteDataStore::storageProcessParameters()
1478 {
1479     resolveDirectoriesIfNecessary();
1480
1481     StorageProcessCreationParameters parameters;
1482
1483     parameters.sessionID = m_sessionID;
1484
1485 #if ENABLE(INDEXED_DATABASE)
1486     parameters.indexedDatabaseDirectory = resolvedIndexedDatabaseDirectory();
1487     if (!parameters.indexedDatabaseDirectory.isEmpty())
1488         SandboxExtension::createHandleForReadWriteDirectory(parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
1489 #endif
1490 #if ENABLE(SERVICE_WORKER)
1491     parameters.serviceWorkerRegistrationDirectory = resolvedServiceWorkerRegistrationDirectory();
1492     if (!parameters.serviceWorkerRegistrationDirectory.isEmpty())
1493         SandboxExtension::createHandleForReadWriteDirectory(parameters.serviceWorkerRegistrationDirectory, parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
1494 #endif
1495
1496     return parameters;
1497 }
1498
1499 Vector<WebCore::Cookie> WebsiteDataStore::pendingCookies() const
1500 {
1501     return copyToVector(m_pendingCookies);
1502 }
1503
1504 void WebsiteDataStore::addPendingCookie(const WebCore::Cookie& cookie)
1505 {
1506     m_pendingCookies.add(cookie);
1507 }
1508
1509 void WebsiteDataStore::removePendingCookie(const WebCore::Cookie& cookie)
1510 {
1511     m_pendingCookies.remove(cookie);
1512 }
1513
1514 #if !PLATFORM(COCOA)
1515 WebsiteDataStoreParameters WebsiteDataStore::parameters()
1516 {
1517     // FIXME: Implement cookies.
1518     WebsiteDataStoreParameters parameters;
1519     parameters.networkSessionParameters.sessionID = m_sessionID;
1520     return parameters;
1521 }
1522 #endif
1523
1524 }