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