Domain relationships in the ITP Database should be inserted in a single query and...
[WebKit-https.git] / Source / WebKit / UIProcess / WebsiteData / WebsiteDataStore.cpp
1 /*
2  * Copyright (C) 2014-2019 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 "APIHTTPCookieStore.h"
30 #include "APIProcessPoolConfiguration.h"
31 #include "APIWebsiteDataRecord.h"
32 #include "AuthenticatorManager.h"
33 #include "DeviceIdHashSaltStorage.h"
34 #include "MockAuthenticatorManager.h"
35 #include "NetworkProcessMessages.h"
36 #include "ShouldGrandfatherStatistics.h"
37 #include "StorageAccessStatus.h"
38 #include "WebKit2Initialize.h"
39 #include "WebPageProxy.h"
40 #include "WebProcessCache.h"
41 #include "WebProcessMessages.h"
42 #include "WebProcessPool.h"
43 #include "WebResourceLoadStatisticsStore.h"
44 #include "WebsiteData.h"
45 #include "WebsiteDataStoreClient.h"
46 #include "WebsiteDataStoreParameters.h"
47 #include <WebCore/ApplicationCacheStorage.h>
48 #include <WebCore/CredentialStorage.h>
49 #include <WebCore/DatabaseTracker.h>
50 #include <WebCore/HTMLMediaElement.h>
51 #include <WebCore/OriginLock.h>
52 #include <WebCore/RegistrableDomain.h>
53 #include <WebCore/SecurityOrigin.h>
54 #include <WebCore/SecurityOriginData.h>
55 #include <WebCore/StorageQuotaManager.h>
56 #include <wtf/CallbackAggregator.h>
57 #include <wtf/CompletionHandler.h>
58 #include <wtf/CrossThreadCopier.h>
59 #include <wtf/FileSystem.h>
60 #include <wtf/ProcessPrivilege.h>
61 #include <wtf/RunLoop.h>
62
63 #if ENABLE(NETSCAPE_PLUGIN_API)
64 #include "PluginProcessManager.h"
65 #endif
66
67 #if HAVE(SEC_KEY_PROXY)
68 #include "SecKeyProxyStore.h"
69 #endif
70
71 #if HAVE(APP_SSO)
72 #include "SOAuthorizationCoordinator.h"
73 #endif
74
75 namespace WebKit {
76
77 static bool allowsWebsiteDataRecordsForAllOrigins;
78 void WebsiteDataStore::allowWebsiteDataRecordsForAllOrigins()
79 {
80     allowsWebsiteDataRecordsForAllOrigins = true;
81 }
82
83 static HashMap<PAL::SessionID, WebsiteDataStore*>& nonDefaultDataStores()
84 {
85     RELEASE_ASSERT(isUIThread());
86     static NeverDestroyed<HashMap<PAL::SessionID, WebsiteDataStore*>> map;
87     return map;
88 }
89
90 Ref<WebsiteDataStore> WebsiteDataStore::createNonPersistent()
91 {
92     return adoptRef(*new WebsiteDataStore(WebsiteDataStoreConfiguration::create(IsPersistent::No), PAL::SessionID::generateEphemeralSessionID()));
93 }
94
95 Ref<WebsiteDataStore> WebsiteDataStore::create(Ref<WebsiteDataStoreConfiguration>&& configuration, PAL::SessionID sessionID)
96 {
97     return adoptRef(*new WebsiteDataStore(WTFMove(configuration), sessionID));
98 }
99
100 WebsiteDataStore::WebsiteDataStore(Ref<WebsiteDataStoreConfiguration>&& configuration, PAL::SessionID sessionID)
101     : m_sessionID(sessionID)
102     , m_resolvedConfiguration(WTFMove(configuration))
103     , m_configuration(m_resolvedConfiguration->copy())
104     , m_deviceIdHashSaltStorage(DeviceIdHashSaltStorage::create(isPersistent() ? m_configuration->deviceIdHashSaltsStorageDirectory() : String()))
105     , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
106 #if ENABLE(WEB_AUTHN)
107     , m_authenticatorManager(makeUniqueRef<AuthenticatorManager>())
108 #endif
109     , m_client(makeUniqueRef<WebsiteDataStoreClient>())
110 #if HAVE(APP_SSO)
111     , m_soAuthorizationCoordinator(makeUniqueRef<SOAuthorizationCoordinator>())
112 #endif
113 {
114     WTF::setProcessPrivileges(allPrivileges());
115     maybeRegisterWithSessionIDMap();
116     platformInitialize();
117
118     ASSERT(RunLoop::isMain());
119 }
120
121 WebsiteDataStore::~WebsiteDataStore()
122 {
123     ASSERT(RunLoop::isMain());
124
125     platformDestroy();
126
127     if (m_sessionID != PAL::SessionID::defaultSessionID()) {
128         ASSERT(nonDefaultDataStores().get(m_sessionID) == this);
129         nonDefaultDataStores().remove(m_sessionID);
130         for (auto& processPool : WebProcessPool::allProcessPools()) {
131             if (auto* networkProcess = processPool->networkProcess())
132                 networkProcess->removeSession(m_sessionID);
133         }
134     }
135 }
136
137 static RefPtr<WebsiteDataStore>& globalDefaultDataStore()
138 {
139     static NeverDestroyed<RefPtr<WebsiteDataStore>> globalDefaultDataStore;
140     return globalDefaultDataStore.get();
141 }
142
143 Ref<WebsiteDataStore> WebsiteDataStore::defaultDataStore()
144 {
145     InitializeWebKit2();
146
147     auto& store = globalDefaultDataStore();
148     if (!store)
149         store = adoptRef(new WebsiteDataStore(WebsiteDataStoreConfiguration::create(IsPersistent::Yes), PAL::SessionID::defaultSessionID()));
150
151     return *store;
152 }
153
154 void WebsiteDataStore::deleteDefaultDataStoreForTesting()
155 {
156     globalDefaultDataStore() = nullptr;
157 }
158
159 bool WebsiteDataStore::defaultDataStoreExists()
160 {
161     return !!globalDefaultDataStore();
162 }
163
164 void WebsiteDataStore::maybeRegisterWithSessionIDMap()
165 {
166     if (m_sessionID != PAL::SessionID::defaultSessionID()) {
167         auto result = nonDefaultDataStores().add(m_sessionID, this);
168         ASSERT_UNUSED(result, result.isNewEntry);
169     }
170 }
171
172 WebsiteDataStore* WebsiteDataStore::existingNonDefaultDataStoreForSessionID(PAL::SessionID sessionID)
173 {
174     return sessionID != PAL::SessionID::defaultSessionID() ? nonDefaultDataStores().get(sessionID) : nullptr;
175 }
176
177 void WebsiteDataStore::registerProcess(WebProcessProxy& process)
178 {
179     ASSERT(process.pageCount() || process.provisionalPageCount());
180     m_processes.add(process);
181 }
182
183 void WebsiteDataStore::unregisterProcess(WebProcessProxy& process)
184 {
185     ASSERT(!process.pageCount());
186     ASSERT(!process.provisionalPageCount());
187     m_processes.remove(process);
188 }
189
190 WebProcessPool* WebsiteDataStore::processPoolForCookieStorageOperations()
191 {
192     auto pools = processPools(1, false);
193     return pools.isEmpty() ? nullptr : pools.begin()->get();
194 }
195
196 void WebsiteDataStore::resolveDirectoriesIfNecessary()
197 {
198     if (m_hasResolvedDirectories)
199         return;
200     m_hasResolvedDirectories = true;
201
202     // Resolve directory paths.
203     if (!m_configuration->applicationCacheDirectory().isEmpty())
204         m_resolvedConfiguration->setApplicationCacheDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->applicationCacheDirectory()));
205     if (!m_configuration->mediaCacheDirectory().isEmpty())
206         m_resolvedConfiguration->setMediaCacheDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->mediaCacheDirectory()));
207     if (!m_configuration->mediaKeysStorageDirectory().isEmpty())
208         m_resolvedConfiguration->setMediaKeysStorageDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->mediaKeysStorageDirectory()));
209     if (!m_configuration->webSQLDatabaseDirectory().isEmpty())
210         m_resolvedConfiguration->setWebSQLDatabaseDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->webSQLDatabaseDirectory()));
211     if (!m_configuration->indexedDBDatabaseDirectory().isEmpty())
212         m_resolvedConfiguration->setIndexedDBDatabaseDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->indexedDBDatabaseDirectory()));
213     if (!m_configuration->deviceIdHashSaltsStorageDirectory().isEmpty())
214         m_resolvedConfiguration->setDeviceIdHashSaltsStorageDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->deviceIdHashSaltsStorageDirectory()));
215     if (!m_configuration->networkCacheDirectory().isEmpty())
216         m_resolvedConfiguration->setNetworkCacheDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->networkCacheDirectory()));
217     if (!m_configuration->resourceLoadStatisticsDirectory().isEmpty())
218         m_resolvedConfiguration->setResourceLoadStatisticsDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->resourceLoadStatisticsDirectory()));
219     if (!m_configuration->serviceWorkerRegistrationDirectory().isEmpty() && m_resolvedConfiguration->serviceWorkerRegistrationDirectory().isEmpty())
220         m_resolvedConfiguration->setServiceWorkerRegistrationDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->serviceWorkerRegistrationDirectory()));
221     if (!m_configuration->javaScriptConfigurationDirectory().isEmpty())
222         m_resolvedConfiguration->setJavaScriptConfigurationDirectory(resolvePathForSandboxExtension(m_configuration->javaScriptConfigurationDirectory()));
223     if (!m_configuration->cacheStorageDirectory().isEmpty() && m_resolvedConfiguration->cacheStorageDirectory().isEmpty())
224         m_resolvedConfiguration->setCacheStorageDirectory(resolvePathForSandboxExtension(m_configuration->cacheStorageDirectory()));
225
226     // Resolve directories for file paths.
227     if (!m_configuration->cookieStorageFile().isEmpty()) {
228         m_resolvedConfiguration->setCookieStorageFile(resolveAndCreateReadWriteDirectoryForSandboxExtension(FileSystem::directoryName(m_configuration->cookieStorageFile())));
229         m_resolvedConfiguration->setCookieStorageFile(FileSystem::pathByAppendingComponent(m_resolvedConfiguration->cookieStorageFile(), FileSystem::pathGetFileName(m_configuration->cookieStorageFile())));
230     }
231 }
232
233 enum class ProcessAccessType {
234     None,
235     OnlyIfLaunched,
236     Launch,
237 };
238
239 static ProcessAccessType computeNetworkProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
240 {
241     for (auto dataType : dataTypes) {
242         if (WebsiteData::ownerProcess(dataType) == WebsiteDataProcessType::Network) {
243             if (isNonPersistentStore)
244                 return ProcessAccessType::OnlyIfLaunched;
245             return ProcessAccessType::Launch;
246         }
247     }
248     return ProcessAccessType::None;
249 }
250
251 static ProcessAccessType computeWebProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
252 {
253     UNUSED_PARAM(isNonPersistentStore);
254
255     ProcessAccessType processAccessType = ProcessAccessType::None;
256
257     if (dataTypes.contains(WebsiteDataType::MemoryCache))
258         return ProcessAccessType::OnlyIfLaunched;
259
260     return processAccessType;
261 }
262
263 void WebsiteDataStore::fetchData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void(Vector<WebsiteDataRecord>)>&& completionHandler)
264 {
265     fetchDataAndApply(dataTypes, fetchOptions, nullptr, WTFMove(completionHandler));
266 }
267
268 void WebsiteDataStore::fetchDataAndApply(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply)
269 {
270     struct CallbackAggregator final : ThreadSafeRefCounted<CallbackAggregator> {
271         CallbackAggregator(OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply, WebsiteDataStore& dataStore)
272             : fetchOptions(fetchOptions)
273             , queue(WTFMove(queue))
274             , apply(WTFMove(apply))
275             , protectedDataStore(dataStore)
276         {
277             ASSERT(RunLoop::isMain());
278         }
279
280         ~CallbackAggregator()
281         {
282             ASSERT(!pendingCallbacks);
283
284             // Make sure the data store gets destroyed on the main thread even though the CallbackAggregator can get destroyed on a background queue.
285             RunLoop::main().dispatch([protectedDataStore = WTFMove(protectedDataStore)] { });
286         }
287
288         void addPendingCallback()
289         {
290             pendingCallbacks++;
291         }
292
293         void removePendingCallback(WebsiteData websiteData)
294         {
295             ASSERT(pendingCallbacks);
296             --pendingCallbacks;
297
298             for (auto& entry : websiteData.entries) {
299                 auto displayName = WebsiteDataRecord::displayNameForOrigin(entry.origin);
300                 if (!displayName) {
301                     if (!allowsWebsiteDataRecordsForAllOrigins)
302                         continue;
303
304                     displayName = makeString(entry.origin.protocol, " ", entry.origin.host);
305                 }
306
307                 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
308                 if (!record.displayName)
309                     record.displayName = WTFMove(displayName);
310
311                 record.add(entry.type, entry.origin);
312
313                 if (fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes)) {
314                     if (!record.size)
315                         record.size = WebsiteDataRecord::Size { 0, { } };
316
317                     record.size->totalSize += entry.size;
318                     record.size->typeSizes.add(static_cast<unsigned>(entry.type), 0).iterator->value += entry.size;
319                 }
320             }
321
322             for (auto& hostName : websiteData.hostNamesWithCookies) {
323                 auto displayName = WebsiteDataRecord::displayNameForCookieHostName(hostName);
324                 if (!displayName)
325                     continue;
326
327                 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
328                 if (!record.displayName)
329                     record.displayName = WTFMove(displayName);
330
331                 record.addCookieHostName(hostName);
332             }
333
334 #if ENABLE(NETSCAPE_PLUGIN_API)
335             for (auto& hostName : websiteData.hostNamesWithPluginData) {
336                 auto displayName = WebsiteDataRecord::displayNameForHostName(hostName);
337                 if (!displayName)
338                     continue;
339
340                 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
341                 if (!record.displayName)
342                     record.displayName = WTFMove(displayName);
343
344                 record.addPluginDataHostName(hostName);
345             }
346 #endif
347
348             for (auto& hostName : websiteData.hostNamesWithHSTSCache) {
349                 auto displayName = WebsiteDataRecord::displayNameForHostName(hostName);
350                 if (!displayName)
351                     continue;
352                 
353                 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
354                 if (!record.displayName)
355                     record.displayName = WTFMove(displayName);
356
357                 record.addHSTSCacheHostname(hostName);
358             }
359
360             callIfNeeded();
361         }
362
363         void callIfNeeded()
364         {
365             if (pendingCallbacks)
366                 return;
367
368             Vector<WebsiteDataRecord> records;
369             records.reserveInitialCapacity(m_websiteDataRecords.size());
370             for (auto& record : m_websiteDataRecords.values())
371                 records.uncheckedAppend(WTFMove(record));
372
373             auto processRecords = [apply = WTFMove(apply), records = WTFMove(records)] () mutable {
374                 apply(WTFMove(records));
375             };
376
377             if (queue)
378                 queue->dispatch(WTFMove(processRecords));
379             else
380                 RunLoop::main().dispatch(WTFMove(processRecords));
381         }
382
383         const OptionSet<WebsiteDataFetchOption> fetchOptions;
384
385         unsigned pendingCallbacks = 0;
386         RefPtr<WorkQueue> queue;
387         Function<void(Vector<WebsiteDataRecord>)> apply;
388
389         HashMap<String, WebsiteDataRecord> m_websiteDataRecords;
390         Ref<WebsiteDataStore> protectedDataStore;
391     };
392
393     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(fetchOptions, WTFMove(queue), WTFMove(apply), *this));
394
395 #if ENABLE(VIDEO)
396     if (dataTypes.contains(WebsiteDataType::DiskCache)) {
397         callbackAggregator->addPendingCallback();
398         m_queue->dispatch([mediaCacheDirectory = m_configuration->mediaCacheDirectory().isolatedCopy(), callbackAggregator] {
399             // FIXME: Make HTMLMediaElement::originsInMediaCache return a collection of SecurityOriginDatas.
400             HashSet<RefPtr<WebCore::SecurityOrigin>> origins = WebCore::HTMLMediaElement::originsInMediaCache(mediaCacheDirectory);
401             WebsiteData websiteData;
402             
403             for (auto& origin : origins) {
404                 WebsiteData::Entry entry { origin->data(), WebsiteDataType::DiskCache, 0 };
405                 websiteData.entries.append(WTFMove(entry));
406             }
407             
408             RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
409                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
410             });
411         });
412     }
413 #endif
414
415     auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
416     if (networkProcessAccessType != ProcessAccessType::None) {
417         for (auto& processPool : processPools()) {
418             switch (networkProcessAccessType) {
419             case ProcessAccessType::OnlyIfLaunched:
420                 if (!processPool->networkProcess())
421                     continue;
422                 break;
423
424             case ProcessAccessType::Launch:
425                 processPool->ensureNetworkProcess(this);
426                 break;
427
428             case ProcessAccessType::None:
429                 ASSERT_NOT_REACHED();
430             }
431
432             callbackAggregator->addPendingCallback();
433             processPool->networkProcess()->fetchWebsiteData(m_sessionID, dataTypes, fetchOptions, [callbackAggregator, processPool](WebsiteData websiteData) {
434                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
435             });
436         }
437     }
438
439     auto webProcessAccessType = computeWebProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
440     if (webProcessAccessType != ProcessAccessType::None) {
441         for (auto& process : processes()) {
442             switch (webProcessAccessType) {
443             case ProcessAccessType::OnlyIfLaunched:
444                 if (process.state() != WebProcessProxy::State::Running)
445                     continue;
446                 break;
447
448             case ProcessAccessType::Launch:
449                 // FIXME: Handle this.
450                 ASSERT_NOT_REACHED();
451                 break;
452
453             case ProcessAccessType::None:
454                 ASSERT_NOT_REACHED();
455             }
456
457             callbackAggregator->addPendingCallback();
458             process.fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator](WebsiteData websiteData) {
459                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
460             });
461         }
462     }
463
464     if (dataTypes.contains(WebsiteDataType::DeviceIdHashSalt)) {
465         callbackAggregator->addPendingCallback();
466
467         m_deviceIdHashSaltStorage->getDeviceIdHashSaltOrigins([callbackAggregator](auto&& origins) {
468             WebsiteData websiteData;
469
470             while (!origins.isEmpty())
471                 websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::DeviceIdHashSalt, 0 });
472
473             callbackAggregator->removePendingCallback(WTFMove(websiteData));
474         });
475     }
476
477     if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
478         callbackAggregator->addPendingCallback();
479
480         m_queue->dispatch([fetchOptions, applicationCacheDirectory = m_configuration->applicationCacheDirectory().isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration->applicationCacheFlatFileSubdirectoryName().isolatedCopy(), callbackAggregator] {
481             auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
482
483             WebsiteData websiteData;
484
485             // FIXME: getOriginsWithCache should return a collection of SecurityOriginDatas.
486             auto origins = storage->originsWithCache();
487
488             for (auto& origin : origins) {
489                 uint64_t size = fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes) ? storage->diskUsageForOrigin(origin) : 0;
490                 WebsiteData::Entry entry { origin->data(), WebsiteDataType::OfflineWebApplicationCache, size };
491
492                 websiteData.entries.append(WTFMove(entry));
493             }
494
495             RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
496                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
497             });
498         });
499     }
500
501     if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
502         callbackAggregator->addPendingCallback();
503
504         m_queue->dispatch([webSQLDatabaseDirectory = m_configuration->webSQLDatabaseDirectory().isolatedCopy(), callbackAggregator] {
505             auto origins = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->origins();
506             RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
507                 WebsiteData websiteData;
508                 for (auto& origin : origins)
509                     websiteData.entries.append(WebsiteData::Entry { WTFMove(origin), WebsiteDataType::WebSQLDatabases, 0 });
510                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
511             });
512         });
513     }
514
515     if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
516         callbackAggregator->addPendingCallback();
517
518         m_queue->dispatch([mediaKeysStorageDirectory = m_configuration->mediaKeysStorageDirectory().isolatedCopy(), callbackAggregator] {
519             auto origins = mediaKeyOrigins(mediaKeysStorageDirectory);
520
521             RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
522                 WebsiteData websiteData;
523                 for (auto& origin : origins)
524                     websiteData.entries.append(WebsiteData::Entry { origin, WebsiteDataType::MediaKeys, 0 });
525
526                 callbackAggregator->removePendingCallback(WTFMove(websiteData));
527             });
528         });
529     }
530
531 #if ENABLE(NETSCAPE_PLUGIN_API)
532     if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
533         class State {
534         public:
535             static void fetchData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
536             {
537                 new State(WTFMove(callbackAggregator), WTFMove(plugins));
538             }
539
540         private:
541             State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
542                 : m_callbackAggregator(WTFMove(callbackAggregator))
543                 , m_plugins(WTFMove(plugins))
544             {
545                 m_callbackAggregator->addPendingCallback();
546
547                 fetchWebsiteDataForNextPlugin();
548             }
549
550             ~State()
551             {
552                 ASSERT(m_plugins.isEmpty());
553             }
554
555             void fetchWebsiteDataForNextPlugin()
556             {
557                 if (m_plugins.isEmpty()) {
558                     WebsiteData websiteData;
559                     websiteData.hostNamesWithPluginData = WTFMove(m_hostNames);
560
561                     m_callbackAggregator->removePendingCallback(WTFMove(websiteData));
562
563                     delete this;
564                     return;
565                 }
566
567                 auto plugin = m_plugins.takeLast();
568                 PluginProcessManager::singleton().fetchWebsiteData(plugin, m_callbackAggregator->fetchOptions, [this](Vector<String> hostNames) {
569                     for (auto& hostName : hostNames)
570                         m_hostNames.add(WTFMove(hostName));
571                     fetchWebsiteDataForNextPlugin();
572                 });
573             }
574
575             Ref<CallbackAggregator> m_callbackAggregator;
576             Vector<PluginModuleInfo> m_plugins;
577             HashSet<String> m_hostNames;
578         };
579
580         State::fetchData(*callbackAggregator, plugins());
581     }
582 #endif
583
584     callbackAggregator->callIfNeeded();
585 }
586
587 #if ENABLE(RESOURCE_LOAD_STATISTICS)
588 void WebsiteDataStore::fetchDataForRegistrableDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<WebCore::RegistrableDomain>& domains, CompletionHandler<void(Vector<WebsiteDataRecord>&&, HashSet<WebCore::RegistrableDomain>&&)>&& completionHandler)
589 {
590     fetchDataAndApply(dataTypes, fetchOptions, m_queue.copyRef(), [domains = crossThreadCopy(domains), completionHandler = WTFMove(completionHandler)] (auto&& existingDataRecords) mutable {
591         ASSERT(!RunLoop::isMain());
592         
593         Vector<WebsiteDataRecord> matchingDataRecords;
594         HashSet<WebCore::RegistrableDomain> domainsWithMatchingDataRecords;
595         for (auto&& dataRecord : existingDataRecords) {
596             for (auto& domain : domains) {
597                 if (dataRecord.matches(domain)) {
598                     matchingDataRecords.append(WTFMove(dataRecord));
599                     domainsWithMatchingDataRecords.add(domain.isolatedCopy());
600                     break;
601                 }
602             }
603         }
604         RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), matchingDataRecords = WTFMove(matchingDataRecords), domainsWithMatchingDataRecords = WTFMove(domainsWithMatchingDataRecords)] () mutable {
605             completionHandler(WTFMove(matchingDataRecords), WTFMove(domainsWithMatchingDataRecords));
606         });
607     });
608 }
609 #endif
610
611 static ProcessAccessType computeNetworkProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
612 {
613     ProcessAccessType processAccessType = ProcessAccessType::None;
614
615     for (auto dataType : dataTypes) {
616         if (dataType == WebsiteDataType::Cookies) {
617             if (isNonPersistentStore)
618                 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
619             else
620                 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
621         } else if (WebsiteData::ownerProcess(dataType) == WebsiteDataProcessType::Network)
622             return ProcessAccessType::Launch;
623     }
624     
625     return processAccessType;
626 }
627
628 static ProcessAccessType computeWebProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
629 {
630     UNUSED_PARAM(isNonPersistentStore);
631
632     ProcessAccessType processAccessType = ProcessAccessType::None;
633
634     if (dataTypes.contains(WebsiteDataType::MemoryCache))
635         processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
636
637     return processAccessType;
638 }
639
640 void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, WallTime modifiedSince, Function<void()>&& completionHandler)
641 {
642     struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
643         CallbackAggregator(WebsiteDataStore& dataStore, Function<void()>&& completionHandler)
644             : completionHandler(WTFMove(completionHandler))
645             , protectedDataStore(dataStore)
646         {
647             ASSERT(RunLoop::isMain());
648         }
649
650         ~CallbackAggregator()
651         {
652             // Make sure the data store gets destroyed on the main thread even though the CallbackAggregator can get destroyed on a background queue.
653             RunLoop::main().dispatch([protectedDataStore = WTFMove(protectedDataStore)] { });
654         }
655
656         void addPendingCallback()
657         {
658             pendingCallbacks++;
659         }
660
661         void removePendingCallback()
662         {
663             ASSERT(pendingCallbacks);
664             --pendingCallbacks;
665
666             callIfNeeded();
667         }
668
669         void callIfNeeded()
670         {
671             if (!pendingCallbacks)
672                 RunLoop::main().dispatch(WTFMove(completionHandler));
673         }
674
675         unsigned pendingCallbacks = 0;
676         Function<void()> completionHandler;
677         Ref<WebsiteDataStore> protectedDataStore;
678     };
679
680     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(*this, WTFMove(completionHandler)));
681
682 #if ENABLE(VIDEO)
683     if (dataTypes.contains(WebsiteDataType::DiskCache)) {
684         callbackAggregator->addPendingCallback();
685         m_queue->dispatch([modifiedSince, mediaCacheDirectory = m_configuration->mediaCacheDirectory().isolatedCopy(), callbackAggregator] {
686             WebCore::HTMLMediaElement::clearMediaCache(mediaCacheDirectory, modifiedSince);
687             
688             WTF::RunLoop::main().dispatch([callbackAggregator] {
689                 callbackAggregator->removePendingCallback();
690             });
691         });
692     }
693 #endif
694
695 #if ENABLE(RESOURCE_LOAD_STATISTICS)
696     bool didNotifyNetworkProcessToDeleteWebsiteData = false;
697 #endif
698     auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
699     if (networkProcessAccessType != ProcessAccessType::None) {
700         for (auto& processPool : processPools()) {
701             switch (networkProcessAccessType) {
702             case ProcessAccessType::OnlyIfLaunched:
703                 if (!processPool->networkProcess())
704                     continue;
705                 break;
706
707             case ProcessAccessType::Launch:
708                 processPool->ensureNetworkProcess(this);
709                 break;
710
711             case ProcessAccessType::None:
712                 ASSERT_NOT_REACHED();
713             }
714
715             callbackAggregator->addPendingCallback();
716             processPool->networkProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
717                 callbackAggregator->removePendingCallback();
718             });
719 #if ENABLE(RESOURCE_LOAD_STATISTICS)
720             didNotifyNetworkProcessToDeleteWebsiteData = true;
721 #endif
722         }
723     }
724
725     auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
726     if (webProcessAccessType != ProcessAccessType::None) {
727         for (auto& processPool : processPools()) {
728             processPool->clearSuspendedPages(AllowProcessCaching::No);
729             processPool->webProcessCache().clear();
730         }
731
732         for (auto& process : processes()) {
733             switch (webProcessAccessType) {
734             case ProcessAccessType::OnlyIfLaunched:
735                 if (process.state() != WebProcessProxy::State::Running)
736                     continue;
737                 break;
738
739             case ProcessAccessType::Launch:
740                 // FIXME: Handle this.
741                 ASSERT_NOT_REACHED();
742                 break;
743
744             case ProcessAccessType::None:
745                 ASSERT_NOT_REACHED();
746             }
747
748             callbackAggregator->addPendingCallback();
749             process.deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] {
750                 callbackAggregator->removePendingCallback();
751             });
752         }
753     }
754
755     if (dataTypes.contains(WebsiteDataType::DeviceIdHashSalt) || (dataTypes.contains(WebsiteDataType::Cookies))) {
756         callbackAggregator->addPendingCallback();
757
758         m_deviceIdHashSaltStorage->deleteDeviceIdHashSaltOriginsModifiedSince(modifiedSince, [callbackAggregator] {
759             callbackAggregator->removePendingCallback();
760         });
761     }
762
763     if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
764         callbackAggregator->addPendingCallback();
765
766         m_queue->dispatch([applicationCacheDirectory = m_configuration->applicationCacheDirectory().isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration->applicationCacheFlatFileSubdirectoryName().isolatedCopy(), callbackAggregator] {
767             auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
768
769             storage->deleteAllCaches();
770
771             WTF::RunLoop::main().dispatch([callbackAggregator] {
772                 callbackAggregator->removePendingCallback();
773             });
774         });
775     }
776
777     if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
778         callbackAggregator->addPendingCallback();
779
780         m_queue->dispatch([webSQLDatabaseDirectory = m_configuration->webSQLDatabaseDirectory().isolatedCopy(), callbackAggregator, modifiedSince] {
781             WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->deleteDatabasesModifiedSince(modifiedSince);
782
783             RunLoop::main().dispatch([callbackAggregator] {
784                 callbackAggregator->removePendingCallback();
785             });
786         });
787     }
788
789     if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
790         callbackAggregator->addPendingCallback();
791
792         m_queue->dispatch([mediaKeysStorageDirectory = m_configuration->mediaKeysStorageDirectory().isolatedCopy(), callbackAggregator, modifiedSince] {
793             removeMediaKeys(mediaKeysStorageDirectory, modifiedSince);
794
795             RunLoop::main().dispatch([callbackAggregator] {
796                 callbackAggregator->removePendingCallback();
797             });
798         });
799     }
800
801     if (dataTypes.contains(WebsiteDataType::SearchFieldRecentSearches) && isPersistent()) {
802         callbackAggregator->addPendingCallback();
803
804         m_queue->dispatch([modifiedSince, callbackAggregator] {
805             platformRemoveRecentSearches(modifiedSince);
806
807             RunLoop::main().dispatch([callbackAggregator] {
808                 callbackAggregator->removePendingCallback();
809             });
810         });
811     }
812
813 #if ENABLE(NETSCAPE_PLUGIN_API)
814     if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
815         class State {
816         public:
817             static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, WallTime modifiedSince)
818             {
819                 new State(WTFMove(callbackAggregator), WTFMove(plugins), modifiedSince);
820             }
821
822         private:
823             State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, WallTime modifiedSince)
824                 : m_callbackAggregator(WTFMove(callbackAggregator))
825                 , m_plugins(WTFMove(plugins))
826                 , m_modifiedSince(modifiedSince)
827             {
828                 m_callbackAggregator->addPendingCallback();
829
830                 deleteWebsiteDataForNextPlugin();
831             }
832
833             ~State()
834             {
835                 ASSERT(m_plugins.isEmpty());
836             }
837
838             void deleteWebsiteDataForNextPlugin()
839             {
840                 if (m_plugins.isEmpty()) {
841                     m_callbackAggregator->removePendingCallback();
842
843                     delete this;
844                     return;
845                 }
846
847                 auto plugin = m_plugins.takeLast();
848                 PluginProcessManager::singleton().deleteWebsiteData(plugin, m_modifiedSince, [this] {
849                     deleteWebsiteDataForNextPlugin();
850                 });
851             }
852
853             Ref<CallbackAggregator> m_callbackAggregator;
854             Vector<PluginModuleInfo> m_plugins;
855             WallTime m_modifiedSince;
856         };
857
858         State::deleteData(*callbackAggregator, plugins(), modifiedSince);
859     }
860 #endif
861
862 #if ENABLE(RESOURCE_LOAD_STATISTICS)
863     if (dataTypes.contains(WebsiteDataType::ResourceLoadStatistics)) {
864         if (!didNotifyNetworkProcessToDeleteWebsiteData) {
865             for (auto& processPool : processPools()) {
866                 if (auto* process = processPool->networkProcess()) {
867                     callbackAggregator->addPendingCallback();
868                     process->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] {
869                         callbackAggregator->removePendingCallback();
870                     });
871                 }
872             }
873         }
874
875         callbackAggregator->addPendingCallback();
876         clearResourceLoadStatisticsInWebProcesses([callbackAggregator] {
877             callbackAggregator->removePendingCallback();
878         });
879     }
880 #endif
881
882     // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
883     callbackAggregator->callIfNeeded();
884 }
885
886 void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, const Vector<WebsiteDataRecord>& dataRecords, Function<void()>&& completionHandler)
887 {
888     Vector<WebCore::SecurityOriginData> origins;
889
890     for (const auto& dataRecord : dataRecords) {
891         for (auto& origin : dataRecord.origins)
892             origins.append(origin);
893     }
894
895     struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
896         CallbackAggregator(WebsiteDataStore& dataStore, Function<void()>&& completionHandler)
897             : completionHandler(WTFMove(completionHandler))
898             , protectedDataStore(dataStore)
899         {
900             ASSERT(RunLoop::isMain());
901         }
902
903         ~CallbackAggregator()
904         {
905             // Make sure the data store gets destroyed on the main thread even though the CallbackAggregator can get destroyed on a background queue.
906             RunLoop::main().dispatch([protectedDataStore = WTFMove(protectedDataStore)] { });
907         }
908
909         void addPendingCallback()
910         {
911             pendingCallbacks++;
912         }
913
914         void removePendingCallback()
915         {
916             ASSERT(pendingCallbacks);
917             --pendingCallbacks;
918
919             callIfNeeded();
920         }
921
922         void callIfNeeded()
923         {
924             if (!pendingCallbacks)
925                 RunLoop::main().dispatch(WTFMove(completionHandler));
926         }
927
928         unsigned pendingCallbacks = 0;
929         Function<void()> completionHandler;
930         Ref<WebsiteDataStore> protectedDataStore;
931     };
932
933     RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(*this, WTFMove(completionHandler)));
934     
935     if (dataTypes.contains(WebsiteDataType::DiskCache)) {
936         HashSet<WebCore::SecurityOriginData> origins;
937         for (const auto& dataRecord : dataRecords) {
938             for (const auto& origin : dataRecord.origins)
939                 origins.add(origin);
940         }
941         
942 #if ENABLE(VIDEO)
943         callbackAggregator->addPendingCallback();
944         m_queue->dispatch([origins = WTFMove(origins), mediaCacheDirectory = m_configuration->mediaCacheDirectory().isolatedCopy(), callbackAggregator] {
945
946             // FIXME: Move SecurityOrigin::toRawString to SecurityOriginData and
947             // make HTMLMediaElement::clearMediaCacheForOrigins take SecurityOriginData.
948             HashSet<RefPtr<WebCore::SecurityOrigin>> securityOrigins;
949             for (auto& origin : origins)
950                 securityOrigins.add(origin.securityOrigin());
951             WebCore::HTMLMediaElement::clearMediaCacheForOrigins(mediaCacheDirectory, securityOrigins);
952             
953             WTF::RunLoop::main().dispatch([callbackAggregator] {
954                 callbackAggregator->removePendingCallback();
955             });
956         });
957 #endif
958     }
959     
960     auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
961     if (networkProcessAccessType != ProcessAccessType::None) {
962         for (auto& processPool : processPools()) {
963             switch (networkProcessAccessType) {
964             case ProcessAccessType::OnlyIfLaunched:
965                 if (!processPool->networkProcess())
966                     continue;
967                 break;
968
969             case ProcessAccessType::Launch:
970                 processPool->ensureNetworkProcess(this);
971                 break;
972
973             case ProcessAccessType::None:
974                 ASSERT_NOT_REACHED();
975             }
976
977             Vector<String> cookieHostNames;
978             Vector<String> HSTSCacheHostNames;
979             for (const auto& dataRecord : dataRecords) {
980                 for (auto& hostName : dataRecord.cookieHostNames)
981                     cookieHostNames.append(hostName);
982                 for (auto& hostName : dataRecord.HSTSCacheHostNames)
983                     HSTSCacheHostNames.append(hostName);
984             }
985
986             callbackAggregator->addPendingCallback();
987             processPool->networkProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, cookieHostNames, HSTSCacheHostNames, [callbackAggregator, processPool] {
988                 callbackAggregator->removePendingCallback();
989             });
990         }
991     }
992
993     auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
994     if (webProcessAccessType != ProcessAccessType::None) {
995         for (auto& process : processes()) {
996             switch (webProcessAccessType) {
997             case ProcessAccessType::OnlyIfLaunched:
998                 if (process.state() != WebProcessProxy::State::Running)
999                     continue;
1000                 break;
1001
1002             case ProcessAccessType::Launch:
1003                 // FIXME: Handle this.
1004                 ASSERT_NOT_REACHED();
1005                 break;
1006
1007             case ProcessAccessType::None:
1008                 ASSERT_NOT_REACHED();
1009             }
1010
1011             callbackAggregator->addPendingCallback();
1012
1013             process.deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator] {
1014                 callbackAggregator->removePendingCallback();
1015             });
1016         }
1017     }
1018
1019     if (dataTypes.contains(WebsiteDataType::DeviceIdHashSalt) || (dataTypes.contains(WebsiteDataType::Cookies))) {
1020         callbackAggregator->addPendingCallback();
1021
1022         m_deviceIdHashSaltStorage->deleteDeviceIdHashSaltForOrigins(origins, [callbackAggregator] {
1023             callbackAggregator->removePendingCallback();
1024         });
1025     }
1026
1027     if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
1028         HashSet<WebCore::SecurityOriginData> origins;
1029         for (const auto& dataRecord : dataRecords) {
1030             for (const auto& origin : dataRecord.origins)
1031                 origins.add(origin);
1032         }
1033
1034         callbackAggregator->addPendingCallback();
1035         m_queue->dispatch([origins = WTFMove(origins), applicationCacheDirectory = m_configuration->applicationCacheDirectory().isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration->applicationCacheFlatFileSubdirectoryName().isolatedCopy(), callbackAggregator] {
1036             auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
1037
1038             for (const auto& origin : origins)
1039                 storage->deleteCacheForOrigin(origin.securityOrigin());
1040
1041             WTF::RunLoop::main().dispatch([callbackAggregator] {
1042                 callbackAggregator->removePendingCallback();
1043             });
1044         });
1045     }
1046
1047     if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
1048         HashSet<WebCore::SecurityOriginData> origins;
1049         for (const auto& dataRecord : dataRecords) {
1050             for (const auto& origin : dataRecord.origins)
1051                 origins.add(origin);
1052         }
1053
1054         callbackAggregator->addPendingCallback();
1055         m_queue->dispatch([origins = WTFMove(origins), callbackAggregator, webSQLDatabaseDirectory = m_configuration->webSQLDatabaseDirectory().isolatedCopy()] {
1056             auto databaseTracker = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory);
1057             for (auto& origin : origins)
1058                 databaseTracker->deleteOrigin(origin);
1059             RunLoop::main().dispatch([callbackAggregator] {
1060                 callbackAggregator->removePendingCallback();
1061             });
1062         });
1063     }
1064
1065     if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
1066         HashSet<WebCore::SecurityOriginData> origins;
1067         for (const auto& dataRecord : dataRecords) {
1068             for (const auto& origin : dataRecord.origins)
1069                 origins.add(origin);
1070         }
1071
1072         callbackAggregator->addPendingCallback();
1073         m_queue->dispatch([mediaKeysStorageDirectory = m_configuration->mediaKeysStorageDirectory().isolatedCopy(), callbackAggregator, origins = WTFMove(origins)] {
1074
1075             removeMediaKeys(mediaKeysStorageDirectory, origins);
1076
1077             RunLoop::main().dispatch([callbackAggregator] {
1078                 callbackAggregator->removePendingCallback();
1079             });
1080         });
1081     }
1082
1083 #if ENABLE(NETSCAPE_PLUGIN_API)
1084     if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
1085         Vector<String> hostNames;
1086         for (const auto& dataRecord : dataRecords) {
1087             for (const auto& hostName : dataRecord.pluginDataHostNames)
1088                 hostNames.append(hostName);
1089         }
1090
1091
1092         class State {
1093         public:
1094             static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1095             {
1096                 new State(WTFMove(callbackAggregator), WTFMove(plugins), WTFMove(hostNames));
1097             }
1098
1099         private:
1100             State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1101                 : m_callbackAggregator(WTFMove(callbackAggregator))
1102                 , m_plugins(WTFMove(plugins))
1103                 , m_hostNames(WTFMove(hostNames))
1104             {
1105                 m_callbackAggregator->addPendingCallback();
1106
1107                 deleteWebsiteDataForNextPlugin();
1108             }
1109
1110             ~State()
1111             {
1112                 ASSERT(m_plugins.isEmpty());
1113             }
1114
1115             void deleteWebsiteDataForNextPlugin()
1116             {
1117                 if (m_plugins.isEmpty()) {
1118                     m_callbackAggregator->removePendingCallback();
1119
1120                     delete this;
1121                     return;
1122                 }
1123
1124                 auto plugin = m_plugins.takeLast();
1125                 PluginProcessManager::singleton().deleteWebsiteDataForHostNames(plugin, m_hostNames, [this] {
1126                     deleteWebsiteDataForNextPlugin();
1127                 });
1128             }
1129
1130             Ref<CallbackAggregator> m_callbackAggregator;
1131             Vector<PluginModuleInfo> m_plugins;
1132             Vector<String> m_hostNames;
1133         };
1134
1135         if (!hostNames.isEmpty())
1136             State::deleteData(*callbackAggregator, plugins(), WTFMove(hostNames));
1137     }
1138 #endif
1139
1140     // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
1141     callbackAggregator->callIfNeeded();
1142 }
1143
1144 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1145 void WebsiteDataStore::setMaxStatisticsEntries(size_t maximumEntryCount, CompletionHandler<void()>&& completionHandler)
1146 {
1147     ASSERT(RunLoop::isMain());
1148
1149     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1150
1151     for (auto& processPool : processPools())
1152         processPool->ensureNetworkProcess().setMaxStatisticsEntries(m_sessionID, maximumEntryCount, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1153 }
1154
1155 void WebsiteDataStore::setPruneEntriesDownTo(size_t pruneTargetCount, CompletionHandler<void()>&& completionHandler)
1156 {
1157     ASSERT(RunLoop::isMain());
1158     
1159     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1160
1161     for (auto& processPool : processPools()) {
1162         processPool->ensureNetworkProcess().setPruneEntriesDownTo(m_sessionID, pruneTargetCount, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1163     }
1164 }
1165
1166 void WebsiteDataStore::setGrandfatheringTime(Seconds seconds, CompletionHandler<void()>&& completionHandler)
1167 {
1168     ASSERT(RunLoop::isMain());
1169
1170     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1171
1172     for (auto& processPool : processPools())
1173         processPool->ensureNetworkProcess().setGrandfatheringTime(m_sessionID, seconds, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1174 }
1175
1176 void WebsiteDataStore::setMinimumTimeBetweenDataRecordsRemoval(Seconds seconds, CompletionHandler<void()>&& completionHandler)
1177 {
1178     ASSERT(RunLoop::isMain());
1179
1180     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1181
1182     for (auto& processPool : processPools())
1183         processPool->ensureNetworkProcess().setMinimumTimeBetweenDataRecordsRemoval(m_sessionID, seconds, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1184 }
1185     
1186 void WebsiteDataStore::dumpResourceLoadStatistics(CompletionHandler<void(const String&)>&& completionHandler)
1187 {
1188     ASSERT(RunLoop::isMain());
1189
1190     for (auto& processPool : processPools()) {
1191         if (auto* process = processPool->networkProcess()) {
1192             process->dumpResourceLoadStatistics(m_sessionID, WTFMove(completionHandler));
1193             RELEASE_ASSERT(processPools().size() == 1);
1194             break;
1195         }
1196     }
1197 }
1198
1199 void WebsiteDataStore::isPrevalentResource(const URL& url, CompletionHandler<void(bool isPrevalent)>&& completionHandler)
1200 {
1201     ASSERT(RunLoop::isMain());
1202     
1203     if (url.protocolIsAbout() || url.isEmpty()) {
1204         completionHandler(false);
1205         return;
1206     }
1207
1208     for (auto& processPool : processPools()) {
1209         if (auto* process = processPool->networkProcess()) {
1210             process->isPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1211             RELEASE_ASSERT(processPools().size() == 1);
1212             break;
1213         }
1214     }
1215 }
1216
1217 void WebsiteDataStore::isGrandfathered(const URL& url, CompletionHandler<void(bool isPrevalent)>&& completionHandler)
1218 {
1219     ASSERT(RunLoop::isMain());
1220     
1221     if (url.protocolIsAbout() || url.isEmpty()) {
1222         completionHandler(false);
1223         return;
1224     }
1225
1226     for (auto& processPool : processPools()) {
1227         if (auto* process = processPool->networkProcess()) {
1228             process->isGrandfathered(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1229             RELEASE_ASSERT(processPools().size() == 1);
1230             break;
1231         }
1232     }
1233 }
1234
1235 void WebsiteDataStore::setPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
1236 {
1237     ASSERT(RunLoop::isMain());
1238     
1239     if (url.protocolIsAbout() || url.isEmpty()) {
1240         completionHandler();
1241         return;
1242     }
1243     
1244     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1245
1246     for (auto& processPool : processPools()) {
1247         processPool->ensureNetworkProcess().setPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1248     }
1249 }
1250
1251 void WebsiteDataStore::setPrevalentResourceForDebugMode(const URL& url, CompletionHandler<void()>&& completionHandler)
1252 {
1253     ASSERT(RunLoop::isMain());
1254     
1255     if (url.protocolIsAbout() || url.isEmpty()) {
1256         completionHandler();
1257         return;
1258     }
1259     
1260     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1261     
1262     for (auto& processPool : processPools()) {
1263         if (auto* process = processPool->networkProcess())
1264             process->setPrevalentResourceForDebugMode(m_sessionID, WebCore::RegistrableDomain { url }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1265     }
1266 }
1267
1268 void WebsiteDataStore::isVeryPrevalentResource(const URL& url, CompletionHandler<void(bool isVeryPrevalent)>&& completionHandler)
1269 {
1270     ASSERT(RunLoop::isMain());
1271     
1272     if (url.protocolIsAbout() || url.isEmpty()) {
1273         completionHandler(false);
1274         return;
1275     }
1276     
1277     for (auto& processPool : processPools()) {
1278         if (auto* process = processPool->networkProcess()) {
1279             process->isVeryPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1280             ASSERT(processPools().size() == 1);
1281             break;
1282         }
1283     }
1284 }
1285
1286 void WebsiteDataStore::setVeryPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
1287 {
1288     ASSERT(RunLoop::isMain());
1289     
1290     if (url.protocolIsAbout() || url.isEmpty()) {
1291         completionHandler();
1292         return;
1293     }
1294     
1295     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1296     
1297     for (auto& processPool : processPools()) {
1298         if (auto* process = processPool->networkProcess())
1299             process->setVeryPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1300     }
1301 }
1302
1303 void WebsiteDataStore::setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value, CompletionHandler<void()>&& completionHandler)
1304 {
1305     ASSERT(RunLoop::isMain());
1306     
1307     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1308
1309     for (auto& processPool : processPools())
1310         processPool->ensureNetworkProcess().setShouldClassifyResourcesBeforeDataRecordsRemoval(m_sessionID, value, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1311 }
1312
1313 void WebsiteDataStore::setSubframeUnderTopFrameDomain(const URL& subFrameURL, const URL& topFrameURL, CompletionHandler<void()>&& completionHandler)
1314 {
1315     ASSERT(RunLoop::isMain());
1316     
1317     if (subFrameURL.protocolIsAbout() || subFrameURL.isEmpty() || topFrameURL.protocolIsAbout() || topFrameURL.isEmpty()) {
1318         completionHandler();
1319         return;
1320     }
1321
1322     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1323     
1324     for (auto& processPool : processPools()) {
1325         if (auto* process = processPool->networkProcess())
1326             process->setSubframeUnderTopFrameDomain(m_sessionID, WebCore::RegistrableDomain { subFrameURL }, WebCore::RegistrableDomain { topFrameURL }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1327     }
1328 }
1329
1330 void WebsiteDataStore::isRegisteredAsSubFrameUnder(const URL& subFrameURL, const URL& topFrameURL, CompletionHandler<void(bool)>&& completionHandler)
1331 {
1332     ASSERT(RunLoop::isMain());
1333
1334     for (auto& processPool : processPools()) {
1335         if (auto* process = processPool->networkProcess()) {
1336             process->isRegisteredAsSubFrameUnder(m_sessionID, WebCore::RegistrableDomain { subFrameURL }, WebCore::RegistrableDomain { topFrameURL }, WTFMove(completionHandler));
1337             ASSERT(processPools().size() == 1);
1338             break;
1339         }
1340     }
1341 }
1342
1343 void WebsiteDataStore::setSubresourceUnderTopFrameDomain(const URL& subresourceURL, const URL& topFrameURL, CompletionHandler<void()>&& completionHandler)
1344 {
1345     ASSERT(RunLoop::isMain());
1346     
1347     if (subresourceURL.protocolIsAbout() || subresourceURL.isEmpty() || topFrameURL.protocolIsAbout() || topFrameURL.isEmpty()) {
1348         completionHandler();
1349         return;
1350     }
1351
1352     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1353     
1354     for (auto& processPool : processPools()) {
1355         if (auto* process = processPool->networkProcess())
1356             process->setSubresourceUnderTopFrameDomain(m_sessionID, WebCore::RegistrableDomain { subresourceURL }, WebCore::RegistrableDomain { topFrameURL }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1357     }
1358 }
1359
1360 void WebsiteDataStore::isRegisteredAsSubresourceUnder(const URL& subresourceURL, const URL& topFrameURL, CompletionHandler<void(bool)>&& completionHandler)
1361 {
1362     ASSERT(RunLoop::isMain());
1363     
1364     for (auto& processPool : processPools()) {
1365         if (auto* process = processPool->networkProcess()) {
1366             process->isRegisteredAsSubresourceUnder(m_sessionID, WebCore::RegistrableDomain { subresourceURL }, WebCore::RegistrableDomain { topFrameURL }, WTFMove(completionHandler));
1367             ASSERT(processPools().size() == 1);
1368             break;
1369         }
1370     }
1371 }
1372
1373 void WebsiteDataStore::setSubresourceUniqueRedirectTo(const URL& subresourceURL, const URL& urlRedirectedTo, CompletionHandler<void()>&& completionHandler)
1374 {
1375     ASSERT(RunLoop::isMain());
1376     
1377     if (subresourceURL.protocolIsAbout() || subresourceURL.isEmpty() || urlRedirectedTo.protocolIsAbout() || urlRedirectedTo.isEmpty()) {
1378         completionHandler();
1379         return;
1380     }
1381
1382     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1383     
1384     for (auto& processPool : processPools()) {
1385         if (auto* process = processPool->networkProcess())
1386             process->setSubresourceUniqueRedirectTo(m_sessionID, WebCore::RegistrableDomain { subresourceURL }, WebCore::RegistrableDomain { urlRedirectedTo }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1387     }
1388 }
1389
1390 void WebsiteDataStore::setSubresourceUniqueRedirectFrom(const URL& subresourceURL, const URL& urlRedirectedFrom, CompletionHandler<void()>&& completionHandler)
1391 {
1392     ASSERT(RunLoop::isMain());
1393     
1394     if (subresourceURL.protocolIsAbout() || subresourceURL.isEmpty() || urlRedirectedFrom.protocolIsAbout() || urlRedirectedFrom.isEmpty()) {
1395         completionHandler();
1396         return;
1397     }
1398
1399     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1400     
1401     for (auto& processPool : processPools()) {
1402         if (auto* process = processPool->networkProcess())
1403             process->setSubresourceUniqueRedirectFrom(m_sessionID, WebCore::RegistrableDomain { subresourceURL }, WebCore::RegistrableDomain { urlRedirectedFrom }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1404     }
1405 }
1406
1407 void WebsiteDataStore::setTopFrameUniqueRedirectTo(const URL& topFrameURL, const URL& urlRedirectedTo, CompletionHandler<void()>&& completionHandler)
1408 {
1409     ASSERT(RunLoop::isMain());
1410     
1411     if (topFrameURL.protocolIsAbout() || topFrameURL.isEmpty() || urlRedirectedTo.protocolIsAbout() || urlRedirectedTo.isEmpty()) {
1412         completionHandler();
1413         return;
1414     }
1415
1416     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1417     
1418     for (auto& processPool : processPools()) {
1419         if (auto* process = processPool->networkProcess())
1420             process->setTopFrameUniqueRedirectTo(m_sessionID, WebCore::RegistrableDomain { topFrameURL }, WebCore::RegistrableDomain { urlRedirectedTo }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1421     }
1422 }
1423
1424 void WebsiteDataStore::setTopFrameUniqueRedirectFrom(const URL& topFrameURL, const URL& urlRedirectedFrom, CompletionHandler<void()>&& completionHandler)
1425 {
1426     ASSERT(RunLoop::isMain());
1427     
1428     if (topFrameURL.protocolIsAbout() || topFrameURL.isEmpty() || urlRedirectedFrom.protocolIsAbout() || urlRedirectedFrom.isEmpty()) {
1429         completionHandler();
1430         return;
1431     }
1432
1433     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1434     
1435     for (auto& processPool : processPools()) {
1436         if (auto* process = processPool->networkProcess())
1437             process->setTopFrameUniqueRedirectFrom(m_sessionID, WebCore::RegistrableDomain { topFrameURL }, WebCore::RegistrableDomain { urlRedirectedFrom }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1438     }
1439 }
1440
1441 void WebsiteDataStore::isRegisteredAsRedirectingTo(const URL& urlRedirectedFrom, const URL& urlRedirectedTo, CompletionHandler<void(bool)>&& completionHandler)
1442 {
1443     ASSERT(RunLoop::isMain());
1444     
1445     for (auto& processPool : processPools()) {
1446         if (auto* process = processPool->networkProcess()) {
1447             process->isRegisteredAsRedirectingTo(m_sessionID, WebCore::RegistrableDomain { urlRedirectedFrom }, WebCore::RegistrableDomain { urlRedirectedTo }, WTFMove(completionHandler));
1448             ASSERT(processPools().size() == 1);
1449             break;
1450         }
1451     }
1452 }
1453
1454 void WebsiteDataStore::clearPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
1455 {
1456     ASSERT(RunLoop::isMain());
1457         
1458     if (url.protocolIsAbout() || url.isEmpty()) {
1459         completionHandler();
1460         return;
1461     }
1462
1463     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1464
1465     for (auto& processPool : processPools()) {
1466         if (auto* process = processPool->networkProcess())
1467             process->clearPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1468     }
1469 }
1470
1471 void WebsiteDataStore::resetParametersToDefaultValues(CompletionHandler<void()>&& completionHandler)
1472 {
1473     ASSERT(RunLoop::isMain());
1474
1475     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1476     
1477     for (auto& processPool : processPools()) {
1478         if (auto* process = processPool->networkProcess())
1479             process->resetParametersToDefaultValues(m_sessionID, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1480     }
1481 }
1482
1483 void WebsiteDataStore::submitTelemetry()
1484 {
1485     ASSERT(RunLoop::isMain());
1486     
1487     for (auto& processPool : processPools()) {
1488         if (auto* process = processPool->networkProcess())
1489             process->submitTelemetry(m_sessionID, [] { });
1490     }
1491 }
1492
1493 void WebsiteDataStore::scheduleClearInMemoryAndPersistent(WallTime modifiedSince, ShouldGrandfatherStatistics shouldGrandfather, CompletionHandler<void()>&& completionHandler)
1494 {
1495     ASSERT(RunLoop::isMain());
1496     
1497     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1498
1499     for (auto& processPool : processPools()) {
1500         if (auto* process = processPool->networkProcess())
1501             process->scheduleClearInMemoryAndPersistent(m_sessionID, modifiedSince, shouldGrandfather, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1502     }
1503 }
1504
1505 void WebsiteDataStore::scheduleClearInMemoryAndPersistent(ShouldGrandfatherStatistics shouldGrandfather, CompletionHandler<void()>&& completionHandler)
1506 {
1507     ASSERT(RunLoop::isMain());
1508     
1509     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1510
1511     for (auto& processPool : processPools()) {
1512         if (auto* process = processPool->networkProcess())
1513             process->scheduleClearInMemoryAndPersistent(m_sessionID, { }, shouldGrandfather, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1514     }
1515 }
1516
1517 void WebsiteDataStore::scheduleCookieBlockingUpdate(CompletionHandler<void()>&& completionHandler)
1518 {
1519     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1520
1521     for (auto& processPool : processPools()) {
1522         if (auto* process = processPool->networkProcess())
1523             process->scheduleCookieBlockingUpdate(m_sessionID, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1524     }
1525 }
1526
1527 void WebsiteDataStore::scheduleStatisticsAndDataRecordsProcessing(CompletionHandler<void()>&& completionHandler)
1528 {
1529     ASSERT(RunLoop::isMain());
1530     
1531     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1532     
1533     for (auto& processPool : processPools()) {
1534         if (auto* process = processPool->networkProcess())
1535             process->scheduleStatisticsAndDataRecordsProcessing(m_sessionID, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1536     }
1537 }
1538
1539 void WebsiteDataStore::setLastSeen(const URL& url, Seconds seconds, CompletionHandler<void()>&& completionHandler)
1540 {
1541     if (url.protocolIsAbout() || url.isEmpty()) {
1542         completionHandler();
1543         return;
1544     }
1545
1546     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1547
1548     for (auto& processPool : processPools()) {
1549         if (auto* process = processPool->networkProcess())
1550             process->setLastSeen(m_sessionID, WebCore::RegistrableDomain { url }, seconds, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1551     }
1552 }
1553
1554 void WebsiteDataStore::mergeStatisticForTesting(const URL& url , const URL& topFrameUrl1, const URL& topFrameUrl2, Seconds lastSeen, bool hadUserInteraction, Seconds mostRecentUserInteraction, bool isGrandfathered, bool isPrevalent, bool isVeryPrevalent, unsigned dataRecordsRemoved, CompletionHandler<void()>&& completionHandler)
1555 {
1556     if (url.protocolIsAbout() || url.isEmpty()) {
1557         completionHandler();
1558         return;
1559     }
1560
1561     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1562
1563     for (auto& processPool : processPools()) {
1564         if (auto* process = processPool->networkProcess())
1565             process->mergeStatisticForTesting(m_sessionID, WebCore::RegistrableDomain { url }, WebCore::RegistrableDomain { topFrameUrl1 }, WebCore::RegistrableDomain { topFrameUrl2 }, lastSeen, hadUserInteraction, mostRecentUserInteraction, isGrandfathered, isPrevalent, isVeryPrevalent, dataRecordsRemoved, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1566     }
1567 }
1568
1569 void WebsiteDataStore::setNotifyPagesWhenDataRecordsWereScanned(bool value, CompletionHandler<void()>&& completionHandler)
1570 {
1571     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1572
1573     for (auto& processPool : processPools())
1574         processPool->ensureNetworkProcess().setNotifyPagesWhenDataRecordsWereScanned(m_sessionID, value, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1575 }
1576
1577 void WebsiteDataStore::setIsRunningResourceLoadStatisticsTest(bool value, CompletionHandler<void()>&& completionHandler)
1578 {
1579     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1580     
1581     for (auto& processPool : processPools())
1582         processPool->ensureNetworkProcess().setIsRunningResourceLoadStatisticsTest(m_sessionID, value, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1583 }
1584
1585 void WebsiteDataStore::setNotifyPagesWhenTelemetryWasCaptured(bool value, CompletionHandler<void()>&& completionHandler)
1586 {
1587     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1588     
1589     for (auto& processPool : processPools())
1590         processPool->ensureNetworkProcess().setNotifyPagesWhenTelemetryWasCaptured(m_sessionID, value, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1591 }
1592
1593 void WebsiteDataStore::getAllStorageAccessEntries(WebPageProxyIdentifier pageID, CompletionHandler<void(Vector<String>&& domains)>&& completionHandler)
1594 {
1595     auto* webPage = WebProcessProxy::webPage(pageID);
1596     if (!webPage) {
1597         completionHandler({ });
1598         return;
1599     }
1600     
1601     auto& networkProcess = webPage->process().processPool().ensureNetworkProcess();
1602     networkProcess.getAllStorageAccessEntries(m_sessionID, WTFMove(completionHandler));
1603 }
1604
1605
1606 void WebsiteDataStore::setTimeToLiveUserInteraction(Seconds seconds, CompletionHandler<void()>&& completionHandler)
1607 {
1608     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1609     
1610     for (auto& processPool : processPools())
1611         processPool->ensureNetworkProcess().setTimeToLiveUserInteraction(m_sessionID, seconds, [callbackAggregator = callbackAggregator.copyRef()] { });
1612 }
1613
1614 void WebsiteDataStore::logUserInteraction(const URL& url, CompletionHandler<void()>&& completionHandler)
1615 {
1616     ASSERT(RunLoop::isMain());
1617     
1618     if (url.protocolIsAbout() || url.isEmpty()) {
1619         completionHandler();
1620         return;
1621     }
1622     
1623     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1624
1625     for (auto& processPool : processPools()) {
1626         if (auto* process = processPool->networkProcess())
1627             process->logUserInteraction(m_sessionID, WebCore::RegistrableDomain { url }, [callbackAggregator = callbackAggregator.copyRef()] { });
1628     }
1629 }
1630
1631 void WebsiteDataStore::hasHadUserInteraction(const URL& url, CompletionHandler<void(bool)>&& completionHandler)
1632 {
1633     ASSERT(RunLoop::isMain());
1634     
1635     if (url.protocolIsAbout() || url.isEmpty()) {
1636         completionHandler(false);
1637         return;
1638     }
1639     
1640     for (auto& processPool : processPools()) {
1641         if (auto* process = processPool->networkProcess()) {
1642             process->hasHadUserInteraction(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1643             ASSERT(processPools().size() == 1);
1644             break;
1645         }
1646     }
1647 }
1648
1649 void WebsiteDataStore::isRelationshipOnlyInDatabaseOnce(const URL& subUrl, const URL& topUrl, CompletionHandler<void(bool)>&& completionHandler)
1650 {
1651     ASSERT(RunLoop::isMain());
1652     
1653     if (subUrl.protocolIsAbout() || subUrl.isEmpty() || topUrl.protocolIsAbout() || topUrl.isEmpty()) {
1654         completionHandler(false);
1655         return;
1656     }
1657     
1658     for (auto& processPool : processPools()) {
1659         if (auto* process = processPool->networkProcess()) {
1660             process->isRelationshipOnlyInDatabaseOnce(m_sessionID, WebCore::RegistrableDomain { subUrl }, WebCore::RegistrableDomain { topUrl }, WTFMove(completionHandler));
1661             ASSERT(processPools().size() == 1);
1662             break;
1663         }
1664     }
1665 }
1666
1667 void WebsiteDataStore::clearUserInteraction(const URL& url, CompletionHandler<void()>&& completionHandler)
1668 {
1669     ASSERT(RunLoop::isMain());
1670     
1671     if (url.protocolIsAbout() || url.isEmpty()) {
1672         completionHandler();
1673         return;
1674     }
1675     
1676     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1677
1678     for (auto& processPool : processPools()) {
1679         if (auto* process = processPool->networkProcess())
1680             process->clearUserInteraction(m_sessionID, WebCore::RegistrableDomain { url }, [callbackAggregator = callbackAggregator.copyRef()] { });
1681     }
1682 }
1683
1684 void WebsiteDataStore::setGrandfathered(const URL& url, bool isGrandfathered, CompletionHandler<void()>&& completionHandler)
1685 {
1686     ASSERT(RunLoop::isMain());
1687     
1688     if (url.protocolIsAbout() || url.isEmpty()) {
1689         completionHandler();
1690         return;
1691     }
1692     
1693     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1694     
1695     for (auto& processPool : processPools()) {
1696         if (auto* process = processPool->networkProcess())
1697             process->setGrandfathered(m_sessionID, WebCore::RegistrableDomain { url }, isGrandfathered, [callbackAggregator = callbackAggregator.copyRef()] { });
1698     }
1699 }
1700
1701 void WebsiteDataStore::setUseITPDatabase(bool value)
1702 {
1703     ASSERT(RunLoop::isMain());
1704
1705     for (auto& processPool : processPools())
1706         processPool->ensureNetworkProcess().setUseITPDatabase(m_sessionID, value);
1707 }
1708
1709 void WebsiteDataStore::setCrossSiteLoadWithLinkDecorationForTesting(const URL& fromURL, const URL& toURL, CompletionHandler<void()>&& completionHandler)
1710 {
1711     ASSERT(RunLoop::isMain());
1712     
1713     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1714     
1715     for (auto& processPool : processPools()) {
1716         if (auto* process = processPool->networkProcess())
1717             process->setCrossSiteLoadWithLinkDecorationForTesting(m_sessionID, WebCore::RegistrableDomain { fromURL }, WebCore::RegistrableDomain { toURL }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1718     }
1719 }
1720
1721 void WebsiteDataStore::resetCrossSiteLoadsWithLinkDecorationForTesting(CompletionHandler<void()>&& completionHandler)
1722 {
1723     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1724     
1725     for (auto& processPool : processPools()) {
1726         if (auto* networkProcess = processPool->networkProcess())
1727             networkProcess->resetCrossSiteLoadsWithLinkDecorationForTesting(m_sessionID, [callbackAggregator = callbackAggregator.copyRef()] { });
1728     }
1729 }
1730
1731 void WebsiteDataStore::deleteCookiesForTesting(const URL& url, bool includeHttpOnlyCookies, CompletionHandler<void()>&& completionHandler)
1732 {
1733     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1734     
1735     for (auto& processPool : processPools()) {
1736         if (auto* networkProcess = processPool->networkProcess())
1737             networkProcess->deleteCookiesForTesting(m_sessionID, WebCore::RegistrableDomain { url }, includeHttpOnlyCookies, [callbackAggregator = callbackAggregator.copyRef()] { });
1738     }
1739 }
1740
1741 void WebsiteDataStore::hasLocalStorageForTesting(const URL& url, CompletionHandler<void(bool)>&& completionHandler) const
1742 {
1743     for (auto& processPool : processPools()) {
1744         if (auto* networkProcess = processPool->networkProcess()) {
1745             networkProcess->hasLocalStorage(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1746             ASSERT(processPools().size() == 1);
1747             break;
1748         }
1749     }
1750     ASSERT(!completionHandler);
1751 }
1752
1753 void WebsiteDataStore::hasIsolatedSessionForTesting(const URL& url, CompletionHandler<void(bool)>&& completionHandler) const
1754 {
1755     for (auto& processPool : processPools()) {
1756         if (auto* networkProcess = processPool->networkProcess()) {
1757             networkProcess->hasIsolatedSession(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1758             ASSERT(processPools().size() == 1);
1759             break;
1760         }
1761     }
1762     ASSERT(!completionHandler);
1763 }
1764
1765 void WebsiteDataStore::setResourceLoadStatisticsShouldDowngradeReferrerForTesting(bool enabled, CompletionHandler<void()>&& completionHandler)
1766 {
1767     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1768     
1769     for (auto& processPool : processPools()) {
1770         if (auto* networkProcess = processPool->networkProcess()) {
1771             networkProcess->setShouldDowngradeReferrerForTesting(enabled, [callbackAggregator = callbackAggregator.copyRef()] { });
1772             ASSERT(processPools().size() == 1);
1773             break;
1774         }
1775     }
1776     ASSERT(!completionHandler);
1777 }
1778 #endif // ENABLE(RESOURCE_LOAD_STATISTICS)
1779
1780 void WebsiteDataStore::setCacheMaxAgeCapForPrevalentResources(Seconds seconds, CompletionHandler<void()>&& completionHandler)
1781 {
1782 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1783     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1784     
1785     for (auto& processPool : processPools())
1786         processPool->ensureNetworkProcess().setCacheMaxAgeCapForPrevalentResources(m_sessionID, seconds, [callbackAggregator = callbackAggregator.copyRef()] { });
1787 #else
1788     UNUSED_PARAM(seconds);
1789     completionHandler();
1790 #endif
1791 }
1792
1793 void WebsiteDataStore::resetCacheMaxAgeCapForPrevalentResources(CompletionHandler<void()>&& completionHandler)
1794 {
1795 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1796     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1797     
1798     for (auto& processPool : processPools()) {
1799         if (auto* networkProcess = processPool->networkProcess())
1800             networkProcess->resetCacheMaxAgeCapForPrevalentResources(m_sessionID, [callbackAggregator = callbackAggregator.copyRef()] { });
1801     }
1802 #else
1803     completionHandler();
1804 #endif
1805 }
1806
1807 bool WebsiteDataStore::isAssociatedProcessPool(WebProcessPool& processPool) const
1808 {
1809     if (auto* processPoolDataStore = processPool.websiteDataStore())
1810         return processPoolDataStore == this;
1811     return false;
1812 }
1813
1814 HashSet<RefPtr<WebProcessPool>> WebsiteDataStore::processPools(size_t count, bool ensureAPoolExists) const
1815 {
1816     HashSet<RefPtr<WebProcessPool>> processPools;
1817     for (auto& process : processes()) {
1818         if (auto* processPool = process.processPoolIfExists())
1819             processPools.add(processPool);
1820     }
1821
1822     if (processPools.isEmpty()) {
1823         // Check if we're one of the legacy data stores.
1824         for (auto& processPool : WebProcessPool::allProcessPools()) {
1825             if (!isAssociatedProcessPool(*processPool))
1826                 continue;
1827
1828             processPools.add(processPool);
1829
1830             if (processPools.size() == count)
1831                 break;
1832         }
1833     }
1834
1835     if (processPools.isEmpty() && count && ensureAPoolExists) {
1836         auto processPool = WebProcessPool::create(API::ProcessPoolConfiguration::create());
1837         processPools.add(processPool.ptr());
1838     }
1839
1840     return processPools;
1841 }
1842
1843 #if ENABLE(NETSCAPE_PLUGIN_API)
1844 Vector<PluginModuleInfo> WebsiteDataStore::plugins() const
1845 {
1846     Vector<PluginModuleInfo> plugins;
1847
1848     for (auto& processPool : processPools()) {
1849         for (auto& plugin : processPool->pluginInfoStore().plugins())
1850             plugins.append(plugin);
1851     }
1852
1853     return plugins;
1854 }
1855 #endif
1856
1857 static String computeMediaKeyFile(const String& mediaKeyDirectory)
1858 {
1859     return FileSystem::pathByAppendingComponent(mediaKeyDirectory, "SecureStop.plist");
1860 }
1861
1862 Vector<WebCore::SecurityOriginData> WebsiteDataStore::mediaKeyOrigins(const String& mediaKeysStorageDirectory)
1863 {
1864     ASSERT(!mediaKeysStorageDirectory.isEmpty());
1865
1866     Vector<WebCore::SecurityOriginData> origins;
1867
1868     for (const auto& originPath : FileSystem::listDirectory(mediaKeysStorageDirectory, "*")) {
1869         auto mediaKeyFile = computeMediaKeyFile(originPath);
1870         if (!FileSystem::fileExists(mediaKeyFile))
1871             continue;
1872
1873         auto mediaKeyIdentifier = FileSystem::pathGetFileName(originPath);
1874
1875         if (auto securityOrigin = WebCore::SecurityOriginData::fromDatabaseIdentifier(mediaKeyIdentifier))
1876             origins.append(*securityOrigin);
1877     }
1878
1879     return origins;
1880 }
1881
1882 void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, WallTime modifiedSince)
1883 {
1884     ASSERT(!mediaKeysStorageDirectory.isEmpty());
1885
1886     for (const auto& mediaKeyDirectory : FileSystem::listDirectory(mediaKeysStorageDirectory, "*")) {
1887         auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1888
1889         auto modificationTime = FileSystem::getFileModificationTime(mediaKeyFile);
1890         if (!modificationTime)
1891             continue;
1892
1893         if (modificationTime.value() < modifiedSince)
1894             continue;
1895
1896         FileSystem::deleteFile(mediaKeyFile);
1897         FileSystem::deleteEmptyDirectory(mediaKeyDirectory);
1898     }
1899 }
1900
1901 void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, const HashSet<WebCore::SecurityOriginData>& origins)
1902 {
1903     ASSERT(!mediaKeysStorageDirectory.isEmpty());
1904
1905     for (const auto& origin : origins) {
1906         auto mediaKeyDirectory = FileSystem::pathByAppendingComponent(mediaKeysStorageDirectory, origin.databaseIdentifier());
1907         auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1908
1909         FileSystem::deleteFile(mediaKeyFile);
1910         FileSystem::deleteEmptyDirectory(mediaKeyDirectory);
1911     }
1912 }
1913
1914 bool WebsiteDataStore::resourceLoadStatisticsEnabled() const
1915 {
1916 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1917     return m_resourceLoadStatisticsEnabled;
1918 #else
1919     return false;
1920 #endif
1921 }
1922
1923 bool WebsiteDataStore::resourceLoadStatisticsDebugMode() const
1924 {
1925 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1926     return m_resourceLoadStatisticsDebugMode;
1927 #else
1928     return false;
1929 #endif
1930 }
1931
1932 void WebsiteDataStore::setResourceLoadStatisticsEnabled(bool enabled)
1933 {
1934 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1935     if (m_sessionID.isEphemeral() || enabled == resourceLoadStatisticsEnabled())
1936         return;
1937
1938     if (enabled) {
1939         m_resourceLoadStatisticsEnabled = true;
1940         
1941         resolveDirectoriesIfNecessary();
1942         
1943         for (auto& processPool : processPools(std::numeric_limits<size_t>::max(), false))
1944             processPool->sendToNetworkingProcess(Messages::NetworkProcess::SetResourceLoadStatisticsEnabled(m_sessionID, true));
1945         return;
1946     }
1947
1948     for (auto& processPool : processPools(std::numeric_limits<size_t>::max(), false))
1949         processPool->sendToNetworkingProcess(Messages::NetworkProcess::SetResourceLoadStatisticsEnabled(m_sessionID, false));
1950
1951     m_resourceLoadStatisticsEnabled = false;
1952 #else
1953     UNUSED_PARAM(enabled);
1954 #endif
1955 }
1956
1957 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1958 void WebsiteDataStore::setStatisticsTestingCallback(Function<void(const String&)>&& callback)
1959 {
1960     if (callback) {
1961         for (auto& processPool : processPools(std::numeric_limits<size_t>::max(), false))
1962             processPool->sendToNetworkingProcess(Messages::NetworkProcess::SetResourceLoadStatisticsLogTestingEvent(true));
1963     }
1964     
1965     m_statisticsTestingCallback = WTFMove(callback);
1966 }
1967 #endif
1968
1969 void WebsiteDataStore::setResourceLoadStatisticsDebugMode(bool enabled)
1970 {
1971     setResourceLoadStatisticsDebugMode(enabled, []() { });
1972 }
1973
1974 void WebsiteDataStore::setResourceLoadStatisticsDebugMode(bool enabled, CompletionHandler<void()>&& completionHandler)
1975 {
1976 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1977     m_resourceLoadStatisticsDebugMode = enabled;
1978
1979     auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1980     
1981     for (auto& processPool : processPools())
1982         processPool->ensureNetworkProcess().setResourceLoadStatisticsDebugMode(m_sessionID, enabled, [callbackAggregator = callbackAggregator.copyRef()] { });
1983 #else
1984     UNUSED_PARAM(enabled);
1985     UNUSED_PARAM(completionHandler);
1986 #endif
1987 }
1988
1989 #if ENABLE(RESOURCE_LOAD_STATISTICS)
1990 void WebsiteDataStore::logTestingEvent(const String& event)
1991 {
1992     ASSERT(RunLoop::isMain());
1993     
1994     if (m_statisticsTestingCallback)
1995         m_statisticsTestingCallback(event);
1996 }
1997
1998 void WebsiteDataStore::clearResourceLoadStatisticsInWebProcesses(CompletionHandler<void()>&& callback)
1999 {
2000     if (resourceLoadStatisticsEnabled()) {
2001         for (auto& processPool : processPools())
2002             processPool->clearResourceLoadStatistics();
2003     }
2004     callback();
2005 }
2006 #endif
2007
2008 Vector<WebCore::Cookie> WebsiteDataStore::pendingCookies() const
2009 {
2010     return copyToVector(m_pendingCookies);
2011 }
2012
2013 void WebsiteDataStore::addPendingCookie(const WebCore::Cookie& cookie)
2014 {
2015     m_pendingCookies.removeIf([&cookie](auto& pendingCookie) {
2016         return pendingCookie.isKeyEqual(cookie);
2017     });
2018     m_pendingCookies.add(cookie);
2019 }
2020
2021 void WebsiteDataStore::removePendingCookie(const WebCore::Cookie& cookie)
2022 {
2023     m_pendingCookies.remove(cookie);
2024 }
2025     
2026 void WebsiteDataStore::clearPendingCookies()
2027 {
2028     m_pendingCookies.clear();
2029 }
2030
2031 uint64_t WebsiteDataStore::perThirdPartyOriginStorageQuota() const
2032 {
2033     // FIXME: Consider whether allowing to set a perThirdPartyOriginStorageQuota from a WebsiteDataStore.
2034     return WebCore::StorageQuotaManager::defaultThirdPartyQuotaFromPerOriginQuota(perOriginStorageQuota());
2035 }
2036
2037 #if !PLATFORM(COCOA)
2038 WebsiteDataStoreParameters WebsiteDataStore::parameters()
2039 {
2040     WebsiteDataStoreParameters parameters;
2041     parameters.networkSessionParameters.sessionID = m_sessionID;
2042
2043     resolveDirectoriesIfNecessary();
2044
2045     auto localStorageDirectory = resolvedLocalStorageDirectory();
2046     if (!localStorageDirectory.isEmpty()) {
2047         parameters.localStorageDirectory = localStorageDirectory;
2048         SandboxExtension::createHandleForReadWriteDirectory(localStorageDirectory, parameters.localStorageDirectoryExtensionHandle);
2049     }
2050
2051 #if ENABLE(INDEXED_DATABASE)
2052     parameters.indexedDatabaseDirectory = resolvedIndexedDatabaseDirectory();
2053     if (!parameters.indexedDatabaseDirectory.isEmpty())
2054         SandboxExtension::createHandleForReadWriteDirectory(parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
2055 #endif
2056
2057 #if ENABLE(SERVICE_WORKER)
2058     parameters.serviceWorkerRegistrationDirectory = resolvedServiceWorkerRegistrationDirectory();
2059     if (!parameters.serviceWorkerRegistrationDirectory.isEmpty())
2060         SandboxExtension::createHandleForReadWriteDirectory(parameters.serviceWorkerRegistrationDirectory, parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
2061 #endif
2062
2063     parameters.perOriginStorageQuota = perOriginStorageQuota();
2064     parameters.perThirdPartyOriginStorageQuota = perThirdPartyOriginStorageQuota();
2065
2066     platformSetNetworkParameters(parameters);
2067
2068     return parameters;
2069 }
2070 #endif
2071
2072 #if HAVE(SEC_KEY_PROXY)
2073 void WebsiteDataStore::addSecKeyProxyStore(Ref<SecKeyProxyStore>&& store)
2074 {
2075     m_secKeyProxyStores.append(WTFMove(store));
2076 }
2077 #endif
2078
2079 #if ENABLE(WEB_AUTHN)
2080 void WebsiteDataStore::setMockWebAuthenticationConfiguration(MockWebAuthenticationConfiguration&& configuration)
2081 {
2082     if (!m_authenticatorManager->isMock()) {
2083         m_authenticatorManager = makeUniqueRef<MockAuthenticatorManager>(WTFMove(configuration));
2084         return;
2085     }
2086     static_cast<MockAuthenticatorManager*>(&m_authenticatorManager)->setTestConfiguration(WTFMove(configuration));
2087 }
2088 #endif
2089
2090 API::HTTPCookieStore& WebsiteDataStore::cookieStore()
2091 {
2092     if (!m_cookieStore)
2093         m_cookieStore = API::HTTPCookieStore::create(*this);
2094
2095     return *m_cookieStore;
2096 }
2097
2098 void WebsiteDataStore::didCreateNetworkProcess()
2099 {
2100 }
2101
2102 bool WebsiteDataStore::setSourceApplicationSecondaryIdentifier(String&& identifier)
2103 {
2104     if (m_networkingHasBegun)
2105         return false;
2106     m_resolvedConfiguration->setSourceApplicationSecondaryIdentifier(WTFMove(identifier));
2107     return true;
2108 }
2109
2110 bool WebsiteDataStore::setSourceApplicationBundleIdentifier(String&& identifier)
2111 {
2112     if (m_networkingHasBegun)
2113         return false;
2114     m_resolvedConfiguration->setSourceApplicationBundleIdentifier(WTFMove(identifier));
2115     return true;
2116 }
2117
2118 void WebsiteDataStore::getLocalStorageDetails(Function<void(Vector<LocalStorageDatabaseTracker::OriginDetails>&&)>&& completionHandler)
2119 {
2120     if (!isPersistent()) {
2121         completionHandler({ });
2122         return;
2123     }
2124
2125     for (auto& processPool : processPools()) {
2126         processPool->ensureNetworkProcess(this);
2127         processPool->networkProcess()->getLocalStorageDetails(m_sessionID, [completionHandler = WTFMove(completionHandler)](auto&& details) {
2128             completionHandler(WTFMove(details));
2129         });
2130         // FIXME: Support fetching from multiple pools.
2131         break;
2132     }
2133     ASSERT(!completionHandler);
2134 }
2135
2136 #if !PLATFORM(COCOA)
2137 WTF::String WebsiteDataStore::defaultMediaCacheDirectory()
2138 {
2139     // FIXME: Implement. https://bugs.webkit.org/show_bug.cgi?id=156369 and https://bugs.webkit.org/show_bug.cgi?id=156370
2140     return WTF::String();
2141 }
2142
2143 WTF::String WebsiteDataStore::defaultJavaScriptConfigurationDirectory()
2144 {
2145     // FIXME: Implement.
2146     return WTF::String();
2147 }
2148 #endif
2149
2150 #if !USE(GLIB)
2151 WTF::String WebsiteDataStore::defaultDeviceIdHashSaltsStorageDirectory()
2152 {
2153     // Not implemented.
2154     return WTF::String();
2155 }
2156 #endif
2157
2158 }