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