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