1/*
2 * Copyright (C) 2014-2019 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 "APIWebsiteDataStore.h"
32#include "AuthenticatorManager.h"
33#include "DeviceIdHashSaltStorage.h"
34#include "MockAuthenticatorManager.h"
35#include "NetworkProcessMessages.h"
36#include "ShouldGrandfatherStatistics.h"
37#include "StorageAccessStatus.h"
38#include "WebProcessCache.h"
39#include "WebProcessMessages.h"
40#include "WebProcessPool.h"
41#include "WebResourceLoadStatisticsStore.h"
42#include "WebsiteData.h"
43#include "WebsiteDataStoreClient.h"
44#include "WebsiteDataStoreParameters.h"
45#include <WebCore/ApplicationCacheStorage.h>
46#include <WebCore/CredentialStorage.h>
47#include <WebCore/DatabaseTracker.h>
48#include <WebCore/HTMLMediaElement.h>
49#include <WebCore/OriginLock.h>
50#include <WebCore/RegistrableDomain.h>
51#include <WebCore/SecurityOrigin.h>
52#include <WebCore/SecurityOriginData.h>
53#include <WebCore/StorageQuotaManager.h>
54#include <wtf/CallbackAggregator.h>
55#include <wtf/CompletionHandler.h>
56#include <wtf/CrossThreadCopier.h>
57#include <wtf/FileSystem.h>
58#include <wtf/ProcessPrivilege.h>
59#include <wtf/RunLoop.h>
60
61#if ENABLE(NETSCAPE_PLUGIN_API)
62#include "PluginProcessManager.h"
63#endif
64
65#if HAVE(SEC_KEY_PROXY)
66#include "SecKeyProxyStore.h"
67#endif
68
69namespace WebKit {
70
71static bool allowsWebsiteDataRecordsForAllOrigins;
72void WebsiteDataStore::allowWebsiteDataRecordsForAllOrigins()
73{
74 allowsWebsiteDataRecordsForAllOrigins = true;
75}
76
77static HashMap<PAL::SessionID, WebsiteDataStore*>& nonDefaultDataStores()
78{
79 RELEASE_ASSERT(isUIThread());
80 static NeverDestroyed<HashMap<PAL::SessionID, WebsiteDataStore*>> map;
81 return map;
82}
83
84Ref<WebsiteDataStore> WebsiteDataStore::createNonPersistent()
85{
86 return adoptRef(*new WebsiteDataStore(PAL::SessionID::generateEphemeralSessionID()));
87}
88
89Ref<WebsiteDataStore> WebsiteDataStore::create(Ref<WebsiteDataStoreConfiguration>&& configuration, PAL::SessionID sessionID)
90{
91 return adoptRef(*new WebsiteDataStore(WTFMove(configuration), sessionID));
92}
93
94WebsiteDataStore::WebsiteDataStore(Ref<WebsiteDataStoreConfiguration>&& configuration, PAL::SessionID sessionID)
95 : m_sessionID(sessionID)
96 , m_resolvedConfiguration(WTFMove(configuration))
97 , m_configuration(m_resolvedConfiguration->copy())
98 , m_deviceIdHashSaltStorage(DeviceIdHashSaltStorage::create(isPersistent() ? m_configuration->deviceIdHashSaltsStorageDirectory() : String()))
99 , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
100 , m_sourceApplicationBundleIdentifier(m_configuration->sourceApplicationBundleIdentifier())
101 , m_sourceApplicationSecondaryIdentifier(m_configuration->sourceApplicationSecondaryIdentifier())
102#if ENABLE(WEB_AUTHN)
103 , m_authenticatorManager(makeUniqueRef<AuthenticatorManager>())
104#endif
105 , m_client(makeUniqueRef<WebsiteDataStoreClient>())
106{
107#if HAVE(LOAD_OPTIMIZER)
108WEBSITEDATASTORE_LOADOPTIMIZER_ADDITIONS_2
109#endif
110 WTF::setProcessPrivileges(allPrivileges());
111 maybeRegisterWithSessionIDMap();
112 platformInitialize();
113
114 ASSERT(RunLoop::isMain());
115}
116
117WebsiteDataStore::WebsiteDataStore(PAL::SessionID sessionID)
118 : m_sessionID(sessionID)
119 , m_resolvedConfiguration(WebsiteDataStoreConfiguration::create())
120 , m_configuration(m_resolvedConfiguration->copy())
121 , m_deviceIdHashSaltStorage(DeviceIdHashSaltStorage::create(isPersistent() ? m_configuration->deviceIdHashSaltsStorageDirectory() : String()))
122 , m_queue(WorkQueue::create("com.apple.WebKit.WebsiteDataStore"))
123#if ENABLE(WEB_AUTHN)
124 , m_authenticatorManager(makeUniqueRef<AuthenticatorManager>())
125#endif
126 , m_client(makeUniqueRef<WebsiteDataStoreClient>())
127{
128#if HAVE(LOAD_OPTIMIZER)
129WEBSITEDATASTORE_LOADOPTIMIZER_ADDITIONS_2
130#endif
131 maybeRegisterWithSessionIDMap();
132 platformInitialize();
133
134 ASSERT(RunLoop::isMain());
135}
136
137WebsiteDataStore::~WebsiteDataStore()
138{
139 ASSERT(RunLoop::isMain());
140
141 platformDestroy();
142
143 if (m_sessionID.isValid() && m_sessionID != PAL::SessionID::defaultSessionID()) {
144 ASSERT(nonDefaultDataStores().get(m_sessionID) == this);
145 nonDefaultDataStores().remove(m_sessionID);
146 for (auto& processPool : WebProcessPool::allProcessPools()) {
147 if (auto* networkProcess = processPool->networkProcess())
148 networkProcess->removeSession(m_sessionID);
149 }
150 }
151}
152
153void WebsiteDataStore::maybeRegisterWithSessionIDMap()
154{
155 if (m_sessionID.isValid() && m_sessionID != PAL::SessionID::defaultSessionID()) {
156 auto result = nonDefaultDataStores().add(m_sessionID, this);
157 ASSERT_UNUSED(result, result.isNewEntry);
158 }
159}
160
161WebsiteDataStore* WebsiteDataStore::existingNonDefaultDataStoreForSessionID(PAL::SessionID sessionID)
162{
163 return sessionID.isValid() && sessionID != PAL::SessionID::defaultSessionID() ? nonDefaultDataStores().get(sessionID) : nullptr;
164}
165
166WebProcessPool* WebsiteDataStore::processPoolForCookieStorageOperations()
167{
168 auto pools = processPools(1, false);
169 if (!pools.isEmpty())
170 return pools.begin()->get();
171
172 for (auto* processPool : WebProcessPool::allProcessPools()) {
173 for (auto& process : processPool->processes()) {
174 if (process != processPool->dummyProcessProxy() && process->pageCount() && &process->websiteDataStore() == this)
175 return processPool;
176 }
177 }
178
179 return nullptr;
180}
181
182void WebsiteDataStore::resolveDirectoriesIfNecessary()
183{
184 if (m_hasResolvedDirectories)
185 return;
186 m_hasResolvedDirectories = true;
187
188 // Resolve directory paths.
189 if (!m_configuration->applicationCacheDirectory().isEmpty())
190 m_resolvedConfiguration->setApplicationCacheDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->applicationCacheDirectory()));
191 if (!m_configuration->mediaCacheDirectory().isEmpty())
192 m_resolvedConfiguration->setMediaCacheDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->mediaCacheDirectory()));
193 if (!m_configuration->mediaKeysStorageDirectory().isEmpty())
194 m_resolvedConfiguration->setMediaKeysStorageDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->mediaKeysStorageDirectory()));
195 if (!m_configuration->webSQLDatabaseDirectory().isEmpty())
196 m_resolvedConfiguration->setWebSQLDatabaseDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->webSQLDatabaseDirectory()));
197 if (!m_configuration->indexedDBDatabaseDirectory().isEmpty())
198 m_resolvedConfiguration->setIndexedDBDatabaseDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->indexedDBDatabaseDirectory()));
199 if (!m_configuration->deviceIdHashSaltsStorageDirectory().isEmpty())
200 m_resolvedConfiguration->setDeviceIdHashSaltsStorageDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->deviceIdHashSaltsStorageDirectory()));
201 if (!m_configuration->resourceLoadStatisticsDirectory().isEmpty())
202 m_resolvedConfiguration->setResourceLoadStatisticsDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->resourceLoadStatisticsDirectory()));
203 if (!m_configuration->serviceWorkerRegistrationDirectory().isEmpty() && m_resolvedConfiguration->serviceWorkerRegistrationDirectory().isEmpty())
204 m_resolvedConfiguration->setServiceWorkerRegistrationDirectory(resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->serviceWorkerRegistrationDirectory()));
205 if (!m_configuration->javaScriptConfigurationDirectory().isEmpty())
206 m_resolvedConfiguration->setJavaScriptConfigurationDirectory(resolvePathForSandboxExtension(m_configuration->javaScriptConfigurationDirectory()));
207 if (!m_configuration->cacheStorageDirectory().isEmpty() && m_resolvedConfiguration->cacheStorageDirectory().isEmpty())
208 m_resolvedConfiguration->setCacheStorageDirectory(resolvePathForSandboxExtension(m_configuration->cacheStorageDirectory()));
209
210 // Resolve directories for file paths.
211 if (!m_configuration->cookieStorageFile().isEmpty()) {
212 m_resolvedConfiguration->setCookieStorageFile(resolveAndCreateReadWriteDirectoryForSandboxExtension(FileSystem::directoryName(m_configuration->cookieStorageFile())));
213 m_resolvedConfiguration->setCookieStorageFile(FileSystem::pathByAppendingComponent(m_resolvedConfiguration->cookieStorageFile(), FileSystem::pathGetFileName(m_configuration->cookieStorageFile())));
214 }
215}
216
217enum class ProcessAccessType {
218 None,
219 OnlyIfLaunched,
220 Launch,
221};
222
223static ProcessAccessType computeNetworkProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
224{
225 for (auto dataType : dataTypes) {
226 if (WebsiteData::ownerProcess(dataType) == WebsiteDataProcessType::Network) {
227 if (isNonPersistentStore)
228 return ProcessAccessType::OnlyIfLaunched;
229 return ProcessAccessType::Launch;
230 }
231 }
232 return ProcessAccessType::None;
233}
234
235static ProcessAccessType computeWebProcessAccessTypeForDataFetch(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
236{
237 UNUSED_PARAM(isNonPersistentStore);
238
239 ProcessAccessType processAccessType = ProcessAccessType::None;
240
241 if (dataTypes.contains(WebsiteDataType::MemoryCache))
242 return ProcessAccessType::OnlyIfLaunched;
243
244 return processAccessType;
245}
246
247void WebsiteDataStore::fetchData(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, Function<void(Vector<WebsiteDataRecord>)>&& completionHandler)
248{
249 fetchDataAndApply(dataTypes, fetchOptions, nullptr, WTFMove(completionHandler));
250}
251
252void WebsiteDataStore::fetchDataAndApply(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply)
253{
254 struct CallbackAggregator final : ThreadSafeRefCounted<CallbackAggregator> {
255 CallbackAggregator(OptionSet<WebsiteDataFetchOption> fetchOptions, RefPtr<WorkQueue>&& queue, Function<void(Vector<WebsiteDataRecord>)>&& apply, WebsiteDataStore& dataStore)
256 : fetchOptions(fetchOptions)
257 , queue(WTFMove(queue))
258 , apply(WTFMove(apply))
259 , protectedDataStore(dataStore)
260 {
261 ASSERT(RunLoop::isMain());
262 }
263
264 ~CallbackAggregator()
265 {
266 ASSERT(!pendingCallbacks);
267
268 // Make sure the data store gets destroyed on the main thread even though the CallbackAggregator can get destroyed on a background queue.
269 RunLoop::main().dispatch([protectedDataStore = WTFMove(protectedDataStore)] { });
270 }
271
272 void addPendingCallback()
273 {
274 pendingCallbacks++;
275 }
276
277 void removePendingCallback(WebsiteData websiteData)
278 {
279 ASSERT(pendingCallbacks);
280 --pendingCallbacks;
281
282 for (auto& entry : websiteData.entries) {
283 auto displayName = WebsiteDataRecord::displayNameForOrigin(entry.origin);
284 if (!displayName) {
285 if (!allowsWebsiteDataRecordsForAllOrigins)
286 continue;
287
288 displayName = makeString(entry.origin.protocol, " ", entry.origin.host);
289 }
290
291 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
292 if (!record.displayName)
293 record.displayName = WTFMove(displayName);
294
295 record.add(entry.type, entry.origin);
296
297 if (fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes)) {
298 if (!record.size)
299 record.size = WebsiteDataRecord::Size { 0, { } };
300
301 record.size->totalSize += entry.size;
302 record.size->typeSizes.add(static_cast<unsigned>(entry.type), 0).iterator->value += entry.size;
303 }
304 }
305
306 for (auto& hostName : websiteData.hostNamesWithCookies) {
307 auto displayName = WebsiteDataRecord::displayNameForCookieHostName(hostName);
308 if (!displayName)
309 continue;
310
311 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
312 if (!record.displayName)
313 record.displayName = WTFMove(displayName);
314
315 record.addCookieHostName(hostName);
316 }
317
318#if ENABLE(NETSCAPE_PLUGIN_API)
319 for (auto& hostName : websiteData.hostNamesWithPluginData) {
320 auto displayName = WebsiteDataRecord::displayNameForHostName(hostName);
321 if (!displayName)
322 continue;
323
324 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
325 if (!record.displayName)
326 record.displayName = WTFMove(displayName);
327
328 record.addPluginDataHostName(hostName);
329 }
330#endif
331
332 for (auto& hostName : websiteData.hostNamesWithHSTSCache) {
333 auto displayName = WebsiteDataRecord::displayNameForHostName(hostName);
334 if (!displayName)
335 continue;
336
337 auto& record = m_websiteDataRecords.add(displayName, WebsiteDataRecord { }).iterator->value;
338 if (!record.displayName)
339 record.displayName = WTFMove(displayName);
340
341 record.addHSTSCacheHostname(hostName);
342 }
343
344 callIfNeeded();
345 }
346
347 void callIfNeeded()
348 {
349 if (pendingCallbacks)
350 return;
351
352 Vector<WebsiteDataRecord> records;
353 records.reserveInitialCapacity(m_websiteDataRecords.size());
354 for (auto& record : m_websiteDataRecords.values())
355 records.uncheckedAppend(WTFMove(record));
356
357 auto processRecords = [apply = WTFMove(apply), records = WTFMove(records)] () mutable {
358 apply(WTFMove(records));
359 };
360
361 if (queue)
362 queue->dispatch(WTFMove(processRecords));
363 else
364 RunLoop::main().dispatch(WTFMove(processRecords));
365 }
366
367 const OptionSet<WebsiteDataFetchOption> fetchOptions;
368
369 unsigned pendingCallbacks = 0;
370 RefPtr<WorkQueue> queue;
371 Function<void(Vector<WebsiteDataRecord>)> apply;
372
373 HashMap<String, WebsiteDataRecord> m_websiteDataRecords;
374 Ref<WebsiteDataStore> protectedDataStore;
375 };
376
377 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(fetchOptions, WTFMove(queue), WTFMove(apply), *this));
378
379#if ENABLE(VIDEO)
380 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
381 callbackAggregator->addPendingCallback();
382 m_queue->dispatch([mediaCacheDirectory = m_configuration->mediaCacheDirectory().isolatedCopy(), callbackAggregator] {
383 // FIXME: Make HTMLMediaElement::originsInMediaCache return a collection of SecurityOriginDatas.
384 HashSet<RefPtr<WebCore::SecurityOrigin>> origins = WebCore::HTMLMediaElement::originsInMediaCache(mediaCacheDirectory);
385 WebsiteData websiteData;
386
387 for (auto& origin : origins) {
388 WebsiteData::Entry entry { origin->data(), WebsiteDataType::DiskCache, 0 };
389 websiteData.entries.append(WTFMove(entry));
390 }
391
392 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
393 callbackAggregator->removePendingCallback(WTFMove(websiteData));
394 });
395 });
396 }
397#endif
398
399 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
400 if (networkProcessAccessType != ProcessAccessType::None) {
401 for (auto& processPool : processPools()) {
402 switch (networkProcessAccessType) {
403 case ProcessAccessType::OnlyIfLaunched:
404 if (!processPool->networkProcess())
405 continue;
406 break;
407
408 case ProcessAccessType::Launch:
409 processPool->ensureNetworkProcess(this);
410 break;
411
412 case ProcessAccessType::None:
413 ASSERT_NOT_REACHED();
414 }
415
416 callbackAggregator->addPendingCallback();
417 processPool->networkProcess()->fetchWebsiteData(m_sessionID, dataTypes, fetchOptions, [callbackAggregator, processPool](WebsiteData websiteData) {
418 callbackAggregator->removePendingCallback(WTFMove(websiteData));
419 });
420 }
421 }
422
423 auto webProcessAccessType = computeWebProcessAccessTypeForDataFetch(dataTypes, !isPersistent());
424 if (webProcessAccessType != ProcessAccessType::None) {
425 for (auto& process : processes()) {
426 switch (webProcessAccessType) {
427 case ProcessAccessType::OnlyIfLaunched:
428 if (!process->canSendMessage())
429 continue;
430 break;
431
432 case ProcessAccessType::Launch:
433 // FIXME: Handle this.
434 ASSERT_NOT_REACHED();
435 break;
436
437 case ProcessAccessType::None:
438 ASSERT_NOT_REACHED();
439 }
440
441 callbackAggregator->addPendingCallback();
442 process->fetchWebsiteData(m_sessionID, dataTypes, [callbackAggregator](WebsiteData websiteData) {
443 callbackAggregator->removePendingCallback(WTFMove(websiteData));
444 });
445 }
446 }
447
448 if (dataTypes.contains(WebsiteDataType::DeviceIdHashSalt)) {
449 callbackAggregator->addPendingCallback();
450
451 m_deviceIdHashSaltStorage->getDeviceIdHashSaltOrigins([callbackAggregator](auto&& origins) {
452 WebsiteData websiteData;
453
454 while (!origins.isEmpty())
455 websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::DeviceIdHashSalt, 0 });
456
457 callbackAggregator->removePendingCallback(WTFMove(websiteData));
458 });
459 }
460
461 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
462 callbackAggregator->addPendingCallback();
463
464 m_queue->dispatch([fetchOptions, applicationCacheDirectory = m_configuration->applicationCacheDirectory().isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration->applicationCacheFlatFileSubdirectoryName().isolatedCopy(), callbackAggregator] {
465 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
466
467 WebsiteData websiteData;
468
469 // FIXME: getOriginsWithCache should return a collection of SecurityOriginDatas.
470 auto origins = storage->originsWithCache();
471
472 for (auto& origin : origins) {
473 uint64_t size = fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes) ? storage->diskUsageForOrigin(origin) : 0;
474 WebsiteData::Entry entry { origin->data(), WebsiteDataType::OfflineWebApplicationCache, size };
475
476 websiteData.entries.append(WTFMove(entry));
477 }
478
479 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins), websiteData = WTFMove(websiteData)]() mutable {
480 callbackAggregator->removePendingCallback(WTFMove(websiteData));
481 });
482 });
483 }
484
485 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
486 callbackAggregator->addPendingCallback();
487
488 m_queue->dispatch([webSQLDatabaseDirectory = m_configuration->webSQLDatabaseDirectory().isolatedCopy(), callbackAggregator] {
489 auto origins = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->origins();
490 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
491 WebsiteData websiteData;
492 for (auto& origin : origins)
493 websiteData.entries.append(WebsiteData::Entry { WTFMove(origin), WebsiteDataType::WebSQLDatabases, 0 });
494 callbackAggregator->removePendingCallback(WTFMove(websiteData));
495 });
496 });
497 }
498
499 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
500 callbackAggregator->addPendingCallback();
501
502 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration->mediaKeysStorageDirectory().isolatedCopy(), callbackAggregator] {
503 auto origins = mediaKeyOrigins(mediaKeysStorageDirectory);
504
505 RunLoop::main().dispatch([callbackAggregator, origins = WTFMove(origins)]() mutable {
506 WebsiteData websiteData;
507 for (auto& origin : origins)
508 websiteData.entries.append(WebsiteData::Entry { origin, WebsiteDataType::MediaKeys, 0 });
509
510 callbackAggregator->removePendingCallback(WTFMove(websiteData));
511 });
512 });
513 }
514
515#if PLATFORM(COCOA)
516 if (dataTypes.contains(WebsiteDataType::Credentials) && isPersistent()) {
517 for (auto& processPool : processPools()) {
518 if (!processPool->networkProcess())
519 continue;
520
521 callbackAggregator->addPendingCallback();
522 WTF::CompletionHandler<void(Vector<WebCore::SecurityOriginData>&&)> completionHandler = [callbackAggregator](Vector<WebCore::SecurityOriginData>&& origins) mutable {
523 WebsiteData websiteData;
524 for (auto& origin : origins)
525 websiteData.entries.append(WebsiteData::Entry { origin, WebsiteDataType::Credentials, 0 });
526 callbackAggregator->removePendingCallback(WTFMove(websiteData));
527 };
528 processPool->networkProcess()->sendWithAsyncReply(Messages::NetworkProcess::OriginsWithPersistentCredentials(), WTFMove(completionHandler));
529 }
530 }
531#endif
532
533#if ENABLE(NETSCAPE_PLUGIN_API)
534 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
535 class State {
536 public:
537 static void fetchData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
538 {
539 new State(WTFMove(callbackAggregator), WTFMove(plugins));
540 }
541
542 private:
543 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins)
544 : m_callbackAggregator(WTFMove(callbackAggregator))
545 , m_plugins(WTFMove(plugins))
546 {
547 m_callbackAggregator->addPendingCallback();
548
549 fetchWebsiteDataForNextPlugin();
550 }
551
552 ~State()
553 {
554 ASSERT(m_plugins.isEmpty());
555 }
556
557 void fetchWebsiteDataForNextPlugin()
558 {
559 if (m_plugins.isEmpty()) {
560 WebsiteData websiteData;
561 websiteData.hostNamesWithPluginData = WTFMove(m_hostNames);
562
563 m_callbackAggregator->removePendingCallback(WTFMove(websiteData));
564
565 delete this;
566 return;
567 }
568
569 auto plugin = m_plugins.takeLast();
570 PluginProcessManager::singleton().fetchWebsiteData(plugin, m_callbackAggregator->fetchOptions, [this](Vector<String> hostNames) {
571 for (auto& hostName : hostNames)
572 m_hostNames.add(WTFMove(hostName));
573 fetchWebsiteDataForNextPlugin();
574 });
575 }
576
577 Ref<CallbackAggregator> m_callbackAggregator;
578 Vector<PluginModuleInfo> m_plugins;
579 HashSet<String> m_hostNames;
580 };
581
582 State::fetchData(*callbackAggregator, plugins());
583 }
584#endif
585
586 callbackAggregator->callIfNeeded();
587}
588
589#if ENABLE(RESOURCE_LOAD_STATISTICS)
590void WebsiteDataStore::fetchDataForRegistrableDomains(OptionSet<WebsiteDataType> dataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, const Vector<WebCore::RegistrableDomain>& domains, CompletionHandler<void(Vector<WebsiteDataRecord>&&, HashSet<WebCore::RegistrableDomain>&&)>&& completionHandler)
591{
592 fetchDataAndApply(dataTypes, fetchOptions, m_queue.copyRef(), [domains = crossThreadCopy(domains), completionHandler = WTFMove(completionHandler)] (auto&& existingDataRecords) mutable {
593 ASSERT(!RunLoop::isMain());
594
595 Vector<WebsiteDataRecord> matchingDataRecords;
596 HashSet<WebCore::RegistrableDomain> domainsWithMatchingDataRecords;
597 for (auto&& dataRecord : existingDataRecords) {
598 for (auto& domain : domains) {
599 if (dataRecord.matches(domain)) {
600 matchingDataRecords.append(WTFMove(dataRecord));
601 domainsWithMatchingDataRecords.add(domain.isolatedCopy());
602 break;
603 }
604 }
605 }
606 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), matchingDataRecords = WTFMove(matchingDataRecords), domainsWithMatchingDataRecords = WTFMove(domainsWithMatchingDataRecords)] () mutable {
607 completionHandler(WTFMove(matchingDataRecords), WTFMove(domainsWithMatchingDataRecords));
608 });
609 });
610}
611#endif
612
613static ProcessAccessType computeNetworkProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
614{
615 ProcessAccessType processAccessType = ProcessAccessType::None;
616
617 for (auto dataType : dataTypes) {
618 if (dataType == WebsiteDataType::Cookies) {
619 if (isNonPersistentStore)
620 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
621 else
622 processAccessType = std::max(processAccessType, ProcessAccessType::Launch);
623 } else if (WebsiteData::ownerProcess(dataType) == WebsiteDataProcessType::Network)
624 return ProcessAccessType::Launch;
625 }
626
627 return processAccessType;
628}
629
630static ProcessAccessType computeWebProcessAccessTypeForDataRemoval(OptionSet<WebsiteDataType> dataTypes, bool isNonPersistentStore)
631{
632 UNUSED_PARAM(isNonPersistentStore);
633
634 ProcessAccessType processAccessType = ProcessAccessType::None;
635
636 if (dataTypes.contains(WebsiteDataType::MemoryCache))
637 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
638
639 if (dataTypes.contains(WebsiteDataType::Credentials))
640 processAccessType = std::max(processAccessType, ProcessAccessType::OnlyIfLaunched);
641
642 return processAccessType;
643}
644
645void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, WallTime modifiedSince, Function<void()>&& completionHandler)
646{
647 struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
648 CallbackAggregator(WebsiteDataStore& dataStore, Function<void()>&& completionHandler)
649 : completionHandler(WTFMove(completionHandler))
650 , protectedDataStore(dataStore)
651 {
652 ASSERT(RunLoop::isMain());
653 }
654
655 ~CallbackAggregator()
656 {
657 // Make sure the data store gets destroyed on the main thread even though the CallbackAggregator can get destroyed on a background queue.
658 RunLoop::main().dispatch([protectedDataStore = WTFMove(protectedDataStore)] { });
659 }
660
661 void addPendingCallback()
662 {
663 pendingCallbacks++;
664 }
665
666 void removePendingCallback()
667 {
668 ASSERT(pendingCallbacks);
669 --pendingCallbacks;
670
671 callIfNeeded();
672 }
673
674 void callIfNeeded()
675 {
676 if (!pendingCallbacks)
677 RunLoop::main().dispatch(WTFMove(completionHandler));
678 }
679
680 unsigned pendingCallbacks = 0;
681 Function<void()> completionHandler;
682 Ref<WebsiteDataStore> protectedDataStore;
683 };
684
685 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(*this, WTFMove(completionHandler)));
686
687#if ENABLE(VIDEO)
688 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
689 callbackAggregator->addPendingCallback();
690 m_queue->dispatch([modifiedSince, mediaCacheDirectory = m_configuration->mediaCacheDirectory().isolatedCopy(), callbackAggregator] {
691 WebCore::HTMLMediaElement::clearMediaCache(mediaCacheDirectory, modifiedSince);
692
693 WTF::RunLoop::main().dispatch([callbackAggregator] {
694 callbackAggregator->removePendingCallback();
695 });
696 });
697 }
698#endif
699
700#if ENABLE(RESOURCE_LOAD_STATISTICS)
701 bool didNotifyNetworkProcessToDeleteWebsiteData = false;
702#endif
703 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
704 if (networkProcessAccessType != ProcessAccessType::None) {
705 for (auto& processPool : processPools()) {
706 switch (networkProcessAccessType) {
707 case ProcessAccessType::OnlyIfLaunched:
708 if (!processPool->networkProcess())
709 continue;
710 break;
711
712 case ProcessAccessType::Launch:
713 processPool->ensureNetworkProcess(this);
714 break;
715
716 case ProcessAccessType::None:
717 ASSERT_NOT_REACHED();
718 }
719
720 callbackAggregator->addPendingCallback();
721 processPool->networkProcess()->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator, processPool] {
722 callbackAggregator->removePendingCallback();
723 });
724#if ENABLE(RESOURCE_LOAD_STATISTICS)
725 didNotifyNetworkProcessToDeleteWebsiteData = true;
726#endif
727 }
728 }
729
730 auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
731 if (webProcessAccessType != ProcessAccessType::None) {
732 for (auto& processPool : processPools()) {
733 processPool->clearSuspendedPages(AllowProcessCaching::No);
734 processPool->webProcessCache().clear();
735 }
736
737 for (auto& process : processes()) {
738 switch (webProcessAccessType) {
739 case ProcessAccessType::OnlyIfLaunched:
740 if (!process->canSendMessage())
741 continue;
742 break;
743
744 case ProcessAccessType::Launch:
745 // FIXME: Handle this.
746 ASSERT_NOT_REACHED();
747 break;
748
749 case ProcessAccessType::None:
750 ASSERT_NOT_REACHED();
751 }
752
753 callbackAggregator->addPendingCallback();
754 process->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] {
755 callbackAggregator->removePendingCallback();
756 });
757 }
758 }
759
760 if (dataTypes.contains(WebsiteDataType::DeviceIdHashSalt) || (dataTypes.contains(WebsiteDataType::Cookies))) {
761 callbackAggregator->addPendingCallback();
762
763 m_deviceIdHashSaltStorage->deleteDeviceIdHashSaltOriginsModifiedSince(modifiedSince, [callbackAggregator] {
764 callbackAggregator->removePendingCallback();
765 });
766 }
767
768 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
769 callbackAggregator->addPendingCallback();
770
771 m_queue->dispatch([applicationCacheDirectory = m_configuration->applicationCacheDirectory().isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration->applicationCacheFlatFileSubdirectoryName().isolatedCopy(), callbackAggregator] {
772 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
773
774 storage->deleteAllCaches();
775
776 WTF::RunLoop::main().dispatch([callbackAggregator] {
777 callbackAggregator->removePendingCallback();
778 });
779 });
780 }
781
782 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
783 callbackAggregator->addPendingCallback();
784
785 m_queue->dispatch([webSQLDatabaseDirectory = m_configuration->webSQLDatabaseDirectory().isolatedCopy(), callbackAggregator, modifiedSince] {
786 WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory)->deleteDatabasesModifiedSince(modifiedSince);
787
788 RunLoop::main().dispatch([callbackAggregator] {
789 callbackAggregator->removePendingCallback();
790 });
791 });
792 }
793
794 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
795 callbackAggregator->addPendingCallback();
796
797 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration->mediaKeysStorageDirectory().isolatedCopy(), callbackAggregator, modifiedSince] {
798 removeMediaKeys(mediaKeysStorageDirectory, modifiedSince);
799
800 RunLoop::main().dispatch([callbackAggregator] {
801 callbackAggregator->removePendingCallback();
802 });
803 });
804 }
805
806 if (dataTypes.contains(WebsiteDataType::SearchFieldRecentSearches) && isPersistent()) {
807 callbackAggregator->addPendingCallback();
808
809 m_queue->dispatch([modifiedSince, callbackAggregator] {
810 platformRemoveRecentSearches(modifiedSince);
811
812 RunLoop::main().dispatch([callbackAggregator] {
813 callbackAggregator->removePendingCallback();
814 });
815 });
816 }
817
818#if ENABLE(NETSCAPE_PLUGIN_API)
819 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
820 class State {
821 public:
822 static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, WallTime modifiedSince)
823 {
824 new State(WTFMove(callbackAggregator), WTFMove(plugins), modifiedSince);
825 }
826
827 private:
828 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, WallTime modifiedSince)
829 : m_callbackAggregator(WTFMove(callbackAggregator))
830 , m_plugins(WTFMove(plugins))
831 , m_modifiedSince(modifiedSince)
832 {
833 m_callbackAggregator->addPendingCallback();
834
835 deleteWebsiteDataForNextPlugin();
836 }
837
838 ~State()
839 {
840 ASSERT(m_plugins.isEmpty());
841 }
842
843 void deleteWebsiteDataForNextPlugin()
844 {
845 if (m_plugins.isEmpty()) {
846 m_callbackAggregator->removePendingCallback();
847
848 delete this;
849 return;
850 }
851
852 auto plugin = m_plugins.takeLast();
853 PluginProcessManager::singleton().deleteWebsiteData(plugin, m_modifiedSince, [this] {
854 deleteWebsiteDataForNextPlugin();
855 });
856 }
857
858 Ref<CallbackAggregator> m_callbackAggregator;
859 Vector<PluginModuleInfo> m_plugins;
860 WallTime m_modifiedSince;
861 };
862
863 State::deleteData(*callbackAggregator, plugins(), modifiedSince);
864 }
865#endif
866
867#if ENABLE(RESOURCE_LOAD_STATISTICS)
868 if (dataTypes.contains(WebsiteDataType::ResourceLoadStatistics)) {
869 if (!didNotifyNetworkProcessToDeleteWebsiteData) {
870 for (auto& processPool : processPools()) {
871 if (auto* process = processPool->networkProcess()) {
872 callbackAggregator->addPendingCallback();
873 process->deleteWebsiteData(m_sessionID, dataTypes, modifiedSince, [callbackAggregator] {
874 callbackAggregator->removePendingCallback();
875 });
876 }
877 }
878 }
879
880 callbackAggregator->addPendingCallback();
881 clearResourceLoadStatisticsInWebProcesses([callbackAggregator] {
882 callbackAggregator->removePendingCallback();
883 });
884 }
885#endif
886
887 // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
888 callbackAggregator->callIfNeeded();
889}
890
891void WebsiteDataStore::removeData(OptionSet<WebsiteDataType> dataTypes, const Vector<WebsiteDataRecord>& dataRecords, Function<void()>&& completionHandler)
892{
893 Vector<WebCore::SecurityOriginData> origins;
894
895 for (const auto& dataRecord : dataRecords) {
896 for (auto& origin : dataRecord.origins)
897 origins.append(origin);
898 }
899
900 struct CallbackAggregator : ThreadSafeRefCounted<CallbackAggregator> {
901 CallbackAggregator(WebsiteDataStore& dataStore, Function<void()>&& completionHandler)
902 : completionHandler(WTFMove(completionHandler))
903 , protectedDataStore(dataStore)
904 {
905 ASSERT(RunLoop::isMain());
906 }
907
908 ~CallbackAggregator()
909 {
910 // Make sure the data store gets destroyed on the main thread even though the CallbackAggregator can get destroyed on a background queue.
911 RunLoop::main().dispatch([protectedDataStore = WTFMove(protectedDataStore)] { });
912 }
913
914 void addPendingCallback()
915 {
916 pendingCallbacks++;
917 }
918
919 void removePendingCallback()
920 {
921 ASSERT(pendingCallbacks);
922 --pendingCallbacks;
923
924 callIfNeeded();
925 }
926
927 void callIfNeeded()
928 {
929 if (!pendingCallbacks)
930 RunLoop::main().dispatch(WTFMove(completionHandler));
931 }
932
933 unsigned pendingCallbacks = 0;
934 Function<void()> completionHandler;
935 Ref<WebsiteDataStore> protectedDataStore;
936 };
937
938 RefPtr<CallbackAggregator> callbackAggregator = adoptRef(new CallbackAggregator(*this, WTFMove(completionHandler)));
939
940 if (dataTypes.contains(WebsiteDataType::DiskCache)) {
941 HashSet<WebCore::SecurityOriginData> origins;
942 for (const auto& dataRecord : dataRecords) {
943 for (const auto& origin : dataRecord.origins)
944 origins.add(origin);
945 }
946
947#if ENABLE(VIDEO)
948 callbackAggregator->addPendingCallback();
949 m_queue->dispatch([origins = WTFMove(origins), mediaCacheDirectory = m_configuration->mediaCacheDirectory().isolatedCopy(), callbackAggregator] {
950
951 // FIXME: Move SecurityOrigin::toRawString to SecurityOriginData and
952 // make HTMLMediaElement::clearMediaCacheForOrigins take SecurityOriginData.
953 HashSet<RefPtr<WebCore::SecurityOrigin>> securityOrigins;
954 for (auto& origin : origins)
955 securityOrigins.add(origin.securityOrigin());
956 WebCore::HTMLMediaElement::clearMediaCacheForOrigins(mediaCacheDirectory, securityOrigins);
957
958 WTF::RunLoop::main().dispatch([callbackAggregator] {
959 callbackAggregator->removePendingCallback();
960 });
961 });
962#endif
963 }
964
965 auto networkProcessAccessType = computeNetworkProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
966 if (networkProcessAccessType != ProcessAccessType::None) {
967 for (auto& processPool : processPools()) {
968 switch (networkProcessAccessType) {
969 case ProcessAccessType::OnlyIfLaunched:
970 if (!processPool->networkProcess())
971 continue;
972 break;
973
974 case ProcessAccessType::Launch:
975 processPool->ensureNetworkProcess(this);
976 break;
977
978 case ProcessAccessType::None:
979 ASSERT_NOT_REACHED();
980 }
981
982 Vector<String> cookieHostNames;
983 Vector<String> HSTSCacheHostNames;
984 for (const auto& dataRecord : dataRecords) {
985 for (auto& hostName : dataRecord.cookieHostNames)
986 cookieHostNames.append(hostName);
987 for (auto& hostName : dataRecord.HSTSCacheHostNames)
988 HSTSCacheHostNames.append(hostName);
989 }
990
991 callbackAggregator->addPendingCallback();
992 processPool->networkProcess()->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, cookieHostNames, HSTSCacheHostNames, [callbackAggregator, processPool] {
993 callbackAggregator->removePendingCallback();
994 });
995 }
996 }
997
998 auto webProcessAccessType = computeWebProcessAccessTypeForDataRemoval(dataTypes, !isPersistent());
999 if (webProcessAccessType != ProcessAccessType::None) {
1000 for (auto& process : processes()) {
1001 switch (webProcessAccessType) {
1002 case ProcessAccessType::OnlyIfLaunched:
1003 if (!process->canSendMessage())
1004 continue;
1005 break;
1006
1007 case ProcessAccessType::Launch:
1008 // FIXME: Handle this.
1009 ASSERT_NOT_REACHED();
1010 break;
1011
1012 case ProcessAccessType::None:
1013 ASSERT_NOT_REACHED();
1014 }
1015
1016 callbackAggregator->addPendingCallback();
1017
1018 process->deleteWebsiteDataForOrigins(m_sessionID, dataTypes, origins, [callbackAggregator] {
1019 callbackAggregator->removePendingCallback();
1020 });
1021 }
1022 }
1023
1024 if (dataTypes.contains(WebsiteDataType::DeviceIdHashSalt) || (dataTypes.contains(WebsiteDataType::Cookies))) {
1025 callbackAggregator->addPendingCallback();
1026
1027 m_deviceIdHashSaltStorage->deleteDeviceIdHashSaltForOrigins(origins, [callbackAggregator] {
1028 callbackAggregator->removePendingCallback();
1029 });
1030 }
1031
1032 if (dataTypes.contains(WebsiteDataType::OfflineWebApplicationCache) && isPersistent()) {
1033 HashSet<WebCore::SecurityOriginData> origins;
1034 for (const auto& dataRecord : dataRecords) {
1035 for (const auto& origin : dataRecord.origins)
1036 origins.add(origin);
1037 }
1038
1039 callbackAggregator->addPendingCallback();
1040 m_queue->dispatch([origins = WTFMove(origins), applicationCacheDirectory = m_configuration->applicationCacheDirectory().isolatedCopy(), applicationCacheFlatFileSubdirectoryName = m_configuration->applicationCacheFlatFileSubdirectoryName().isolatedCopy(), callbackAggregator] {
1041 auto storage = WebCore::ApplicationCacheStorage::create(applicationCacheDirectory, applicationCacheFlatFileSubdirectoryName);
1042
1043 for (const auto& origin : origins)
1044 storage->deleteCacheForOrigin(origin.securityOrigin());
1045
1046 WTF::RunLoop::main().dispatch([callbackAggregator] {
1047 callbackAggregator->removePendingCallback();
1048 });
1049 });
1050 }
1051
1052 if (dataTypes.contains(WebsiteDataType::WebSQLDatabases) && isPersistent()) {
1053 HashSet<WebCore::SecurityOriginData> origins;
1054 for (const auto& dataRecord : dataRecords) {
1055 for (const auto& origin : dataRecord.origins)
1056 origins.add(origin);
1057 }
1058
1059 callbackAggregator->addPendingCallback();
1060 m_queue->dispatch([origins = WTFMove(origins), callbackAggregator, webSQLDatabaseDirectory = m_configuration->webSQLDatabaseDirectory().isolatedCopy()] {
1061 auto databaseTracker = WebCore::DatabaseTracker::trackerWithDatabasePath(webSQLDatabaseDirectory);
1062 for (auto& origin : origins)
1063 databaseTracker->deleteOrigin(origin);
1064 RunLoop::main().dispatch([callbackAggregator] {
1065 callbackAggregator->removePendingCallback();
1066 });
1067 });
1068 }
1069
1070 if (dataTypes.contains(WebsiteDataType::MediaKeys) && isPersistent()) {
1071 HashSet<WebCore::SecurityOriginData> origins;
1072 for (const auto& dataRecord : dataRecords) {
1073 for (const auto& origin : dataRecord.origins)
1074 origins.add(origin);
1075 }
1076
1077 callbackAggregator->addPendingCallback();
1078 m_queue->dispatch([mediaKeysStorageDirectory = m_configuration->mediaKeysStorageDirectory().isolatedCopy(), callbackAggregator, origins = WTFMove(origins)] {
1079
1080 removeMediaKeys(mediaKeysStorageDirectory, origins);
1081
1082 RunLoop::main().dispatch([callbackAggregator] {
1083 callbackAggregator->removePendingCallback();
1084 });
1085 });
1086 }
1087
1088 if (dataTypes.contains(WebsiteDataType::Credentials) && isPersistent()) {
1089 for (auto& processPool : processPools()) {
1090 if (!processPool->networkProcess())
1091 continue;
1092
1093 callbackAggregator->addPendingCallback();
1094 WTF::CompletionHandler<void()> completionHandler = [callbackAggregator]() mutable {
1095 callbackAggregator->removePendingCallback();
1096 };
1097 processPool->networkProcess()->sendWithAsyncReply(Messages::NetworkProcess::RemoveCredentialsWithOrigins(origins), WTFMove(completionHandler));
1098 }
1099 }
1100
1101#if ENABLE(NETSCAPE_PLUGIN_API)
1102 if (dataTypes.contains(WebsiteDataType::PlugInData) && isPersistent()) {
1103 Vector<String> hostNames;
1104 for (const auto& dataRecord : dataRecords) {
1105 for (const auto& hostName : dataRecord.pluginDataHostNames)
1106 hostNames.append(hostName);
1107 }
1108
1109
1110 class State {
1111 public:
1112 static void deleteData(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1113 {
1114 new State(WTFMove(callbackAggregator), WTFMove(plugins), WTFMove(hostNames));
1115 }
1116
1117 private:
1118 State(Ref<CallbackAggregator>&& callbackAggregator, Vector<PluginModuleInfo>&& plugins, Vector<String>&& hostNames)
1119 : m_callbackAggregator(WTFMove(callbackAggregator))
1120 , m_plugins(WTFMove(plugins))
1121 , m_hostNames(WTFMove(hostNames))
1122 {
1123 m_callbackAggregator->addPendingCallback();
1124
1125 deleteWebsiteDataForNextPlugin();
1126 }
1127
1128 ~State()
1129 {
1130 ASSERT(m_plugins.isEmpty());
1131 }
1132
1133 void deleteWebsiteDataForNextPlugin()
1134 {
1135 if (m_plugins.isEmpty()) {
1136 m_callbackAggregator->removePendingCallback();
1137
1138 delete this;
1139 return;
1140 }
1141
1142 auto plugin = m_plugins.takeLast();
1143 PluginProcessManager::singleton().deleteWebsiteDataForHostNames(plugin, m_hostNames, [this] {
1144 deleteWebsiteDataForNextPlugin();
1145 });
1146 }
1147
1148 Ref<CallbackAggregator> m_callbackAggregator;
1149 Vector<PluginModuleInfo> m_plugins;
1150 Vector<String> m_hostNames;
1151 };
1152
1153 if (!hostNames.isEmpty())
1154 State::deleteData(*callbackAggregator, plugins(), WTFMove(hostNames));
1155 }
1156#endif
1157
1158 // There's a chance that we don't have any pending callbacks. If so, we want to dispatch the completion handler right away.
1159 callbackAggregator->callIfNeeded();
1160}
1161
1162#if ENABLE(RESOURCE_LOAD_STATISTICS)
1163void WebsiteDataStore::setMaxStatisticsEntries(size_t maximumEntryCount, CompletionHandler<void()>&& completionHandler)
1164{
1165 ASSERT(RunLoop::isMain());
1166
1167 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1168
1169 for (auto& processPool : processPools())
1170 processPool->ensureNetworkProcess().setMaxStatisticsEntries(m_sessionID, maximumEntryCount, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1171}
1172
1173void WebsiteDataStore::setPruneEntriesDownTo(size_t pruneTargetCount, CompletionHandler<void()>&& completionHandler)
1174{
1175 ASSERT(RunLoop::isMain());
1176
1177 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1178
1179 for (auto& processPool : processPools()) {
1180 processPool->ensureNetworkProcess().setPruneEntriesDownTo(m_sessionID, pruneTargetCount, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1181 }
1182}
1183
1184void WebsiteDataStore::setGrandfatheringTime(Seconds seconds, CompletionHandler<void()>&& completionHandler)
1185{
1186 ASSERT(RunLoop::isMain());
1187
1188 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1189
1190 for (auto& processPool : processPools())
1191 processPool->ensureNetworkProcess().setGrandfatheringTime(m_sessionID, seconds, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1192}
1193
1194void WebsiteDataStore::setMinimumTimeBetweenDataRecordsRemoval(Seconds seconds, CompletionHandler<void()>&& completionHandler)
1195{
1196 ASSERT(RunLoop::isMain());
1197
1198 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1199
1200 for (auto& processPool : processPools())
1201 processPool->ensureNetworkProcess().setMinimumTimeBetweenDataRecordsRemoval(m_sessionID, seconds, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1202}
1203
1204void WebsiteDataStore::dumpResourceLoadStatistics(CompletionHandler<void(const String&)>&& completionHandler)
1205{
1206 ASSERT(RunLoop::isMain());
1207
1208 for (auto& processPool : processPools()) {
1209 if (auto* process = processPool->networkProcess()) {
1210 process->dumpResourceLoadStatistics(m_sessionID, WTFMove(completionHandler));
1211 RELEASE_ASSERT(processPools().size() == 1);
1212 break;
1213 }
1214 }
1215}
1216
1217void WebsiteDataStore::isPrevalentResource(const URL& url, CompletionHandler<void(bool isPrevalent)>&& completionHandler)
1218{
1219 ASSERT(RunLoop::isMain());
1220
1221 if (url.protocolIsAbout() || url.isEmpty()) {
1222 completionHandler(false);
1223 return;
1224 }
1225
1226 for (auto& processPool : processPools()) {
1227 if (auto* process = processPool->networkProcess()) {
1228 process->isPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1229 RELEASE_ASSERT(processPools().size() == 1);
1230 break;
1231 }
1232 }
1233}
1234
1235void WebsiteDataStore::setPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
1236{
1237 ASSERT(RunLoop::isMain());
1238
1239 if (url.protocolIsAbout() || url.isEmpty()) {
1240 completionHandler();
1241 return;
1242 }
1243
1244 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1245
1246 for (auto& processPool : processPools()) {
1247 processPool->ensureNetworkProcess().setPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1248 }
1249}
1250
1251void WebsiteDataStore::setPrevalentResourceForDebugMode(const URL& url, CompletionHandler<void()>&& completionHandler)
1252{
1253 ASSERT(RunLoop::isMain());
1254
1255 if (url.protocolIsAbout() || url.isEmpty()) {
1256 completionHandler();
1257 return;
1258 }
1259
1260 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1261
1262 for (auto& processPool : processPools()) {
1263 if (auto* process = processPool->networkProcess())
1264 process->setPrevalentResourceForDebugMode(m_sessionID, WebCore::RegistrableDomain { url }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1265 }
1266}
1267
1268void WebsiteDataStore::isVeryPrevalentResource(const URL& url, CompletionHandler<void(bool isVeryPrevalent)>&& completionHandler)
1269{
1270 ASSERT(RunLoop::isMain());
1271
1272 if (url.protocolIsAbout() || url.isEmpty()) {
1273 completionHandler(false);
1274 return;
1275 }
1276
1277 for (auto& processPool : processPools()) {
1278 if (auto* process = processPool->networkProcess()) {
1279 process->isVeryPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1280 ASSERT(processPools().size() == 1);
1281 break;
1282 }
1283 }
1284}
1285
1286void WebsiteDataStore::setVeryPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
1287{
1288 ASSERT(RunLoop::isMain());
1289
1290 if (url.protocolIsAbout() || url.isEmpty()) {
1291 completionHandler();
1292 return;
1293 }
1294
1295 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1296
1297 for (auto& processPool : processPools()) {
1298 if (auto* process = processPool->networkProcess())
1299 process->setVeryPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1300 }
1301}
1302
1303void WebsiteDataStore::setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value, CompletionHandler<void()>&& completionHandler)
1304{
1305 ASSERT(RunLoop::isMain());
1306
1307 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1308
1309 for (auto& processPool : processPools())
1310 processPool->ensureNetworkProcess().setShouldClassifyResourcesBeforeDataRecordsRemoval(m_sessionID, value, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1311}
1312
1313void WebsiteDataStore::setSubframeUnderTopFrameDomain(const URL& subFrameURL, const URL& topFrameURL, CompletionHandler<void()>&& completionHandler)
1314{
1315 ASSERT(RunLoop::isMain());
1316
1317 if (subFrameURL.protocolIsAbout() || subFrameURL.isEmpty() || topFrameURL.protocolIsAbout() || topFrameURL.isEmpty()) {
1318 completionHandler();
1319 return;
1320 }
1321
1322 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1323
1324 for (auto& processPool : processPools()) {
1325 if (auto* process = processPool->networkProcess())
1326 process->setSubframeUnderTopFrameDomain(m_sessionID, WebCore::RegistrableDomain { subFrameURL }, WebCore::RegistrableDomain { topFrameURL }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1327 }
1328}
1329
1330void WebsiteDataStore::isRegisteredAsSubFrameUnder(const URL& subFrameURL, const URL& topFrameURL, CompletionHandler<void(bool)>&& completionHandler)
1331{
1332 ASSERT(RunLoop::isMain());
1333
1334 for (auto& processPool : processPools()) {
1335 if (auto* process = processPool->networkProcess()) {
1336 process->isRegisteredAsSubFrameUnder(m_sessionID, WebCore::RegistrableDomain { subFrameURL }, WebCore::RegistrableDomain { topFrameURL }, WTFMove(completionHandler));
1337 ASSERT(processPools().size() == 1);
1338 break;
1339 }
1340 }
1341}
1342
1343void WebsiteDataStore::setSubresourceUnderTopFrameDomain(const URL& subresourceURL, const URL& topFrameURL, CompletionHandler<void()>&& completionHandler)
1344{
1345 ASSERT(RunLoop::isMain());
1346
1347 if (subresourceURL.protocolIsAbout() || subresourceURL.isEmpty() || topFrameURL.protocolIsAbout() || topFrameURL.isEmpty()) {
1348 completionHandler();
1349 return;
1350 }
1351
1352 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1353
1354 for (auto& processPool : processPools()) {
1355 if (auto* process = processPool->networkProcess())
1356 process->setSubresourceUnderTopFrameDomain(m_sessionID, WebCore::RegistrableDomain { subresourceURL }, WebCore::RegistrableDomain { topFrameURL }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1357 }
1358}
1359
1360void WebsiteDataStore::isRegisteredAsSubresourceUnder(const URL& subresourceURL, const URL& topFrameURL, CompletionHandler<void(bool)>&& completionHandler)
1361{
1362 ASSERT(RunLoop::isMain());
1363
1364 for (auto& processPool : processPools()) {
1365 if (auto* process = processPool->networkProcess()) {
1366 process->isRegisteredAsSubresourceUnder(m_sessionID, WebCore::RegistrableDomain { subresourceURL }, WebCore::RegistrableDomain { topFrameURL }, WTFMove(completionHandler));
1367 ASSERT(processPools().size() == 1);
1368 break;
1369 }
1370 }
1371}
1372
1373void WebsiteDataStore::setSubresourceUniqueRedirectTo(const URL& subresourceURL, const URL& urlRedirectedTo, CompletionHandler<void()>&& completionHandler)
1374{
1375 ASSERT(RunLoop::isMain());
1376
1377 if (subresourceURL.protocolIsAbout() || subresourceURL.isEmpty() || urlRedirectedTo.protocolIsAbout() || urlRedirectedTo.isEmpty()) {
1378 completionHandler();
1379 return;
1380 }
1381
1382 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1383
1384 for (auto& processPool : processPools()) {
1385 if (auto* process = processPool->networkProcess())
1386 process->setSubresourceUniqueRedirectTo(m_sessionID, WebCore::RegistrableDomain { subresourceURL }, WebCore::RegistrableDomain { urlRedirectedTo }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1387 }
1388}
1389
1390void WebsiteDataStore::setSubresourceUniqueRedirectFrom(const URL& subresourceURL, const URL& urlRedirectedFrom, CompletionHandler<void()>&& completionHandler)
1391{
1392 ASSERT(RunLoop::isMain());
1393
1394 if (subresourceURL.protocolIsAbout() || subresourceURL.isEmpty() || urlRedirectedFrom.protocolIsAbout() || urlRedirectedFrom.isEmpty()) {
1395 completionHandler();
1396 return;
1397 }
1398
1399 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1400
1401 for (auto& processPool : processPools()) {
1402 if (auto* process = processPool->networkProcess())
1403 process->setSubresourceUniqueRedirectFrom(m_sessionID, WebCore::RegistrableDomain { subresourceURL }, WebCore::RegistrableDomain { urlRedirectedFrom }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1404 }
1405}
1406
1407void WebsiteDataStore::setTopFrameUniqueRedirectTo(const URL& topFrameURL, const URL& urlRedirectedTo, CompletionHandler<void()>&& completionHandler)
1408{
1409 ASSERT(RunLoop::isMain());
1410
1411 if (topFrameURL.protocolIsAbout() || topFrameURL.isEmpty() || urlRedirectedTo.protocolIsAbout() || urlRedirectedTo.isEmpty()) {
1412 completionHandler();
1413 return;
1414 }
1415
1416 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1417
1418 for (auto& processPool : processPools()) {
1419 if (auto* process = processPool->networkProcess())
1420 process->setTopFrameUniqueRedirectTo(m_sessionID, WebCore::RegistrableDomain { topFrameURL }, WebCore::RegistrableDomain { urlRedirectedTo }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1421 }
1422}
1423
1424void WebsiteDataStore::setTopFrameUniqueRedirectFrom(const URL& topFrameURL, const URL& urlRedirectedFrom, CompletionHandler<void()>&& completionHandler)
1425{
1426 ASSERT(RunLoop::isMain());
1427
1428 if (topFrameURL.protocolIsAbout() || topFrameURL.isEmpty() || urlRedirectedFrom.protocolIsAbout() || urlRedirectedFrom.isEmpty()) {
1429 completionHandler();
1430 return;
1431 }
1432
1433 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1434
1435 for (auto& processPool : processPools()) {
1436 if (auto* process = processPool->networkProcess())
1437 process->setTopFrameUniqueRedirectFrom(m_sessionID, WebCore::RegistrableDomain { topFrameURL }, WebCore::RegistrableDomain { urlRedirectedFrom }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1438 }
1439}
1440
1441void WebsiteDataStore::isRegisteredAsRedirectingTo(const URL& urlRedirectedFrom, const URL& urlRedirectedTo, CompletionHandler<void(bool)>&& completionHandler)
1442{
1443 ASSERT(RunLoop::isMain());
1444
1445 for (auto& processPool : processPools()) {
1446 if (auto* process = processPool->networkProcess()) {
1447 process->isRegisteredAsRedirectingTo(m_sessionID, WebCore::RegistrableDomain { urlRedirectedFrom }, WebCore::RegistrableDomain { urlRedirectedTo }, WTFMove(completionHandler));
1448 ASSERT(processPools().size() == 1);
1449 break;
1450 }
1451 }
1452}
1453
1454void WebsiteDataStore::clearPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
1455{
1456 ASSERT(RunLoop::isMain());
1457
1458 if (url.protocolIsAbout() || url.isEmpty()) {
1459 completionHandler();
1460 return;
1461 }
1462
1463 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1464
1465 for (auto& processPool : processPools()) {
1466 if (auto* process = processPool->networkProcess())
1467 process->clearPrevalentResource(m_sessionID, WebCore::RegistrableDomain { url }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1468 }
1469}
1470
1471void WebsiteDataStore::resetParametersToDefaultValues(CompletionHandler<void()>&& completionHandler)
1472{
1473 ASSERT(RunLoop::isMain());
1474
1475 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1476
1477 for (auto& processPool : processPools()) {
1478 if (auto* process = processPool->networkProcess())
1479 process->resetParametersToDefaultValues(m_sessionID, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1480 }
1481}
1482
1483void WebsiteDataStore::submitTelemetry()
1484{
1485 ASSERT(RunLoop::isMain());
1486
1487 for (auto& processPool : processPools()) {
1488 if (auto* process = processPool->networkProcess())
1489 process->submitTelemetry(m_sessionID, [] { });
1490 }
1491}
1492
1493void WebsiteDataStore::scheduleClearInMemoryAndPersistent(WallTime modifiedSince, ShouldGrandfatherStatistics shouldGrandfather, CompletionHandler<void()>&& completionHandler)
1494{
1495 ASSERT(RunLoop::isMain());
1496
1497 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1498
1499 for (auto& processPool : processPools()) {
1500 if (auto* process = processPool->networkProcess())
1501 process->scheduleClearInMemoryAndPersistent(m_sessionID, modifiedSince, shouldGrandfather, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1502 }
1503}
1504
1505void WebsiteDataStore::scheduleClearInMemoryAndPersistent(ShouldGrandfatherStatistics shouldGrandfather, CompletionHandler<void()>&& completionHandler)
1506{
1507 ASSERT(RunLoop::isMain());
1508
1509 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1510
1511 for (auto& processPool : processPools()) {
1512 if (auto* process = processPool->networkProcess())
1513 process->scheduleClearInMemoryAndPersistent(m_sessionID, { }, shouldGrandfather, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1514 }
1515}
1516
1517void WebsiteDataStore::scheduleCookieBlockingUpdate(CompletionHandler<void()>&& completionHandler)
1518{
1519 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1520
1521 for (auto& processPool : processPools()) {
1522 if (auto* process = processPool->networkProcess())
1523 process->scheduleCookieBlockingUpdate(m_sessionID, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1524 }
1525}
1526
1527void WebsiteDataStore::scheduleStatisticsAndDataRecordsProcessing(CompletionHandler<void()>&& completionHandler)
1528{
1529 ASSERT(RunLoop::isMain());
1530
1531 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1532
1533 for (auto& processPool : processPools()) {
1534 if (auto* process = processPool->networkProcess())
1535 process->scheduleStatisticsAndDataRecordsProcessing(m_sessionID, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1536 }
1537}
1538
1539void WebsiteDataStore::setLastSeen(const URL& url, Seconds seconds, CompletionHandler<void()>&& completionHandler)
1540{
1541 if (url.protocolIsAbout() || url.isEmpty()) {
1542 completionHandler();
1543 return;
1544 }
1545
1546 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1547
1548 for (auto& processPool : processPools()) {
1549 if (auto* process = processPool->networkProcess())
1550 process->setLastSeen(m_sessionID, WebCore::RegistrableDomain { url }, seconds, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1551 }
1552}
1553
1554void WebsiteDataStore::setNotifyPagesWhenDataRecordsWereScanned(bool value, CompletionHandler<void()>&& completionHandler)
1555{
1556 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1557
1558 for (auto& processPool : processPools())
1559 processPool->ensureNetworkProcess().setNotifyPagesWhenDataRecordsWereScanned(m_sessionID, value, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1560}
1561
1562void WebsiteDataStore::setIsRunningResourceLoadStatisticsTest(bool value, CompletionHandler<void()>&& completionHandler)
1563{
1564 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1565
1566 for (auto& processPool : processPools())
1567 processPool->ensureNetworkProcess().setIsRunningResourceLoadStatisticsTest(m_sessionID, value, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1568}
1569
1570void WebsiteDataStore::setNotifyPagesWhenTelemetryWasCaptured(bool value, CompletionHandler<void()>&& completionHandler)
1571{
1572 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1573
1574 for (auto& processPool : processPools())
1575 processPool->ensureNetworkProcess().setNotifyPagesWhenTelemetryWasCaptured(m_sessionID, value, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1576}
1577
1578void WebsiteDataStore::getAllStorageAccessEntries(WebCore::PageIdentifier pageID, CompletionHandler<void(Vector<String>&& domains)>&& completionHandler)
1579{
1580 auto* webPage = WebProcessProxy::webPage(pageID);
1581 if (!webPage) {
1582 completionHandler({ });
1583 return;
1584 }
1585
1586 auto& networkProcess = webPage->process().processPool().ensureNetworkProcess();
1587 networkProcess.getAllStorageAccessEntries(m_sessionID, WTFMove(completionHandler));
1588}
1589
1590
1591void WebsiteDataStore::setTimeToLiveUserInteraction(Seconds seconds, CompletionHandler<void()>&& completionHandler)
1592{
1593 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1594
1595 for (auto& processPool : processPools())
1596 processPool->ensureNetworkProcess().setTimeToLiveUserInteraction(m_sessionID, seconds, [callbackAggregator = callbackAggregator.copyRef()] { });
1597}
1598
1599void WebsiteDataStore::logUserInteraction(const URL& url, CompletionHandler<void()>&& completionHandler)
1600{
1601 ASSERT(RunLoop::isMain());
1602
1603 if (url.protocolIsAbout() || url.isEmpty()) {
1604 completionHandler();
1605 return;
1606 }
1607
1608 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1609
1610 for (auto& processPool : processPools()) {
1611 if (auto* process = processPool->networkProcess())
1612 process->logUserInteraction(m_sessionID, WebCore::RegistrableDomain { url }, [callbackAggregator = callbackAggregator.copyRef()] { });
1613 }
1614}
1615
1616void WebsiteDataStore::hasHadUserInteraction(const URL& url, CompletionHandler<void(bool)>&& completionHandler)
1617{
1618 ASSERT(RunLoop::isMain());
1619
1620 if (url.protocolIsAbout() || url.isEmpty()) {
1621 completionHandler(false);
1622 return;
1623 }
1624
1625 for (auto& processPool : processPools()) {
1626 if (auto* process = processPool->networkProcess()) {
1627 process->hasHadUserInteraction(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1628 ASSERT(processPools().size() == 1);
1629 break;
1630 }
1631 }
1632}
1633
1634void WebsiteDataStore::clearUserInteraction(const URL& url, CompletionHandler<void()>&& completionHandler)
1635{
1636 ASSERT(RunLoop::isMain());
1637
1638 if (url.protocolIsAbout() || url.isEmpty()) {
1639 completionHandler();
1640 return;
1641 }
1642
1643 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1644
1645 for (auto& processPool : processPools()) {
1646 if (auto* process = processPool->networkProcess())
1647 process->clearUserInteraction(m_sessionID, WebCore::RegistrableDomain { url }, [callbackAggregator = callbackAggregator.copyRef()] { });
1648 }
1649}
1650
1651void WebsiteDataStore::setGrandfathered(const URL& url, bool isGrandfathered, CompletionHandler<void()>&& completionHandler)
1652{
1653 ASSERT(RunLoop::isMain());
1654
1655 if (url.protocolIsAbout() || url.isEmpty()) {
1656 completionHandler();
1657 return;
1658 }
1659
1660 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1661
1662 for (auto& processPool : processPools()) {
1663 if (auto* process = processPool->networkProcess())
1664 process->setGrandfathered(m_sessionID, WebCore::RegistrableDomain { url }, isGrandfathered, [callbackAggregator = callbackAggregator.copyRef()] { });
1665 }
1666}
1667
1668void WebsiteDataStore::setCrossSiteLoadWithLinkDecorationForTesting(const URL& fromURL, const URL& toURL, CompletionHandler<void()>&& completionHandler)
1669{
1670 ASSERT(RunLoop::isMain());
1671
1672 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1673
1674 for (auto& processPool : processPools()) {
1675 if (auto* process = processPool->networkProcess())
1676 process->setCrossSiteLoadWithLinkDecorationForTesting(m_sessionID, WebCore::RegistrableDomain { fromURL }, WebCore::RegistrableDomain { toURL }, [processPool, callbackAggregator = callbackAggregator.copyRef()] { });
1677 }
1678}
1679
1680void WebsiteDataStore::resetCrossSiteLoadsWithLinkDecorationForTesting(CompletionHandler<void()>&& completionHandler)
1681{
1682 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1683
1684 for (auto& processPool : processPools()) {
1685 if (auto* networkProcess = processPool->networkProcess())
1686 networkProcess->resetCrossSiteLoadsWithLinkDecorationForTesting(m_sessionID, [callbackAggregator = callbackAggregator.copyRef()] { });
1687 }
1688}
1689
1690void WebsiteDataStore::deleteCookiesForTesting(const URL& url, bool includeHttpOnlyCookies, CompletionHandler<void()>&& completionHandler)
1691{
1692 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1693
1694 for (auto& processPool : processPools()) {
1695 if (auto* networkProcess = processPool->networkProcess())
1696 networkProcess->deleteCookiesForTesting(m_sessionID, WebCore::RegistrableDomain { url }, includeHttpOnlyCookies, [callbackAggregator = callbackAggregator.copyRef()] { });
1697 }
1698}
1699
1700void WebsiteDataStore::hasLocalStorageForTesting(const URL& url, CompletionHandler<void(bool)>&& completionHandler) const
1701{
1702 for (auto& processPool : processPools()) {
1703 if (auto* networkProcess = processPool->networkProcess()) {
1704 networkProcess->hasLocalStorage(m_sessionID, WebCore::RegistrableDomain { url }, WTFMove(completionHandler));
1705 ASSERT(processPools().size() == 1);
1706 break;
1707 }
1708 }
1709 ASSERT(!completionHandler);
1710}
1711#endif // ENABLE(RESOURCE_LOAD_STATISTICS)
1712
1713void WebsiteDataStore::setCacheMaxAgeCapForPrevalentResources(Seconds seconds, CompletionHandler<void()>&& completionHandler)
1714{
1715#if ENABLE(RESOURCE_LOAD_STATISTICS)
1716 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1717
1718 for (auto& processPool : processPools())
1719 processPool->ensureNetworkProcess().setCacheMaxAgeCapForPrevalentResources(m_sessionID, seconds, [callbackAggregator = callbackAggregator.copyRef()] { });
1720#else
1721 UNUSED_PARAM(seconds);
1722 completionHandler();
1723#endif
1724}
1725
1726void WebsiteDataStore::resetCacheMaxAgeCapForPrevalentResources(CompletionHandler<void()>&& completionHandler)
1727{
1728#if ENABLE(RESOURCE_LOAD_STATISTICS)
1729 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1730
1731 for (auto& processPool : processPools()) {
1732 if (auto* networkProcess = processPool->networkProcess())
1733 networkProcess->resetCacheMaxAgeCapForPrevalentResources(m_sessionID, [callbackAggregator = callbackAggregator.copyRef()] { });
1734 }
1735#else
1736 completionHandler();
1737#endif
1738}
1739
1740bool WebsiteDataStore::isAssociatedProcessPool(WebProcessPool& processPool) const
1741{
1742 if (auto* processPoolDataStore = processPool.websiteDataStore())
1743 return &processPoolDataStore->websiteDataStore() == this;
1744 return false;
1745}
1746
1747HashSet<RefPtr<WebProcessPool>> WebsiteDataStore::processPools(size_t count, bool ensureAPoolExists) const
1748{
1749 HashSet<RefPtr<WebProcessPool>> processPools;
1750 for (auto& process : processes())
1751 processPools.add(&process->processPool());
1752
1753 if (processPools.isEmpty()) {
1754 // Check if we're one of the legacy data stores.
1755 for (auto& processPool : WebProcessPool::allProcessPools()) {
1756 if (!isAssociatedProcessPool(*processPool))
1757 continue;
1758
1759 processPools.add(processPool);
1760
1761 if (processPools.size() == count)
1762 break;
1763 }
1764 }
1765
1766 if (processPools.isEmpty() && count && ensureAPoolExists) {
1767 auto processPool = WebProcessPool::create(API::ProcessPoolConfiguration::createWithWebsiteDataStoreConfiguration(m_configuration));
1768 processPools.add(processPool.ptr());
1769 }
1770
1771 return processPools;
1772}
1773
1774#if ENABLE(NETSCAPE_PLUGIN_API)
1775Vector<PluginModuleInfo> WebsiteDataStore::plugins() const
1776{
1777 Vector<PluginModuleInfo> plugins;
1778
1779 for (auto& processPool : processPools()) {
1780 for (auto& plugin : processPool->pluginInfoStore().plugins())
1781 plugins.append(plugin);
1782 }
1783
1784 return plugins;
1785}
1786#endif
1787
1788static String computeMediaKeyFile(const String& mediaKeyDirectory)
1789{
1790 return FileSystem::pathByAppendingComponent(mediaKeyDirectory, "SecureStop.plist");
1791}
1792
1793Vector<WebCore::SecurityOriginData> WebsiteDataStore::mediaKeyOrigins(const String& mediaKeysStorageDirectory)
1794{
1795 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1796
1797 Vector<WebCore::SecurityOriginData> origins;
1798
1799 for (const auto& originPath : FileSystem::listDirectory(mediaKeysStorageDirectory, "*")) {
1800 auto mediaKeyFile = computeMediaKeyFile(originPath);
1801 if (!FileSystem::fileExists(mediaKeyFile))
1802 continue;
1803
1804 auto mediaKeyIdentifier = FileSystem::pathGetFileName(originPath);
1805
1806 if (auto securityOrigin = WebCore::SecurityOriginData::fromDatabaseIdentifier(mediaKeyIdentifier))
1807 origins.append(*securityOrigin);
1808 }
1809
1810 return origins;
1811}
1812
1813void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, WallTime modifiedSince)
1814{
1815 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1816
1817 for (const auto& mediaKeyDirectory : FileSystem::listDirectory(mediaKeysStorageDirectory, "*")) {
1818 auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1819
1820 auto modificationTime = FileSystem::getFileModificationTime(mediaKeyFile);
1821 if (!modificationTime)
1822 continue;
1823
1824 if (modificationTime.value() < modifiedSince)
1825 continue;
1826
1827 FileSystem::deleteFile(mediaKeyFile);
1828 FileSystem::deleteEmptyDirectory(mediaKeyDirectory);
1829 }
1830}
1831
1832void WebsiteDataStore::removeMediaKeys(const String& mediaKeysStorageDirectory, const HashSet<WebCore::SecurityOriginData>& origins)
1833{
1834 ASSERT(!mediaKeysStorageDirectory.isEmpty());
1835
1836 for (const auto& origin : origins) {
1837 auto mediaKeyDirectory = FileSystem::pathByAppendingComponent(mediaKeysStorageDirectory, origin.databaseIdentifier());
1838 auto mediaKeyFile = computeMediaKeyFile(mediaKeyDirectory);
1839
1840 FileSystem::deleteFile(mediaKeyFile);
1841 FileSystem::deleteEmptyDirectory(mediaKeyDirectory);
1842 }
1843}
1844
1845bool WebsiteDataStore::resourceLoadStatisticsEnabled() const
1846{
1847#if ENABLE(RESOURCE_LOAD_STATISTICS)
1848 return m_resourceLoadStatisticsEnabled;
1849#else
1850 return false;
1851#endif
1852}
1853
1854bool WebsiteDataStore::resourceLoadStatisticsDebugMode() const
1855{
1856#if ENABLE(RESOURCE_LOAD_STATISTICS)
1857 return m_resourceLoadStatisticsDebugMode;
1858#else
1859 return false;
1860#endif
1861}
1862
1863void WebsiteDataStore::setResourceLoadStatisticsEnabled(bool enabled)
1864{
1865#if ENABLE(RESOURCE_LOAD_STATISTICS)
1866 if (m_sessionID.isEphemeral() || enabled == resourceLoadStatisticsEnabled())
1867 return;
1868
1869 if (enabled) {
1870 enableResourceLoadStatisticsAndSetTestingCallback(nullptr);
1871 return;
1872 }
1873
1874 for (auto& processPool : processPools(std::numeric_limits<size_t>::max(), false)) {
1875 processPool->setResourceLoadStatisticsEnabled(false);
1876 processPool->sendToNetworkingProcess(Messages::NetworkProcess::SetResourceLoadStatisticsEnabled(false));
1877 }
1878#else
1879 UNUSED_PARAM(enabled);
1880#endif
1881}
1882
1883void WebsiteDataStore::setResourceLoadStatisticsDebugMode(bool enabled)
1884{
1885 setResourceLoadStatisticsDebugMode(enabled, []() { });
1886}
1887
1888void WebsiteDataStore::setResourceLoadStatisticsDebugMode(bool enabled, CompletionHandler<void()>&& completionHandler)
1889{
1890#if ENABLE(RESOURCE_LOAD_STATISTICS)
1891 m_resourceLoadStatisticsDebugMode = enabled;
1892
1893 auto callbackAggregator = CallbackAggregator::create(WTFMove(completionHandler));
1894
1895 for (auto& processPool : processPools())
1896 processPool->ensureNetworkProcess().setResourceLoadStatisticsDebugMode(m_sessionID, enabled, [callbackAggregator = callbackAggregator.copyRef()] { });
1897#else
1898 UNUSED_PARAM(enabled);
1899 UNUSED_PARAM(completionHandler);
1900#endif
1901}
1902
1903#if ENABLE(RESOURCE_LOAD_STATISTICS)
1904void WebsiteDataStore::enableResourceLoadStatisticsAndSetTestingCallback(Function<void (const String&)>&& callback)
1905{
1906 ASSERT(!m_sessionID.isEphemeral());
1907
1908 m_resourceLoadStatisticsEnabled = true;
1909 setStatisticsTestingCallback(WTFMove(callback));
1910
1911 resolveDirectoriesIfNecessary();
1912
1913 for (auto& processPool : processPools(std::numeric_limits<size_t>::max(), false)) {
1914 processPool->setResourceLoadStatisticsEnabled(true);
1915 processPool->sendToNetworkingProcess(Messages::NetworkProcess::SetResourceLoadStatisticsEnabled(true));
1916 }
1917}
1918
1919void WebsiteDataStore::logTestingEvent(const String& event)
1920{
1921 ASSERT(RunLoop::isMain());
1922
1923 if (m_statisticsTestingCallback)
1924 m_statisticsTestingCallback(event);
1925}
1926
1927void WebsiteDataStore::clearResourceLoadStatisticsInWebProcesses(CompletionHandler<void()>&& callback)
1928{
1929 if (resourceLoadStatisticsEnabled()) {
1930 for (auto& processPool : processPools())
1931 processPool->clearResourceLoadStatistics();
1932 }
1933 callback();
1934}
1935#endif
1936
1937Vector<WebCore::Cookie> WebsiteDataStore::pendingCookies() const
1938{
1939 return copyToVector(m_pendingCookies);
1940}
1941
1942void WebsiteDataStore::addPendingCookie(const WebCore::Cookie& cookie)
1943{
1944 m_pendingCookies.removeIf([&cookie](auto& pendingCookie) {
1945 return pendingCookie.isKeyEqual(cookie);
1946 });
1947 m_pendingCookies.add(cookie);
1948}
1949
1950void WebsiteDataStore::removePendingCookie(const WebCore::Cookie& cookie)
1951{
1952 m_pendingCookies.remove(cookie);
1953}
1954
1955void WebsiteDataStore::clearPendingCookies()
1956{
1957 m_pendingCookies.clear();
1958}
1959
1960uint64_t WebsiteDataStore::perThirdPartyOriginStorageQuota() const
1961{
1962 // FIXME: Consider whether allowing to set a perThirdPartyOriginStorageQuota from a WebsiteDataStore.
1963 return WebCore::StorageQuotaManager::defaultThirdPartyQuotaFromPerOriginQuota(perOriginStorageQuota());
1964}
1965
1966#if !PLATFORM(COCOA)
1967WebsiteDataStoreParameters WebsiteDataStore::parameters()
1968{
1969 WebsiteDataStoreParameters parameters;
1970 parameters.networkSessionParameters.sessionID = m_sessionID;
1971
1972 resolveDirectoriesIfNecessary();
1973
1974 auto localStorageDirectory = resolvedLocalStorageDirectory();
1975 if (!localStorageDirectory.isEmpty()) {
1976 parameters.networkSessionParameters.localStorageDirectory = localStorageDirectory;
1977 SandboxExtension::createHandleForReadWriteDirectory(localStorageDirectory, parameters.networkSessionParameters.localStorageDirectoryExtensionHandle);
1978 }
1979
1980#if ENABLE(INDEXED_DATABASE)
1981 parameters.indexedDatabaseDirectory = resolvedIndexedDatabaseDirectory();
1982 if (!parameters.indexedDatabaseDirectory.isEmpty())
1983 SandboxExtension::createHandleForReadWriteDirectory(parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
1984#endif
1985
1986#if ENABLE(SERVICE_WORKER)
1987 parameters.serviceWorkerRegistrationDirectory = resolvedServiceWorkerRegistrationDirectory();
1988 if (!parameters.serviceWorkerRegistrationDirectory.isEmpty())
1989 SandboxExtension::createHandleForReadWriteDirectory(parameters.serviceWorkerRegistrationDirectory, parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
1990#endif
1991
1992 parameters.perOriginStorageQuota = perOriginStorageQuota();
1993 parameters.perThirdPartyOriginStorageQuota = perThirdPartyOriginStorageQuota();
1994
1995 platformSetNetworkParameters(parameters);
1996
1997 return parameters;
1998}
1999#endif
2000
2001#if HAVE(SEC_KEY_PROXY)
2002void WebsiteDataStore::addSecKeyProxyStore(Ref<SecKeyProxyStore>&& store)
2003{
2004 m_secKeyProxyStores.append(WTFMove(store));
2005}
2006#endif
2007
2008#if ENABLE(WEB_AUTHN)
2009void WebsiteDataStore::setMockWebAuthenticationConfiguration(MockWebAuthenticationConfiguration&& configuration)
2010{
2011 if (!m_authenticatorManager->isMock()) {
2012 m_authenticatorManager = makeUniqueRef<MockAuthenticatorManager>(WTFMove(configuration));
2013 return;
2014 }
2015 static_cast<MockAuthenticatorManager*>(&m_authenticatorManager)->setTestConfiguration(WTFMove(configuration));
2016}
2017#endif
2018
2019API::HTTPCookieStore& WebsiteDataStore::cookieStore()
2020{
2021 if (!m_cookieStore)
2022 m_cookieStore = API::HTTPCookieStore::create(*this);
2023
2024 return *m_cookieStore;
2025}
2026
2027void WebsiteDataStore::didCreateNetworkProcess()
2028{
2029}
2030
2031bool WebsiteDataStore::setSourceApplicationSecondaryIdentifier(String&& identifier)
2032{
2033 if (m_networkingHasBegun)
2034 return false;
2035 m_sourceApplicationSecondaryIdentifier = WTFMove(identifier);
2036 return true;
2037}
2038
2039bool WebsiteDataStore::setAllowsTLSFallback(bool allows)
2040{
2041 if (m_networkingHasBegun)
2042 return false;
2043 m_allowsTLSFallback = allows;
2044 return true;
2045}
2046
2047bool WebsiteDataStore::setSourceApplicationBundleIdentifier(String&& identifier)
2048{
2049 if (m_networkingHasBegun)
2050 return false;
2051 m_sourceApplicationBundleIdentifier = WTFMove(identifier);
2052 return true;
2053}
2054
2055void WebsiteDataStore::getLocalStorageDetails(Function<void(Vector<LocalStorageDatabaseTracker::OriginDetails>&&)>&& completionHandler)
2056{
2057 if (!isPersistent()) {
2058 completionHandler({ });
2059 return;
2060 }
2061
2062 for (auto& processPool : processPools()) {
2063 processPool->ensureNetworkProcess(this);
2064 processPool->networkProcess()->getLocalStorageDetails(m_sessionID, [completionHandler = WTFMove(completionHandler)](auto&& details) {
2065 completionHandler(WTFMove(details));
2066 });
2067 // FIXME: Support fetching from multiple pools.
2068 break;
2069 }
2070 ASSERT(!completionHandler);
2071}
2072
2073}
2074