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