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