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