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