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