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