1/*
2 * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
3 * Copyright (C) 2018 Sony Interactive Entertainment Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "NetworkProcess.h"
29
30#include "ArgumentCoders.h"
31#include "Attachment.h"
32#include "AuthenticationManager.h"
33#include "AuxiliaryProcessMessages.h"
34#include "DataReference.h"
35#include "Download.h"
36#include "DownloadProxyMessages.h"
37#if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
38#include "LegacyCustomProtocolManager.h"
39#endif
40#include "Logging.h"
41#include "NetworkConnectionToWebProcess.h"
42#include "NetworkContentRuleListManagerMessages.h"
43#include "NetworkLoad.h"
44#include "NetworkProcessCreationParameters.h"
45#include "NetworkProcessPlatformStrategies.h"
46#include "NetworkProcessProxyMessages.h"
47#include "NetworkResourceLoadMap.h"
48#include "NetworkResourceLoader.h"
49#include "NetworkSession.h"
50#include "NetworkSessionCreationParameters.h"
51#include "PreconnectTask.h"
52#include "RemoteNetworkingContext.h"
53#include "ShouldGrandfatherStatistics.h"
54#include "StatisticsData.h"
55#include "StorageAccessStatus.h"
56#include "WebCookieManager.h"
57#include "WebPageProxyMessages.h"
58#include "WebProcessPoolMessages.h"
59#include "WebResourceLoadStatisticsStore.h"
60#include "WebSWOriginStore.h"
61#include "WebSWServerConnection.h"
62#include "WebSWServerToContextConnection.h"
63#include "WebsiteDataFetchOption.h"
64#include "WebsiteDataStore.h"
65#include "WebsiteDataStoreParameters.h"
66#include "WebsiteDataType.h"
67#include <WebCore/CookieJar.h>
68#include <WebCore/DNS.h>
69#include <WebCore/DeprecatedGlobalSettings.h>
70#include <WebCore/DiagnosticLoggingClient.h>
71#include <WebCore/LogInitialization.h>
72#include <WebCore/MIMETypeRegistry.h>
73#include <WebCore/NetworkStateNotifier.h>
74#include <WebCore/NetworkStorageSession.h>
75#include <WebCore/ResourceRequest.h>
76#include <WebCore/RuntimeApplicationChecks.h>
77#include <WebCore/RuntimeEnabledFeatures.h>
78#include <WebCore/SchemeRegistry.h>
79#include <WebCore/SecurityOriginData.h>
80#include <WebCore/StorageQuotaManager.h>
81#include <wtf/Algorithms.h>
82#include <wtf/CallbackAggregator.h>
83#include <wtf/OptionSet.h>
84#include <wtf/ProcessPrivilege.h>
85#include <wtf/RunLoop.h>
86#include <wtf/text/AtomicString.h>
87
88#if ENABLE(SEC_ITEM_SHIM)
89#include "SecItemShim.h"
90#endif
91
92#include "NetworkCache.h"
93#include "NetworkCacheCoders.h"
94
95#if PLATFORM(COCOA)
96#include "NetworkSessionCocoa.h"
97#endif
98
99#if USE(SOUP)
100#include <WebCore/DNSResolveQueueSoup.h>
101#include <WebCore/SoupNetworkSession.h>
102#endif
103
104#if USE(CURL)
105#include <WebCore/CurlContext.h>
106#endif
107
108#if ENABLE(SERVICE_WORKER)
109#include "WebSWServerToContextConnectionMessages.h"
110#endif
111
112namespace WebKit {
113using namespace WebCore;
114
115static void callExitSoon(IPC::Connection*)
116{
117 // If the connection has been closed and we haven't responded in the main thread for 10 seconds
118 // the process will exit forcibly.
119 auto watchdogDelay = 10_s;
120
121 WorkQueue::create("com.apple.WebKit.NetworkProcess.WatchDogQueue")->dispatchAfter(watchdogDelay, [] {
122 // We use _exit here since the watchdog callback is called from another thread and we don't want
123 // global destructors or atexit handlers to be called from this thread while the main thread is busy
124 // doing its thing.
125 RELEASE_LOG_ERROR(IPC, "Exiting process early due to unacknowledged closed-connection");
126 _exit(EXIT_FAILURE);
127 });
128}
129
130NetworkProcess::NetworkProcess(AuxiliaryProcessInitializationParameters&& parameters)
131 : m_downloadManager(*this)
132#if ENABLE(CONTENT_EXTENSIONS)
133 , m_networkContentRuleListManager(*this)
134#endif
135#if PLATFORM(IOS_FAMILY)
136 , m_webSQLiteDatabaseTracker([this](bool isHoldingLockedFiles) { parentProcessConnection()->send(Messages::NetworkProcessProxy::SetIsHoldingLockedFiles(isHoldingLockedFiles), 0); })
137#endif
138{
139 NetworkProcessPlatformStrategies::initialize();
140
141 addSupplement<AuthenticationManager>();
142 addSupplement<WebCookieManager>();
143#if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER)
144 addSupplement<LegacyCustomProtocolManager>();
145#endif
146#if PLATFORM(COCOA) || USE(SOUP)
147 LegacyCustomProtocolManager::networkProcessCreated(*this);
148#endif
149
150#if USE(SOUP)
151 DNSResolveQueueSoup::setGlobalDefaultNetworkStorageSessionAccessor([this]() -> NetworkStorageSession& {
152 return defaultStorageSession();
153 });
154#endif
155
156 NetworkStateNotifier::singleton().addListener([weakThis = makeWeakPtr(*this)](bool isOnLine) {
157 if (!weakThis)
158 return;
159 for (auto& webProcessConnection : weakThis->m_webProcessConnections)
160 webProcessConnection->setOnLineState(isOnLine);
161 });
162
163 initialize(WTFMove(parameters));
164}
165
166NetworkProcess::~NetworkProcess()
167{
168 for (auto& callbacks : m_cacheStorageParametersCallbacks.values()) {
169 for (auto& callback : callbacks)
170 callback(String { });
171 }
172}
173
174AuthenticationManager& NetworkProcess::authenticationManager()
175{
176 return *supplement<AuthenticationManager>();
177}
178
179DownloadManager& NetworkProcess::downloadManager()
180{
181 return m_downloadManager;
182}
183
184void NetworkProcess::removeNetworkConnectionToWebProcess(NetworkConnectionToWebProcess& connection)
185{
186 auto count = m_webProcessConnections.removeAllMatching([&] (const auto& c) {
187 return c.ptr() == &connection;
188 });
189 ASSERT_UNUSED(count, count == 1);
190}
191
192bool NetworkProcess::shouldTerminate()
193{
194 // Network process keeps session cookies and credentials, so it should never terminate (as long as UI process connection is alive).
195 return false;
196}
197
198void NetworkProcess::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
199{
200 if (messageReceiverMap().dispatchMessage(connection, decoder))
201 return;
202
203 if (decoder.messageReceiverName() == Messages::AuxiliaryProcess::messageReceiverName()) {
204 AuxiliaryProcess::didReceiveMessage(connection, decoder);
205 return;
206 }
207
208#if ENABLE(CONTENT_EXTENSIONS)
209 if (decoder.messageReceiverName() == Messages::NetworkContentRuleListManager::messageReceiverName()) {
210 m_networkContentRuleListManager.didReceiveMessage(connection, decoder);
211 return;
212 }
213#endif
214
215#if ENABLE(SERVICE_WORKER)
216 if (decoder.messageReceiverName() == Messages::WebSWServerToContextConnection::messageReceiverName()) {
217 ASSERT(parentProcessHasServiceWorkerEntitlement());
218 if (!parentProcessHasServiceWorkerEntitlement())
219 return;
220 if (auto* webSWConnection = connectionToContextProcessFromIPCConnection(connection)) {
221 webSWConnection->didReceiveMessage(connection, decoder);
222 return;
223 }
224 }
225#endif
226 didReceiveNetworkProcessMessage(connection, decoder);
227}
228
229void NetworkProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
230{
231 if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder))
232 return;
233
234 didReceiveSyncNetworkProcessMessage(connection, decoder, replyEncoder);
235}
236
237void NetworkProcess::didClose(IPC::Connection&)
238{
239 ASSERT(RunLoop::isMain());
240
241 // Make sure we flush all cookies to disk before exiting.
242 platformSyncAllCookies([this] {
243 stopRunLoop();
244 });
245}
246
247void NetworkProcess::didCreateDownload()
248{
249 disableTermination();
250}
251
252void NetworkProcess::didDestroyDownload()
253{
254 enableTermination();
255}
256
257IPC::Connection* NetworkProcess::downloadProxyConnection()
258{
259 return parentProcessConnection();
260}
261
262AuthenticationManager& NetworkProcess::downloadsAuthenticationManager()
263{
264 return authenticationManager();
265}
266
267void NetworkProcess::lowMemoryHandler(Critical critical)
268{
269 if (m_suppressMemoryPressureHandler)
270 return;
271
272 WTF::releaseFastMallocFreeMemory();
273
274 for (auto& networkSession : m_networkSessions.values())
275 networkSession.get().clearPrefetchCache();
276}
277
278void NetworkProcess::initializeNetworkProcess(NetworkProcessCreationParameters&& parameters)
279{
280#if HAVE(SEC_KEY_PROXY)
281 WTF::setProcessPrivileges({ ProcessPrivilege::CanAccessRawCookies });
282#else
283 WTF::setProcessPrivileges({ ProcessPrivilege::CanAccessRawCookies, ProcessPrivilege::CanAccessCredentials });
284#endif
285 WebCore::NetworkStorageSession::permitProcessToUseCookieAPI(true);
286 platformInitializeNetworkProcess(parameters);
287
288 WTF::Thread::setCurrentThreadIsUserInitiated();
289 AtomicString::init();
290
291 m_suppressMemoryPressureHandler = parameters.shouldSuppressMemoryPressureHandler;
292 if (!m_suppressMemoryPressureHandler) {
293 auto& memoryPressureHandler = MemoryPressureHandler::singleton();
294 memoryPressureHandler.setLowMemoryHandler([this] (Critical critical, Synchronous) {
295 lowMemoryHandler(critical);
296 });
297 memoryPressureHandler.install();
298 }
299
300 m_diskCacheIsDisabledForTesting = parameters.shouldUseTestingNetworkSession;
301
302 setCacheModel(parameters.cacheModel);
303
304 setCanHandleHTTPSServerTrustEvaluation(parameters.canHandleHTTPSServerTrustEvaluation);
305
306 if (parameters.shouldUseTestingNetworkSession)
307 switchToNewTestingSession();
308
309 WebCore::RuntimeEnabledFeatures::sharedFeatures().setIsITPDatabaseEnabled(parameters.shouldEnableITPDatabase);
310 WebCore::RuntimeEnabledFeatures::sharedFeatures().setIsITPFirstPartyWebsiteDataRemovalEnabled(parameters.isITPFirstPartyWebsiteDataRemovalEnabled);
311
312 WebCore::RuntimeEnabledFeatures::sharedFeatures().setAdClickAttributionDebugModeEnabled(parameters.enableAdClickAttributionDebugMode);
313
314 SandboxExtension::consumePermanently(parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectoryExtensionHandle);
315
316 auto sessionID = parameters.defaultDataStoreParameters.networkSessionParameters.sessionID;
317 setSession(sessionID, NetworkSession::create(*this, WTFMove(parameters.defaultDataStoreParameters.networkSessionParameters)));
318
319#if ENABLE(INDEXED_DATABASE)
320 addIndexedDatabaseSession(sessionID, parameters.defaultDataStoreParameters.indexedDatabaseDirectory, parameters.defaultDataStoreParameters.indexedDatabaseDirectoryExtensionHandle);
321#endif
322
323#if ENABLE(SERVICE_WORKER)
324 if (parentProcessHasServiceWorkerEntitlement()) {
325 addServiceWorkerSession(PAL::SessionID::defaultSessionID(), parameters.serviceWorkerRegistrationDirectory, parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
326
327 for (auto& scheme : parameters.urlSchemesServiceWorkersCanHandle)
328 registerURLSchemeServiceWorkersCanHandle(scheme);
329
330 m_shouldDisableServiceWorkerProcessTerminationDelay = parameters.shouldDisableServiceWorkerProcessTerminationDelay;
331 }
332#endif
333 initializeStorageQuota(parameters.defaultDataStoreParameters);
334
335 auto* defaultSession = networkSession(PAL::SessionID::defaultSessionID());
336 for (const auto& cookie : parameters.defaultDataStoreParameters.pendingCookies)
337 defaultSession->networkStorageSession().setCookie(cookie);
338
339 for (auto& supplement : m_supplements.values())
340 supplement->initialize(parameters);
341
342 for (auto& scheme : parameters.urlSchemesRegisteredAsSecure)
343 registerURLSchemeAsSecure(scheme);
344
345 for (auto& scheme : parameters.urlSchemesRegisteredAsBypassingContentSecurityPolicy)
346 registerURLSchemeAsBypassingContentSecurityPolicy(scheme);
347
348 for (auto& scheme : parameters.urlSchemesRegisteredAsLocal)
349 registerURLSchemeAsLocal(scheme);
350
351 for (auto& scheme : parameters.urlSchemesRegisteredAsNoAccess)
352 registerURLSchemeAsNoAccess(scheme);
353
354 for (auto& scheme : parameters.urlSchemesRegisteredAsDisplayIsolated)
355 registerURLSchemeAsDisplayIsolated(scheme);
356
357 for (auto& scheme : parameters.urlSchemesRegisteredAsCORSEnabled)
358 registerURLSchemeAsCORSEnabled(scheme);
359
360 for (auto& scheme : parameters.urlSchemesRegisteredAsCanDisplayOnlyIfCanRequest)
361 registerURLSchemeAsCanDisplayOnlyIfCanRequest(scheme);
362
363 m_downloadMonitorSpeedMultiplier = parameters.downloadMonitorSpeedMultiplier;
364
365 RELEASE_LOG(Process, "%p - NetworkProcess::initializeNetworkProcess: Presenting process = %d", this, WebCore::presentingApplicationPID());
366}
367
368void NetworkProcess::initializeConnection(IPC::Connection* connection)
369{
370 AuxiliaryProcess::initializeConnection(connection);
371
372 // We give a chance for didClose() to get called on the main thread but forcefully call _exit() after a delay
373 // in case the main thread is unresponsive or didClose() takes too long.
374 connection->setDidCloseOnConnectionWorkQueueCallback(callExitSoon);
375
376 for (auto& supplement : m_supplements.values())
377 supplement->initializeConnection(connection);
378}
379
380void NetworkProcess::createNetworkConnectionToWebProcess(bool isServiceWorkerProcess, WebCore::RegistrableDomain&& registrableDomain)
381{
382#if USE(UNIX_DOMAIN_SOCKETS)
383 IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection();
384
385 auto connection = NetworkConnectionToWebProcess::create(*this, socketPair.server);
386 m_webProcessConnections.append(WTFMove(connection));
387
388 IPC::Attachment clientSocket(socketPair.client);
389 parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCreateNetworkConnectionToWebProcess(clientSocket), 0);
390#elif OS(DARWIN)
391 // Create the listening port.
392 mach_port_t listeningPort = MACH_PORT_NULL;
393 auto kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &listeningPort);
394 if (kr != KERN_SUCCESS) {
395 RELEASE_LOG_ERROR(Process, "NetworkProcess::createNetworkConnectionToWebProcess: Could not allocate mach port, error %x", kr);
396 CRASH();
397 }
398 if (!MACH_PORT_VALID(listeningPort)) {
399 RELEASE_LOG_ERROR(Process, "NetworkProcess::createNetworkConnectionToWebProcess: Could not allocate mach port, returned port was invalid");
400 CRASH();
401 }
402
403 // Create a listening connection.
404 auto connection = NetworkConnectionToWebProcess::create(*this, IPC::Connection::Identifier(listeningPort));
405 m_webProcessConnections.append(WTFMove(connection));
406
407 IPC::Attachment clientPort(listeningPort, MACH_MSG_TYPE_MAKE_SEND);
408 parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCreateNetworkConnectionToWebProcess(clientPort), 0);
409#elif OS(WINDOWS)
410 IPC::Connection::Identifier serverIdentifier, clientIdentifier;
411 if (!IPC::Connection::createServerAndClientIdentifiers(serverIdentifier, clientIdentifier)) {
412 LOG_ERROR("Failed to create server and client identifiers");
413 CRASH();
414 }
415
416 auto connection = NetworkConnectionToWebProcess::create(*this, serverIdentifier);
417 m_webProcessConnections.append(WTFMove(connection));
418
419 IPC::Attachment clientSocket(clientIdentifier);
420 parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCreateNetworkConnectionToWebProcess(clientSocket), 0);
421#else
422 notImplemented();
423#endif
424
425 if (!m_webProcessConnections.isEmpty())
426 m_webProcessConnections.last()->setOnLineState(NetworkStateNotifier::singleton().onLine());
427
428#if ENABLE(SERVICE_WORKER)
429 if (isServiceWorkerProcess && !m_webProcessConnections.isEmpty()) {
430 ASSERT(parentProcessHasServiceWorkerEntitlement());
431 ASSERT(m_waitingForServerToContextProcessConnection);
432 auto contextConnection = WebSWServerToContextConnection::create(*this, registrableDomain, m_webProcessConnections.last()->connection());
433 auto addResult = m_serverToContextConnections.add(WTFMove(registrableDomain), contextConnection.copyRef());
434 ASSERT_UNUSED(addResult, addResult.isNewEntry);
435
436 m_waitingForServerToContextProcessConnection = false;
437
438 for (auto* server : SWServer::allServers())
439 server->serverToContextConnectionCreated(contextConnection);
440 }
441#else
442 UNUSED_PARAM(isServiceWorkerProcess);
443 UNUSED_PARAM(registrableDomain);
444#endif
445}
446
447void NetworkProcess::clearCachedCredentials()
448{
449 defaultStorageSession().credentialStorage().clearCredentials();
450 if (auto* networkSession = this->networkSession(PAL::SessionID::defaultSessionID()))
451 networkSession->clearCredentials();
452 else
453 ASSERT_NOT_REACHED();
454}
455
456void NetworkProcess::addWebsiteDataStore(WebsiteDataStoreParameters&& parameters)
457{
458#if ENABLE(INDEXED_DATABASE)
459 addIndexedDatabaseSession(parameters.networkSessionParameters.sessionID, parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle);
460#endif
461
462#if ENABLE(SERVICE_WORKER)
463 if (parentProcessHasServiceWorkerEntitlement())
464 addServiceWorkerSession(parameters.networkSessionParameters.sessionID, parameters.serviceWorkerRegistrationDirectory, parameters.serviceWorkerRegistrationDirectoryExtensionHandle);
465#endif
466
467 initializeStorageQuota(parameters);
468
469 RemoteNetworkingContext::ensureWebsiteDataStoreSession(*this, WTFMove(parameters));
470}
471
472void NetworkProcess::initializeStorageQuota(const WebsiteDataStoreParameters& parameters)
473{
474 auto& managers = m_storageQuotaManagers.ensure(parameters.networkSessionParameters.sessionID, [] {
475 return StorageQuotaManagers { };
476 }).iterator->value;
477 managers.setDefaultQuotas(parameters.perOriginStorageQuota, parameters.perThirdPartyOriginStorageQuota);
478}
479
480void NetworkProcess::switchToNewTestingSession()
481{
482#if PLATFORM(COCOA)
483 // Session name should be short enough for shared memory region name to be under the limit, otherwise sandbox rules won't work (see <rdar://problem/13642852>).
484 String sessionName = makeString("WebKit Test-", getCurrentProcessID());
485
486 auto session = adoptCF(WebCore::createPrivateStorageSession(sessionName.createCFString().get()));
487
488 RetainPtr<CFHTTPCookieStorageRef> cookieStorage;
489 if (WebCore::NetworkStorageSession::processMayUseCookieAPI()) {
490 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
491 if (session)
492 cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, session.get()));
493 }
494
495 m_defaultNetworkStorageSession = std::make_unique<WebCore::NetworkStorageSession>(PAL::SessionID::defaultSessionID(), WTFMove(session), WTFMove(cookieStorage));
496#elif USE(SOUP)
497 m_defaultNetworkStorageSession = std::make_unique<WebCore::NetworkStorageSession>(PAL::SessionID::defaultSessionID(), std::make_unique<WebCore::SoupNetworkSession>());
498#elif USE(CURL)
499 m_defaultNetworkStorageSession = std::make_unique<WebCore::NetworkStorageSession>(PAL::SessionID::defaultSessionID());
500#endif
501}
502
503#if PLATFORM(COCOA)
504void NetworkProcess::ensureSession(const PAL::SessionID& sessionID, const String& identifierBase, RetainPtr<CFHTTPCookieStorageRef>&& cookieStorage)
505#else
506void NetworkProcess::ensureSession(const PAL::SessionID& sessionID, const String& identifierBase)
507#endif
508{
509 ASSERT(sessionID != PAL::SessionID::defaultSessionID());
510
511 auto addResult = m_networkStorageSessions.add(sessionID, nullptr);
512 if (!addResult.isNewEntry)
513 return;
514
515#if PLATFORM(COCOA)
516 RetainPtr<CFURLStorageSessionRef> storageSession;
517 RetainPtr<CFStringRef> cfIdentifier = String(identifierBase + ".PrivateBrowsing").createCFString();
518 if (sessionID.isEphemeral())
519 storageSession = adoptCF(createPrivateStorageSession(cfIdentifier.get()));
520 else
521 storageSession = WebCore::NetworkStorageSession::createCFStorageSessionForIdentifier(cfIdentifier.get());
522
523 if (NetworkStorageSession::processMayUseCookieAPI()) {
524 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
525 if (!cookieStorage && storageSession)
526 cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, storageSession.get()));
527 }
528
529 addResult.iterator->value = std::make_unique<NetworkStorageSession>(sessionID, WTFMove(storageSession), WTFMove(cookieStorage));
530#elif USE(SOUP)
531 addResult.iterator->value = std::make_unique<NetworkStorageSession>(sessionID, std::make_unique<SoupNetworkSession>(sessionID));
532#elif USE(CURL)
533 addResult.iterator->value = std::make_unique<NetworkStorageSession>(sessionID);
534#endif
535}
536
537WebCore::NetworkStorageSession* NetworkProcess::storageSession(const PAL::SessionID& sessionID) const
538{
539 if (sessionID == PAL::SessionID::defaultSessionID())
540 return &defaultStorageSession();
541 return m_networkStorageSessions.get(sessionID);
542}
543
544WebCore::NetworkStorageSession& NetworkProcess::defaultStorageSession() const
545{
546 if (!m_defaultNetworkStorageSession)
547 m_defaultNetworkStorageSession = platformCreateDefaultStorageSession();
548 return *m_defaultNetworkStorageSession;
549}
550
551void NetworkProcess::forEachNetworkStorageSession(const Function<void(WebCore::NetworkStorageSession&)>& functor)
552{
553 functor(defaultStorageSession());
554 for (auto& storageSession : m_networkStorageSessions.values())
555 functor(*storageSession);
556}
557
558NetworkSession* NetworkProcess::networkSession(const PAL::SessionID& sessionID) const
559{
560 return m_networkSessions.get(sessionID);
561}
562
563void NetworkProcess::setSession(const PAL::SessionID& sessionID, Ref<NetworkSession>&& session)
564{
565 m_networkSessions.set(sessionID, WTFMove(session));
566}
567
568void NetworkProcess::destroySession(const PAL::SessionID& sessionID)
569{
570 ASSERT(sessionID != PAL::SessionID::defaultSessionID());
571
572 if (auto session = m_networkSessions.take(sessionID))
573 session->get().invalidateAndCancel();
574 m_networkStorageSessions.remove(sessionID);
575 m_sessionsControlledByAutomation.remove(sessionID);
576 CacheStorage::Engine::destroyEngine(*this, sessionID);
577
578#if ENABLE(SERVICE_WORKER)
579 m_swServers.remove(sessionID);
580 m_swDatabasePaths.remove(sessionID);
581#endif
582
583 m_storageQuotaManagers.remove(sessionID);
584}
585
586#if ENABLE(RESOURCE_LOAD_STATISTICS)
587void NetworkProcess::dumpResourceLoadStatistics(PAL::SessionID sessionID, CompletionHandler<void(String)>&& completionHandler)
588{
589 if (auto* networkSession = this->networkSession(sessionID)) {
590 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
591 resourceLoadStatistics->dumpResourceLoadStatistics(WTFMove(completionHandler));
592 else
593 completionHandler({ });
594 } else {
595 ASSERT_NOT_REACHED();
596 completionHandler({ });
597 }
598}
599
600void NetworkProcess::updatePrevalentDomainsToBlockCookiesFor(PAL::SessionID sessionID, const Vector<RegistrableDomain>& domainsToBlock, CompletionHandler<void()>&& completionHandler)
601{
602 if (auto* networkStorageSession = storageSession(sessionID))
603 networkStorageSession->setPrevalentDomainsToBlockCookiesFor(domainsToBlock);
604 completionHandler();
605}
606
607void NetworkProcess::isGrandfathered(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler)
608{
609 if (auto* networkSession = this->networkSession(sessionID)) {
610 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
611 resourceLoadStatistics->isGrandfathered(domain, WTFMove(completionHandler));
612 else
613 completionHandler(false);
614 } else {
615 ASSERT_NOT_REACHED();
616 completionHandler(false);
617 }
618}
619
620void NetworkProcess::isPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler)
621{
622 if (auto* networkSession = this->networkSession(sessionID)) {
623 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
624 resourceLoadStatistics->isPrevalentResource(domain, WTFMove(completionHandler));
625 else
626 completionHandler(false);
627 } else {
628 ASSERT_NOT_REACHED();
629 completionHandler(false);
630 }
631}
632
633void NetworkProcess::isVeryPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler)
634{
635 if (auto* networkSession = this->networkSession(sessionID)) {
636 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
637 resourceLoadStatistics->isVeryPrevalentResource(domain, WTFMove(completionHandler));
638 else
639 completionHandler(false);
640 } else {
641 ASSERT_NOT_REACHED();
642 completionHandler(false);
643 }
644}
645
646void NetworkProcess::setAgeCapForClientSideCookies(PAL::SessionID sessionID, Optional<Seconds> seconds, CompletionHandler<void()>&& completionHandler)
647{
648 if (auto* networkStorageSession = storageSession(sessionID))
649 networkStorageSession->setAgeCapForClientSideCookies(seconds);
650 completionHandler();
651}
652
653void NetworkProcess::setGrandfathered(PAL::SessionID sessionID, const RegistrableDomain& domain, bool isGrandfathered, CompletionHandler<void()>&& completionHandler)
654{
655 if (auto* networkSession = this->networkSession(sessionID)) {
656 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
657 resourceLoadStatistics->setGrandfathered(domain, isGrandfathered, WTFMove(completionHandler));
658 else
659 completionHandler();
660 } else {
661 ASSERT_NOT_REACHED();
662 completionHandler();
663 }
664}
665
666void NetworkProcess::setPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
667{
668 if (auto* networkSession = this->networkSession(sessionID)) {
669 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
670 resourceLoadStatistics->setPrevalentResource(domain, WTFMove(completionHandler));
671 else
672 completionHandler();
673 } else {
674 ASSERT_NOT_REACHED();
675 completionHandler();
676 }
677}
678
679void NetworkProcess::setPrevalentResourceForDebugMode(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
680{
681 if (auto* networkSession = this->networkSession(sessionID)) {
682 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
683 resourceLoadStatistics->setPrevalentResourceForDebugMode(domain, WTFMove(completionHandler));
684 else
685 completionHandler();
686 } else {
687 ASSERT_NOT_REACHED();
688 completionHandler();
689 }
690}
691
692void NetworkProcess::setVeryPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
693{
694 if (auto* networkSession = this->networkSession(sessionID)) {
695 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
696 resourceLoadStatistics->setVeryPrevalentResource(domain, WTFMove(completionHandler));
697 else
698 completionHandler();
699 } else {
700 ASSERT_NOT_REACHED();
701 completionHandler();
702 }
703}
704
705void NetworkProcess::clearPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
706{
707 if (auto* networkSession = this->networkSession(sessionID)) {
708 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
709 resourceLoadStatistics->clearPrevalentResource(domain, WTFMove(completionHandler));
710 else
711 completionHandler();
712 } else {
713 ASSERT_NOT_REACHED();
714 completionHandler();
715 }
716}
717
718void NetworkProcess::submitTelemetry(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
719{
720 if (auto* networkSession = this->networkSession(sessionID)) {
721 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
722 resourceLoadStatistics->submitTelemetry(WTFMove(completionHandler));
723 else
724 completionHandler();
725 } else {
726 ASSERT_NOT_REACHED();
727 completionHandler();
728 }
729}
730
731void NetworkProcess::scheduleCookieBlockingUpdate(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
732{
733 if (auto* networkSession = this->networkSession(sessionID)) {
734 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
735 resourceLoadStatistics->scheduleCookieBlockingUpdate(WTFMove(completionHandler));
736 else
737 completionHandler();
738 } else {
739 ASSERT_NOT_REACHED();
740 completionHandler();
741 }
742}
743
744void NetworkProcess::scheduleClearInMemoryAndPersistent(PAL::SessionID sessionID, Optional<WallTime> modifiedSince, ShouldGrandfatherStatistics shouldGrandfather, CompletionHandler<void()>&& completionHandler)
745{
746 if (auto* networkSession = this->networkSession(sessionID)) {
747 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) {
748 if (modifiedSince)
749 resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince.value(), shouldGrandfather, WTFMove(completionHandler));
750 else
751 resourceLoadStatistics->scheduleClearInMemoryAndPersistent(shouldGrandfather, WTFMove(completionHandler));
752 } else
753 completionHandler();
754 } else {
755 ASSERT_NOT_REACHED();
756 completionHandler();
757 }
758}
759
760void NetworkProcess::resetParametersToDefaultValues(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
761{
762 if (auto* networkSession = this->networkSession(sessionID)) {
763 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
764 resourceLoadStatistics->resetParametersToDefaultValues(WTFMove(completionHandler));
765 else
766 completionHandler();
767 } else {
768 ASSERT_NOT_REACHED();
769 completionHandler();
770 }
771}
772
773void NetworkProcess::scheduleStatisticsAndDataRecordsProcessing(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
774{
775 if (auto* networkSession = this->networkSession(sessionID)) {
776 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
777 resourceLoadStatistics->scheduleStatisticsAndDataRecordsProcessing(WTFMove(completionHandler));
778 else
779 completionHandler();
780 } else {
781 ASSERT_NOT_REACHED();
782 completionHandler();
783 }
784}
785
786void NetworkProcess::setNotifyPagesWhenDataRecordsWereScanned(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler)
787{
788 if (auto* networkSession = this->networkSession(sessionID)) {
789 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
790 resourceLoadStatistics->setNotifyPagesWhenDataRecordsWereScanned(value, WTFMove(completionHandler));
791 else
792 completionHandler();
793 } else {
794 ASSERT_NOT_REACHED();
795 completionHandler();
796 }
797}
798
799void NetworkProcess::setIsRunningResourceLoadStatisticsTest(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler)
800{
801 if (auto* networkSession = this->networkSession(sessionID)) {
802 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
803 resourceLoadStatistics->setIsRunningTest(value, WTFMove(completionHandler));
804 else
805 completionHandler();
806 } else {
807 ASSERT_NOT_REACHED();
808 completionHandler();
809 }
810}
811
812void NetworkProcess::setNotifyPagesWhenTelemetryWasCaptured(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler)
813{
814 if (auto* networkSession = this->networkSession(sessionID)) {
815 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
816 resourceLoadStatistics->setNotifyPagesWhenTelemetryWasCaptured(value, WTFMove(completionHandler));
817 else
818 completionHandler();
819 } else {
820 ASSERT_NOT_REACHED();
821 completionHandler();
822 }
823}
824
825void NetworkProcess::setSubframeUnderTopFrameDomain(PAL::SessionID sessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, CompletionHandler<void()>&& completionHandler)
826{
827 if (auto* networkSession = this->networkSession(sessionID)) {
828 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
829 resourceLoadStatistics->setSubframeUnderTopFrameDomain(subFrameDomain, topFrameDomain, WTFMove(completionHandler));
830 else
831 completionHandler();
832 } else {
833 ASSERT_NOT_REACHED();
834 completionHandler();
835 }
836}
837
838void NetworkProcess::isRegisteredAsRedirectingTo(PAL::SessionID sessionID, const RegistrableDomain& domainRedirectedFrom, const RegistrableDomain& domainRedirectedTo, CompletionHandler<void(bool)>&& completionHandler)
839{
840 if (auto* networkSession = this->networkSession(sessionID)) {
841 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
842 resourceLoadStatistics->isRegisteredAsRedirectingTo(domainRedirectedFrom, domainRedirectedTo, WTFMove(completionHandler));
843 else
844 completionHandler(false);
845 } else {
846 ASSERT_NOT_REACHED();
847 completionHandler(false);
848 }
849}
850
851void NetworkProcess::isRegisteredAsSubFrameUnder(PAL::SessionID sessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, CompletionHandler<void(bool)>&& completionHandler)
852{
853 if (auto* networkSession = this->networkSession(sessionID)) {
854 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
855 resourceLoadStatistics->isRegisteredAsSubFrameUnder(subFrameDomain, topFrameDomain, WTFMove(completionHandler));
856 else
857 completionHandler(false);
858 } else {
859 ASSERT_NOT_REACHED();
860 completionHandler(false);
861 }
862}
863
864void NetworkProcess::setSubresourceUnderTopFrameDomain(PAL::SessionID sessionID, const RegistrableDomain& subresourceDomain, const RegistrableDomain& topFrameDomain, CompletionHandler<void()>&& completionHandler)
865{
866 if (auto* networkSession = this->networkSession(sessionID)) {
867 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
868 resourceLoadStatistics->setSubresourceUnderTopFrameDomain(subresourceDomain, topFrameDomain, WTFMove(completionHandler));
869 else
870 completionHandler();
871 } else {
872 ASSERT_NOT_REACHED();
873 completionHandler();
874 }
875}
876
877void NetworkProcess::setSubresourceUniqueRedirectTo(PAL::SessionID sessionID, const RegistrableDomain& subresourceDomain, const RegistrableDomain& domainRedirectedTo, CompletionHandler<void()>&& completionHandler)
878{
879 if (auto* networkSession = this->networkSession(sessionID)) {
880 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
881 resourceLoadStatistics->setSubresourceUniqueRedirectTo(subresourceDomain, domainRedirectedTo, WTFMove(completionHandler));
882 else
883 completionHandler();
884 } else {
885 ASSERT_NOT_REACHED();
886 completionHandler();
887 }
888}
889
890void NetworkProcess::setSubresourceUniqueRedirectFrom(PAL::SessionID sessionID, const RegistrableDomain& subresourceDomain, const RegistrableDomain& domainRedirectedFrom, CompletionHandler<void()>&& completionHandler)
891{
892 if (auto* networkSession = this->networkSession(sessionID)) {
893 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
894 resourceLoadStatistics->setSubresourceUniqueRedirectFrom(subresourceDomain, domainRedirectedFrom, WTFMove(completionHandler));
895 else
896 completionHandler();
897 } else {
898 ASSERT_NOT_REACHED();
899 completionHandler();
900 }
901}
902
903void NetworkProcess::isRegisteredAsSubresourceUnder(PAL::SessionID sessionID, const RegistrableDomain& subresourceDomain, const RegistrableDomain& topFrameDomain, CompletionHandler<void(bool)>&& completionHandler)
904{
905 if (auto* networkSession = this->networkSession(sessionID)) {
906 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
907 resourceLoadStatistics->isRegisteredAsSubresourceUnder(subresourceDomain, topFrameDomain, WTFMove(completionHandler));
908 else
909 completionHandler(false);
910 } else {
911 ASSERT_NOT_REACHED();
912 completionHandler(false);
913 }
914}
915
916void NetworkProcess::setTopFrameUniqueRedirectTo(PAL::SessionID sessionID, const RegistrableDomain& topFrameDomain, const RegistrableDomain& domainRedirectedTo, CompletionHandler<void()>&& completionHandler)
917{
918 if (auto* networkSession = this->networkSession(sessionID)) {
919 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
920 resourceLoadStatistics->setTopFrameUniqueRedirectTo(topFrameDomain, domainRedirectedTo, WTFMove(completionHandler));
921 else
922 completionHandler();
923 } else {
924 ASSERT_NOT_REACHED();
925 completionHandler();
926 }
927}
928
929void NetworkProcess::setTopFrameUniqueRedirectFrom(PAL::SessionID sessionID, const RegistrableDomain& topFrameDomain, const RegistrableDomain& domainRedirectedFrom, CompletionHandler<void()>&& completionHandler)
930{
931 if (auto* networkSession = this->networkSession(sessionID)) {
932 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
933 resourceLoadStatistics->setTopFrameUniqueRedirectFrom(topFrameDomain, domainRedirectedFrom, WTFMove(completionHandler));
934 else
935 completionHandler();
936 } else {
937 ASSERT_NOT_REACHED();
938 completionHandler();
939 }
940}
941
942
943void NetworkProcess::setLastSeen(PAL::SessionID sessionID, const RegistrableDomain& domain, Seconds seconds, CompletionHandler<void()>&& completionHandler)
944{
945 if (auto* networkSession = this->networkSession(sessionID)) {
946 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
947 resourceLoadStatistics->setLastSeen(domain, seconds, WTFMove(completionHandler));
948 else
949 completionHandler();
950 } else {
951 ASSERT_NOT_REACHED();
952 completionHandler();
953 }
954}
955
956void NetworkProcess::getAllStorageAccessEntries(PAL::SessionID sessionID, CompletionHandler<void(Vector<String> domains)>&& completionHandler)
957{
958 if (auto* networkStorageSession = storageSession(sessionID))
959 completionHandler(networkStorageSession->getAllStorageAccessEntries());
960 else {
961 ASSERT_NOT_REACHED();
962 completionHandler({ });
963 }
964}
965
966void NetworkProcess::logFrameNavigation(PAL::SessionID sessionID, const RegistrableDomain& targetDomain, const RegistrableDomain& topFrameDomain, const RegistrableDomain& sourceDomain, bool isRedirect, bool isMainFrame)
967{
968 if (auto* networkSession = this->networkSession(sessionID)) {
969 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
970 resourceLoadStatistics->logFrameNavigation(targetDomain, topFrameDomain, sourceDomain, isRedirect, isMainFrame);
971 } else
972 ASSERT_NOT_REACHED();
973}
974
975void NetworkProcess::logUserInteraction(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
976{
977 if (auto* networkSession = this->networkSession(sessionID)) {
978 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
979 resourceLoadStatistics->logUserInteraction(domain, WTFMove(completionHandler));
980 else
981 completionHandler();
982 } else {
983 ASSERT_NOT_REACHED();
984 completionHandler();
985 }
986}
987
988void NetworkProcess::hadUserInteraction(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler)
989{
990 if (auto* networkSession = this->networkSession(sessionID)) {
991 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
992 resourceLoadStatistics->hasHadUserInteraction(domain, WTFMove(completionHandler));
993 else
994 completionHandler(false);
995 } else {
996 ASSERT_NOT_REACHED();
997 completionHandler(false);
998 }
999}
1000
1001void NetworkProcess::clearUserInteraction(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler)
1002{
1003 if (auto* networkSession = this->networkSession(sessionID)) {
1004 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1005 resourceLoadStatistics->clearUserInteraction(domain, WTFMove(completionHandler));
1006 else
1007 completionHandler();
1008 } else {
1009 ASSERT_NOT_REACHED();
1010 completionHandler();
1011 }
1012}
1013
1014void NetworkProcess::removePrevalentDomains(PAL::SessionID sessionID, const Vector<RegistrableDomain>& domains)
1015{
1016 if (auto* networkStorageSession = storageSession(sessionID))
1017 networkStorageSession->removePrevalentDomains(domains);
1018}
1019
1020void NetworkProcess::setCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler)
1021{
1022 if (auto* networkStorageSession = storageSession(sessionID))
1023 networkStorageSession->setCacheMaxAgeCapForPrevalentResources(Seconds { seconds });
1024 else
1025 ASSERT_NOT_REACHED();
1026 completionHandler();
1027}
1028
1029void NetworkProcess::setGrandfatheringTime(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler)
1030{
1031 if (auto* networkSession = this->networkSession(sessionID)) {
1032 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1033 resourceLoadStatistics->setGrandfatheringTime(seconds, WTFMove(completionHandler));
1034 else
1035 completionHandler();
1036 } else {
1037 ASSERT_NOT_REACHED();
1038 completionHandler();
1039 }
1040}
1041
1042void NetworkProcess::setMaxStatisticsEntries(PAL::SessionID sessionID, uint64_t maximumEntryCount, CompletionHandler<void()>&& completionHandler)
1043{
1044 if (auto* networkSession = this->networkSession(sessionID)) {
1045 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1046 resourceLoadStatistics->setMaxStatisticsEntries(maximumEntryCount, WTFMove(completionHandler));
1047 else
1048 completionHandler();
1049 } else {
1050 ASSERT_NOT_REACHED();
1051 completionHandler();
1052 }
1053}
1054
1055void NetworkProcess::setMinimumTimeBetweenDataRecordsRemoval(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler)
1056{
1057 if (auto* networkSession = this->networkSession(sessionID)) {
1058 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1059 resourceLoadStatistics->setMinimumTimeBetweenDataRecordsRemoval(seconds, WTFMove(completionHandler));
1060 else
1061 completionHandler();
1062 } else {
1063 ASSERT_NOT_REACHED();
1064 completionHandler();
1065 }
1066}
1067
1068void NetworkProcess::setPruneEntriesDownTo(PAL::SessionID sessionID, uint64_t pruneTargetCount, CompletionHandler<void()>&& completionHandler)
1069{
1070 if (auto* networkSession = this->networkSession(sessionID)) {
1071 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1072 resourceLoadStatistics->setPruneEntriesDownTo(pruneTargetCount, WTFMove(completionHandler));
1073 else
1074 completionHandler();
1075 } else {
1076 ASSERT_NOT_REACHED();
1077 completionHandler();
1078 }
1079}
1080
1081void NetworkProcess::setTimeToLiveUserInteraction(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler)
1082{
1083 if (auto* networkSession = this->networkSession(sessionID)) {
1084 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1085 resourceLoadStatistics->setTimeToLiveUserInteraction(seconds, WTFMove(completionHandler));
1086 else
1087 completionHandler();
1088 } else {
1089 ASSERT_NOT_REACHED();
1090 completionHandler();
1091 }
1092}
1093
1094void NetworkProcess::setShouldClassifyResourcesBeforeDataRecordsRemoval(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler)
1095{
1096 if (auto* networkSession = this->networkSession(sessionID)) {
1097 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1098 resourceLoadStatistics->setShouldClassifyResourcesBeforeDataRecordsRemoval(value, WTFMove(completionHandler));
1099 else
1100 completionHandler();
1101 } else {
1102 ASSERT_NOT_REACHED();
1103 completionHandler();
1104 }
1105}
1106
1107void NetworkProcess::setResourceLoadStatisticsEnabled(bool enabled)
1108{
1109 for (auto& networkSession : m_networkSessions.values())
1110 networkSession.get().setResourceLoadStatisticsEnabled(enabled);
1111}
1112
1113void NetworkProcess::setResourceLoadStatisticsDebugMode(PAL::SessionID sessionID, bool debugMode, CompletionHandler<void()>&& completionHandler)
1114{
1115 if (auto* networkSession = this->networkSession(sessionID)) {
1116 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1117 resourceLoadStatistics->setResourceLoadStatisticsDebugMode(debugMode, WTFMove(completionHandler));
1118 else
1119 completionHandler();
1120 } else {
1121 ASSERT_NOT_REACHED();
1122 completionHandler();
1123 }
1124}
1125
1126void NetworkProcess::resetCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
1127{
1128 if (auto* networkStorageSession = storageSession(sessionID))
1129 networkStorageSession->resetCacheMaxAgeCapForPrevalentResources();
1130 else
1131 ASSERT_NOT_REACHED();
1132 completionHandler();
1133}
1134
1135void NetworkProcess::committedCrossSiteLoadWithLinkDecoration(PAL::SessionID sessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, uint64_t pageID, CompletionHandler<void()>&& completionHandler)
1136{
1137 if (auto* networkStorageSession = storageSession(sessionID))
1138 networkStorageSession->committedCrossSiteLoadWithLinkDecoration(fromDomain, toDomain, pageID);
1139 else
1140 ASSERT_NOT_REACHED();
1141
1142 if (auto* networkSession = this->networkSession(sessionID)) {
1143 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1144 resourceLoadStatistics->logCrossSiteLoadWithLinkDecoration(fromDomain, toDomain, WTFMove(completionHandler));
1145 else
1146 completionHandler();
1147 } else {
1148 ASSERT_NOT_REACHED();
1149 completionHandler();
1150 }
1151}
1152
1153void NetworkProcess::setCrossSiteLoadWithLinkDecorationForTesting(PAL::SessionID sessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, CompletionHandler<void()>&& completionHandler)
1154{
1155 if (auto* networkSession = this->networkSession(sessionID)) {
1156 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
1157 resourceLoadStatistics->logCrossSiteLoadWithLinkDecoration(fromDomain, toDomain, WTFMove(completionHandler));
1158 else
1159 completionHandler();
1160 } else {
1161 ASSERT_NOT_REACHED();
1162 completionHandler();
1163 }
1164}
1165
1166void NetworkProcess::resetCrossSiteLoadsWithLinkDecorationForTesting(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
1167{
1168 if (auto* networkStorageSession = storageSession(sessionID))
1169 networkStorageSession->resetCrossSiteLoadsWithLinkDecorationForTesting();
1170 else
1171 ASSERT_NOT_REACHED();
1172 completionHandler();
1173}
1174#endif // ENABLE(RESOURCE_LOAD_STATISTICS)
1175
1176bool NetworkProcess::sessionIsControlledByAutomation(PAL::SessionID sessionID) const
1177{
1178 return m_sessionsControlledByAutomation.contains(sessionID);
1179}
1180
1181void NetworkProcess::setSessionIsControlledByAutomation(PAL::SessionID sessionID, bool controlled)
1182{
1183 if (controlled)
1184 m_sessionsControlledByAutomation.add(sessionID);
1185 else
1186 m_sessionsControlledByAutomation.remove(sessionID);
1187}
1188
1189static void fetchDiskCacheEntries(NetworkCache::Cache* cache, PAL::SessionID sessionID, OptionSet<WebsiteDataFetchOption> fetchOptions, CompletionHandler<void(Vector<WebsiteData::Entry>)>&& completionHandler)
1190{
1191 if (!cache) {
1192 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] () mutable {
1193 completionHandler({ });
1194 });
1195 return;
1196 }
1197
1198 HashMap<SecurityOriginData, uint64_t> originsAndSizes;
1199 cache->traverse([fetchOptions, completionHandler = WTFMove(completionHandler), originsAndSizes = WTFMove(originsAndSizes)](auto* traversalEntry) mutable {
1200 if (!traversalEntry) {
1201 Vector<WebsiteData::Entry> entries;
1202
1203 for (auto& originAndSize : originsAndSizes)
1204 entries.append(WebsiteData::Entry { originAndSize.key, WebsiteDataType::DiskCache, originAndSize.value });
1205
1206 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), entries = WTFMove(entries)] () mutable {
1207 completionHandler(entries);
1208 });
1209
1210 return;
1211 }
1212
1213 auto url = traversalEntry->entry.response().url();
1214 auto result = originsAndSizes.add({url.protocol().toString(), url.host().toString(), url.port()}, 0);
1215
1216 if (fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes))
1217 result.iterator->value += traversalEntry->entry.sourceStorageRecord().header.size() + traversalEntry->recordInfo.bodySize;
1218 });
1219}
1220
1221void NetworkProcess::fetchWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, uint64_t callbackID)
1222{
1223 struct CallbackAggregator final : public ThreadSafeRefCounted<CallbackAggregator> {
1224 explicit CallbackAggregator(Function<void (WebsiteData)>&& completionHandler)
1225 : m_completionHandler(WTFMove(completionHandler))
1226 {
1227 }
1228
1229 ~CallbackAggregator()
1230 {
1231 RunLoop::main().dispatch([completionHandler = WTFMove(m_completionHandler), websiteData = WTFMove(m_websiteData)] () mutable {
1232 completionHandler(websiteData);
1233 });
1234 }
1235
1236 CompletionHandler<void(WebsiteData)> m_completionHandler;
1237 WebsiteData m_websiteData;
1238 };
1239
1240 auto callbackAggregator = adoptRef(*new CallbackAggregator([this, callbackID] (WebsiteData websiteData) {
1241 parentProcessConnection()->send(Messages::NetworkProcessProxy::DidFetchWebsiteData(callbackID, websiteData), 0);
1242 }));
1243
1244 if (websiteDataTypes.contains(WebsiteDataType::Cookies)) {
1245 if (auto* networkStorageSession = storageSession(sessionID))
1246 networkStorageSession->getHostnamesWithCookies(callbackAggregator->m_websiteData.hostNamesWithCookies);
1247 }
1248
1249 if (websiteDataTypes.contains(WebsiteDataType::Credentials)) {
1250 if (storageSession(sessionID)) {
1251 auto securityOrigins = storageSession(sessionID)->credentialStorage().originsWithCredentials();
1252 for (auto& securityOrigin : securityOrigins)
1253 callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::Credentials, 0 });
1254 }
1255 }
1256
1257 if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) {
1258 CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
1259 callbackAggregator->m_websiteData.entries.appendVector(entries);
1260 });
1261 }
1262
1263#if PLATFORM(COCOA)
1264 if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) {
1265 if (auto* networkStorageSession = storageSession(sessionID))
1266 getHostNamesWithHSTSCache(*networkStorageSession, callbackAggregator->m_websiteData.hostNamesWithHSTSCache);
1267 }
1268#endif
1269
1270#if ENABLE(INDEXED_DATABASE)
1271 auto path = m_idbDatabasePaths.get(sessionID);
1272 if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
1273 // FIXME: Pick the right database store based on the session ID.
1274 postStorageTask(CrossThreadTask([this, callbackAggregator = callbackAggregator.copyRef(), path = WTFMove(path)]() mutable {
1275 RunLoop::main().dispatch([callbackAggregator = WTFMove(callbackAggregator), securityOrigins = indexedDatabaseOrigins(path)] {
1276 for (const auto& securityOrigin : securityOrigins)
1277 callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::IndexedDBDatabases, 0 });
1278 });
1279 }));
1280 }
1281#endif
1282
1283#if ENABLE(SERVICE_WORKER)
1284 path = m_swDatabasePaths.get(sessionID);
1285 if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) {
1286 swServerForSession(sessionID).getOriginsWithRegistrations([callbackAggregator = callbackAggregator.copyRef()](const HashSet<SecurityOriginData>& securityOrigins) mutable {
1287 for (auto& origin : securityOrigins)
1288 callbackAggregator->m_websiteData.entries.append({ origin, WebsiteDataType::ServiceWorkerRegistrations, 0 });
1289 });
1290 }
1291#endif
1292
1293 if (websiteDataTypes.contains(WebsiteDataType::DiskCache)) {
1294 fetchDiskCacheEntries(cache(), sessionID, fetchOptions, [callbackAggregator = WTFMove(callbackAggregator)](auto entries) mutable {
1295 callbackAggregator->m_websiteData.entries.appendVector(entries);
1296 });
1297 }
1298}
1299
1300void NetworkProcess::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, WallTime modifiedSince, uint64_t callbackID)
1301{
1302#if PLATFORM(COCOA)
1303 if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) {
1304 if (auto* networkStorageSession = storageSession(sessionID))
1305 clearHSTSCache(*networkStorageSession, modifiedSince);
1306 }
1307#endif
1308
1309 if (websiteDataTypes.contains(WebsiteDataType::Cookies)) {
1310 if (auto* networkStorageSession = storageSession(sessionID))
1311 networkStorageSession->deleteAllCookiesModifiedSince(modifiedSince);
1312 }
1313
1314 if (websiteDataTypes.contains(WebsiteDataType::Credentials)) {
1315 if (auto* session = storageSession(sessionID))
1316 session->credentialStorage().clearCredentials();
1317 }
1318
1319 auto clearTasksHandler = WTF::CallbackAggregator::create([this, callbackID] {
1320 parentProcessConnection()->send(Messages::NetworkProcessProxy::DidDeleteWebsiteData(callbackID), 0);
1321 });
1322
1323 if (websiteDataTypes.contains(WebsiteDataType::DOMCache))
1324 CacheStorage::Engine::clearAllCaches(*this, sessionID, [clearTasksHandler = clearTasksHandler.copyRef()] { });
1325
1326#if ENABLE(INDEXED_DATABASE)
1327 if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases) && !sessionID.isEphemeral())
1328 idbServer(sessionID).closeAndDeleteDatabasesModifiedSince(modifiedSince, [clearTasksHandler = clearTasksHandler.copyRef()] { });
1329#endif
1330
1331#if ENABLE(SERVICE_WORKER)
1332 if (websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations) && !sessionID.isEphemeral())
1333 swServerForSession(sessionID).clearAll([clearTasksHandler = clearTasksHandler.copyRef()] { });
1334#endif
1335
1336#if ENABLE(RESOURCE_LOAD_STATISTICS)
1337 if (websiteDataTypes.contains(WebsiteDataType::ResourceLoadStatistics)) {
1338 if (auto* networkSession = this->networkSession(sessionID)) {
1339 if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) {
1340 auto deletedTypesRaw = websiteDataTypes.toRaw();
1341 auto monitoredTypesRaw = WebResourceLoadStatisticsStore::monitoredDataTypes().toRaw();
1342
1343 // If we are deleting all of the data types that the resource load statistics store monitors
1344 // we do not need to re-grandfather old data.
1345 auto shouldGrandfather = ((monitoredTypesRaw & deletedTypesRaw) == monitoredTypesRaw) ? ShouldGrandfatherStatistics::No : ShouldGrandfatherStatistics::Yes;
1346
1347 resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince, shouldGrandfather, [clearTasksHandler = clearTasksHandler.copyRef()] { });
1348 }
1349 }
1350 }
1351#endif
1352
1353 if (websiteDataTypes.contains(WebsiteDataType::DiskCache) && !sessionID.isEphemeral())
1354 clearDiskCache(modifiedSince, [clearTasksHandler = WTFMove(clearTasksHandler)] { });
1355
1356 if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases) || websiteDataTypes.contains(WebsiteDataType::DOMCache))
1357 clearStorageQuota(sessionID);
1358
1359 if (websiteDataTypes.contains(WebsiteDataType::AdClickAttributions)) {
1360 if (auto* networkSession = this->networkSession(sessionID))
1361 networkSession->clearAdClickAttribution();
1362 }
1363}
1364
1365static void clearDiskCacheEntries(NetworkCache::Cache* cache, const Vector<SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
1366{
1367 if (!cache) {
1368 RunLoop::main().dispatch(WTFMove(completionHandler));
1369 return;
1370 }
1371
1372 HashSet<RefPtr<SecurityOrigin>> originsToDelete;
1373 for (auto& origin : origins)
1374 originsToDelete.add(origin.securityOrigin());
1375
1376 Vector<NetworkCache::Key> cacheKeysToDelete;
1377 cache->traverse([cache, completionHandler = WTFMove(completionHandler), originsToDelete = WTFMove(originsToDelete), cacheKeysToDelete = WTFMove(cacheKeysToDelete)](auto* traversalEntry) mutable {
1378 if (traversalEntry) {
1379 if (originsToDelete.contains(SecurityOrigin::create(traversalEntry->entry.response().url())))
1380 cacheKeysToDelete.append(traversalEntry->entry.key());
1381 return;
1382 }
1383
1384 cache->remove(cacheKeysToDelete, WTFMove(completionHandler));
1385 return;
1386 });
1387}
1388
1389void NetworkProcess::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, const Vector<SecurityOriginData>& originDatas, const Vector<String>& cookieHostNames, const Vector<String>& HSTSCacheHostNames, uint64_t callbackID)
1390{
1391 if (websiteDataTypes.contains(WebsiteDataType::Cookies)) {
1392 if (auto* networkStorageSession = storageSession(sessionID))
1393 networkStorageSession->deleteCookiesForHostnames(cookieHostNames);
1394 }
1395
1396#if PLATFORM(COCOA)
1397 if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) {
1398 if (auto* networkStorageSession = storageSession(sessionID))
1399 deleteHSTSCacheForHostNames(*networkStorageSession, HSTSCacheHostNames);
1400 }
1401#endif
1402
1403 if (websiteDataTypes.contains(WebsiteDataType::AdClickAttributions)) {
1404 if (auto* networkSession = this->networkSession(sessionID)) {
1405 for (auto& originData : originDatas)
1406 networkSession->clearAdClickAttributionForRegistrableDomain(RegistrableDomain::uncheckedCreateFromHost(originData.host));
1407 }
1408 }
1409
1410 auto clearTasksHandler = WTF::CallbackAggregator::create([this, callbackID] {
1411 parentProcessConnection()->send(Messages::NetworkProcessProxy::DidDeleteWebsiteDataForOrigins(callbackID), 0);
1412 });
1413
1414 if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) {
1415 for (auto& originData : originDatas)
1416 CacheStorage::Engine::clearCachesForOrigin(*this, sessionID, SecurityOriginData { originData }, [clearTasksHandler = clearTasksHandler.copyRef()] { });
1417 }
1418
1419#if ENABLE(INDEXED_DATABASE)
1420 if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases) && !sessionID.isEphemeral())
1421 idbServer(sessionID).closeAndDeleteDatabasesForOrigins(originDatas, [clearTasksHandler = clearTasksHandler.copyRef()] { });
1422#endif
1423
1424#if ENABLE(SERVICE_WORKER)
1425 if (websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations) && !sessionID.isEphemeral()) {
1426 auto& server = swServerForSession(sessionID);
1427 for (auto& originData : originDatas)
1428 server.clear(originData, [clearTasksHandler = clearTasksHandler.copyRef()] { });
1429 }
1430#endif
1431
1432 if (websiteDataTypes.contains(WebsiteDataType::DiskCache) && !sessionID.isEphemeral())
1433 clearDiskCacheEntries(cache(), originDatas, [clearTasksHandler = WTFMove(clearTasksHandler)] { });
1434
1435 if (websiteDataTypes.contains(WebsiteDataType::Credentials)) {
1436 if (auto* session = storageSession(sessionID)) {
1437 for (auto& originData : originDatas)
1438 session->credentialStorage().removeCredentialsWithOrigin(originData);
1439 }
1440 }
1441
1442 // FIXME: Implement storage quota clearing for these origins.
1443}
1444
1445void NetworkProcess::clearStorageQuota(PAL::SessionID sessionID)
1446{
1447 auto iterator = m_storageQuotaManagers.find(sessionID);
1448 if (iterator == m_storageQuotaManagers.end())
1449 return;
1450
1451 auto& managers = iterator->value;
1452 for (auto& manager : managers.managersPerOrigin())
1453 manager.value->resetQuota(managers.defaultQuota(manager.key));
1454}
1455
1456#if ENABLE(RESOURCE_LOAD_STATISTICS)
1457static Vector<String> filterForRegistrableDomains(const Vector<RegistrableDomain>& registrableDomains, const HashSet<String>& foundValues)
1458{
1459 Vector<String> result;
1460 for (const auto& value : foundValues) {
1461 if (registrableDomains.contains(RegistrableDomain::uncheckedCreateFromHost(value)))
1462 result.append(value);
1463 }
1464
1465 return result;
1466}
1467
1468static Vector<WebsiteData::Entry> filterForRegistrableDomains(const Vector<RegistrableDomain>& registrableDomains, const Vector<WebsiteData::Entry>& foundValues)
1469{
1470 Vector<WebsiteData::Entry> result;
1471 for (const auto& value : foundValues) {
1472 if (registrableDomains.contains(RegistrableDomain::uncheckedCreateFromHost(value.origin.host)))
1473 result.append(value);
1474 }
1475
1476 return result;
1477}
1478
1479void NetworkProcess::deleteWebsiteDataForRegistrableDomains(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, HashMap<RegistrableDomain, WebsiteDataToRemove>&& domains, bool shouldNotifyPage, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
1480{
1481 OptionSet<WebsiteDataFetchOption> fetchOptions = WebsiteDataFetchOption::DoNotCreateProcesses;
1482
1483 struct CallbackAggregator final : public ThreadSafeRefCounted<CallbackAggregator> {
1484 explicit CallbackAggregator(CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
1485 : m_completionHandler(WTFMove(completionHandler))
1486 {
1487 }
1488
1489 ~CallbackAggregator()
1490 {
1491 RunLoop::main().dispatch([completionHandler = WTFMove(m_completionHandler), domains = WTFMove(m_domains)] () mutable {
1492 completionHandler(domains);
1493 });
1494 }
1495
1496 CompletionHandler<void(const HashSet<RegistrableDomain>&)> m_completionHandler;
1497 HashSet<RegistrableDomain> m_domains;
1498 };
1499
1500 auto callbackAggregator = adoptRef(*new CallbackAggregator([this, completionHandler = WTFMove(completionHandler), shouldNotifyPage] (const HashSet<RegistrableDomain>& domainsWithData) mutable {
1501 if (shouldNotifyPage)
1502 parentProcessConnection()->send(Messages::NetworkProcessProxy::NotifyWebsiteDataDeletionForRegistrableDomainsFinished(), 0);
1503
1504 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), domainsWithData = crossThreadCopy(domainsWithData)] () mutable {
1505 completionHandler(domainsWithData);
1506 });
1507 }));
1508
1509 HashSet<String> hostNamesWithCookies;
1510 HashSet<String> hostNamesWithHSTSCache;
1511
1512 Vector<RegistrableDomain> domainsToDeleteCookiesFor;
1513 Vector<RegistrableDomain> domainsToDeleteAllButHttpOnlyCookiesFor;
1514 Vector<RegistrableDomain> domainsToDeleteAllButCookiesFor;
1515 Vector<String> hostnamesWithCookiesToDelete;
1516 if (websiteDataTypes.contains(WebsiteDataType::Cookies)) {
1517 for (auto& domain : domains.keys()) {
1518 domainsToDeleteAllButCookiesFor.append(domain);
1519 switch (domains.get(domain)) {
1520 case WebsiteDataToRemove::All:
1521 domainsToDeleteCookiesFor.append(domain);
1522 break;
1523 case WebsiteDataToRemove::AllButHttpOnlyCookies:
1524 domainsToDeleteAllButHttpOnlyCookiesFor.append(domain);
1525 break;
1526 case WebsiteDataToRemove::AllButCookies:
1527 // Already added.
1528 break;
1529 }
1530 }
1531 if (auto* networkStorageSession = storageSession(sessionID)) {
1532 networkStorageSession->getHostnamesWithCookies(hostNamesWithCookies);
1533
1534 hostnamesWithCookiesToDelete = filterForRegistrableDomains(domainsToDeleteCookiesFor, hostNamesWithCookies);
1535 networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, WebCore::IncludeHttpOnlyCookies::Yes);
1536
1537 for (const auto& host : hostnamesWithCookiesToDelete)
1538 callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(host));
1539
1540 hostnamesWithCookiesToDelete = filterForRegistrableDomains(domainsToDeleteAllButHttpOnlyCookiesFor, hostNamesWithCookies);
1541 networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, WebCore::IncludeHttpOnlyCookies::No);
1542
1543 for (const auto& host : hostnamesWithCookiesToDelete)
1544 callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(host));
1545 }
1546 } else {
1547 for (auto& domain : domains.keys())
1548 domainsToDeleteAllButCookiesFor.append(domain);
1549 }
1550
1551 Vector<String> hostnamesWithHSTSToDelete;
1552#if PLATFORM(COCOA)
1553 if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) {
1554 if (auto* networkStorageSession = storageSession(sessionID)) {
1555 getHostNamesWithHSTSCache(*networkStorageSession, hostNamesWithHSTSCache);
1556 hostnamesWithHSTSToDelete = filterForRegistrableDomains(domainsToDeleteAllButCookiesFor, hostNamesWithHSTSCache);
1557
1558 for (const auto& host : hostnamesWithHSTSToDelete)
1559 callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(host));
1560
1561 deleteHSTSCacheForHostNames(*networkStorageSession, hostnamesWithHSTSToDelete);
1562 }
1563 }
1564#endif
1565
1566 /*
1567 // FIXME: No API to delete credentials by origin
1568 HashSet<String> originsWithCredentials;
1569 if (websiteDataTypes.contains(WebsiteDataType::Credentials)) {
1570 if (storageSession(sessionID))
1571 originsWithCredentials = storageSession(sessionID)->credentialStorage().originsWithCredentials();
1572 }
1573 */
1574
1575 if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) {
1576 CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [this, domainsToDeleteAllButCookiesFor, sessionID, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
1577
1578 auto entriesToDelete = filterForRegistrableDomains(domainsToDeleteAllButCookiesFor, entries);
1579
1580 for (const auto& entry : entriesToDelete)
1581 callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host));
1582
1583 for (auto& entry : entriesToDelete)
1584 CacheStorage::Engine::clearCachesForOrigin(*this, sessionID, SecurityOriginData { entry.origin }, [callbackAggregator = callbackAggregator.copyRef()] { });
1585 });
1586 }
1587
1588#if ENABLE(INDEXED_DATABASE)
1589 auto path = m_idbDatabasePaths.get(sessionID);
1590 if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
1591 // FIXME: Pick the right database store based on the session ID.
1592 postStorageTask(CrossThreadTask([this, sessionID, callbackAggregator = callbackAggregator.copyRef(), path = WTFMove(path), domainsToDeleteAllButCookiesFor]() mutable {
1593 RunLoop::main().dispatch([this, sessionID, domainsToDeleteAllButCookiesFor = crossThreadCopy(domainsToDeleteAllButCookiesFor), callbackAggregator = callbackAggregator.copyRef(), securityOrigins = indexedDatabaseOrigins(path)] {
1594 Vector<SecurityOriginData> entriesToDelete;
1595 for (const auto& securityOrigin : securityOrigins) {
1596 auto domain = RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host);
1597 if (!domainsToDeleteAllButCookiesFor.contains(domain))
1598 continue;
1599
1600 entriesToDelete.append(securityOrigin);
1601 callbackAggregator->m_domains.add(domain);
1602 }
1603
1604 idbServer(sessionID).closeAndDeleteDatabasesForOrigins(entriesToDelete, [callbackAggregator = callbackAggregator.copyRef()] { });
1605 });
1606 }));
1607 }
1608#endif
1609
1610#if ENABLE(SERVICE_WORKER)
1611 path = m_swDatabasePaths.get(sessionID);
1612 if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) {
1613 swServerForSession(sessionID).getOriginsWithRegistrations([this, sessionID, domainsToDeleteAllButCookiesFor, callbackAggregator = callbackAggregator.copyRef()](const HashSet<SecurityOriginData>& securityOrigins) mutable {
1614 for (auto& securityOrigin : securityOrigins) {
1615 if (!domainsToDeleteAllButCookiesFor.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
1616 continue;
1617 callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host));
1618 swServerForSession(sessionID).clear(securityOrigin, [callbackAggregator = callbackAggregator.copyRef()] { });
1619 }
1620 });
1621 }
1622#endif
1623
1624 if (websiteDataTypes.contains(WebsiteDataType::DiskCache)) {
1625 fetchDiskCacheEntries(cache(), sessionID, fetchOptions, [this, domainsToDeleteAllButCookiesFor, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
1626
1627 Vector<SecurityOriginData> entriesToDelete;
1628 for (auto& entry : entries) {
1629 if (!domainsToDeleteAllButCookiesFor.contains(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host)))
1630 continue;
1631 entriesToDelete.append(entry.origin);
1632 callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host));
1633 }
1634 clearDiskCacheEntries(cache(), entriesToDelete, [callbackAggregator = callbackAggregator.copyRef()] { });
1635 });
1636 }
1637
1638 auto dataTypesForUIProcess = WebsiteData::filter(websiteDataTypes, WebsiteDataProcessType::UI);
1639 if (!dataTypesForUIProcess.isEmpty() && !domainsToDeleteAllButCookiesFor.isEmpty()) {
1640 CompletionHandler<void(const HashSet<RegistrableDomain>&)> completionHandler = [callbackAggregator = callbackAggregator.copyRef()] (const HashSet<RegistrableDomain>& domains) {
1641 for (auto& domain : domains)
1642 callbackAggregator->m_domains.add(domain);
1643 };
1644 parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::DeleteWebsiteDataInUIProcessForRegistrableDomains(sessionID, dataTypesForUIProcess, fetchOptions, domainsToDeleteAllButCookiesFor), WTFMove(completionHandler));
1645 }
1646}
1647
1648void NetworkProcess::deleteCookiesForTesting(PAL::SessionID sessionID, RegistrableDomain domain, bool includeHttpOnlyCookies, CompletionHandler<void()>&& completionHandler)
1649{
1650 OptionSet<WebsiteDataType> cookieType = WebsiteDataType::Cookies;
1651 HashMap<RegistrableDomain, WebsiteDataToRemove> toDeleteFor;
1652 toDeleteFor.add(domain, includeHttpOnlyCookies ? WebsiteDataToRemove::All : WebsiteDataToRemove::AllButHttpOnlyCookies);
1653 deleteWebsiteDataForRegistrableDomains(sessionID, cookieType, WTFMove(toDeleteFor), true, [completionHandler = WTFMove(completionHandler)] (const HashSet<RegistrableDomain>& domainsDeletedFor) mutable {
1654 UNUSED_PARAM(domainsDeletedFor);
1655 completionHandler();
1656 });
1657}
1658
1659void NetworkProcess::registrableDomainsWithWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, bool shouldNotifyPage, CompletionHandler<void(HashSet<RegistrableDomain>&&)>&& completionHandler)
1660{
1661 OptionSet<WebsiteDataFetchOption> fetchOptions = WebsiteDataFetchOption::DoNotCreateProcesses;
1662
1663 struct CallbackAggregator final : public ThreadSafeRefCounted<CallbackAggregator> {
1664 explicit CallbackAggregator(CompletionHandler<void(HashSet<RegistrableDomain>&&)>&& completionHandler)
1665 : m_completionHandler(WTFMove(completionHandler))
1666 {
1667 }
1668
1669 ~CallbackAggregator()
1670 {
1671 RunLoop::main().dispatch([completionHandler = WTFMove(m_completionHandler), websiteData = WTFMove(m_websiteData)] () mutable {
1672 HashSet<RegistrableDomain> domains;
1673 for (const auto& hostnameWithCookies : websiteData.hostNamesWithCookies)
1674 domains.add(RegistrableDomain::uncheckedCreateFromHost(hostnameWithCookies));
1675
1676 for (const auto& hostnameWithHSTS : websiteData.hostNamesWithHSTSCache)
1677 domains.add(RegistrableDomain::uncheckedCreateFromHost(hostnameWithHSTS));
1678
1679 for (const auto& entry : websiteData.entries)
1680 domains.add(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host));
1681
1682 completionHandler(WTFMove(domains));
1683 });
1684 }
1685
1686 CompletionHandler<void(HashSet<RegistrableDomain>&&)> m_completionHandler;
1687 WebsiteData m_websiteData;
1688 };
1689
1690 auto callbackAggregator = adoptRef(*new CallbackAggregator([this, completionHandler = WTFMove(completionHandler), shouldNotifyPage] (HashSet<RegistrableDomain>&& domainsWithData) mutable {
1691 if (shouldNotifyPage)
1692 parentProcessConnection()->send(Messages::NetworkProcessProxy::NotifyWebsiteDataScanForRegistrableDomainsFinished(), 0);
1693
1694 RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), domainsWithData = crossThreadCopy(domainsWithData)] () mutable {
1695 completionHandler(WTFMove(domainsWithData));
1696 });
1697 }));
1698
1699 auto& websiteDataStore = callbackAggregator->m_websiteData;
1700
1701 Vector<String> hostnamesWithCookiesToDelete;
1702 if (websiteDataTypes.contains(WebsiteDataType::Cookies)) {
1703 if (auto* networkStorageSession = storageSession(sessionID))
1704 networkStorageSession->getHostnamesWithCookies(websiteDataStore.hostNamesWithCookies);
1705 }
1706
1707 Vector<String> hostnamesWithHSTSToDelete;
1708#if PLATFORM(COCOA)
1709 if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) {
1710 if (auto* networkStorageSession = storageSession(sessionID))
1711 getHostNamesWithHSTSCache(*networkStorageSession, websiteDataStore.hostNamesWithHSTSCache);
1712 }
1713#endif
1714
1715 if (websiteDataTypes.contains(WebsiteDataType::Credentials)) {
1716 if (auto* networkStorageSession = storageSession(sessionID)) {
1717 auto securityOrigins = networkStorageSession->credentialStorage().originsWithCredentials();
1718 for (auto& securityOrigin : securityOrigins)
1719 callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::Credentials, 0 });
1720 }
1721 }
1722
1723 if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) {
1724 CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
1725 callbackAggregator->m_websiteData.entries.appendVector(entries);
1726 });
1727 }
1728
1729#if ENABLE(INDEXED_DATABASE)
1730 auto path = m_idbDatabasePaths.get(sessionID);
1731 if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
1732 // FIXME: Pick the right database store based on the session ID.
1733 postStorageTask(CrossThreadTask([this, callbackAggregator = callbackAggregator.copyRef(), path = WTFMove(path)]() mutable {
1734 RunLoop::main().dispatch([callbackAggregator = callbackAggregator.copyRef(), securityOrigins = indexedDatabaseOrigins(path)] {
1735 for (const auto& securityOrigin : securityOrigins)
1736 callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::IndexedDBDatabases, 0 });
1737 });
1738 }));
1739 }
1740#endif
1741
1742#if ENABLE(SERVICE_WORKER)
1743 path = m_swDatabasePaths.get(sessionID);
1744 if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) {
1745 swServerForSession(sessionID).getOriginsWithRegistrations([callbackAggregator = callbackAggregator.copyRef()](const HashSet<SecurityOriginData>& securityOrigins) mutable {
1746 for (auto& securityOrigin : securityOrigins)
1747 callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::ServiceWorkerRegistrations, 0 });
1748 });
1749 }
1750#endif
1751
1752 if (websiteDataTypes.contains(WebsiteDataType::DiskCache)) {
1753 fetchDiskCacheEntries(cache(), sessionID, fetchOptions, [callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
1754 callbackAggregator->m_websiteData.entries.appendVector(entries);
1755 });
1756 }
1757}
1758#endif // ENABLE(RESOURCE_LOAD_STATISTICS)
1759
1760CacheStorage::Engine* NetworkProcess::findCacheEngine(const PAL::SessionID& sessionID)
1761{
1762 return m_cacheEngines.get(sessionID);
1763}
1764
1765CacheStorage::Engine& NetworkProcess::ensureCacheEngine(const PAL::SessionID& sessionID, Function<Ref<CacheStorage::Engine>()>&& functor)
1766{
1767 return m_cacheEngines.ensure(sessionID, WTFMove(functor)).iterator->value;
1768}
1769
1770void NetworkProcess::removeCacheEngine(const PAL::SessionID& sessionID)
1771{
1772 m_cacheEngines.remove(sessionID);
1773}
1774
1775void NetworkProcess::downloadRequest(PAL::SessionID sessionID, DownloadID downloadID, const ResourceRequest& request, const String& suggestedFilename)
1776{
1777 downloadManager().startDownload(sessionID, downloadID, request, suggestedFilename);
1778}
1779
1780void NetworkProcess::resumeDownload(PAL::SessionID sessionID, DownloadID downloadID, const IPC::DataReference& resumeData, const String& path, WebKit::SandboxExtension::Handle&& sandboxExtensionHandle)
1781{
1782 downloadManager().resumeDownload(sessionID, downloadID, resumeData, path, WTFMove(sandboxExtensionHandle));
1783}
1784
1785void NetworkProcess::cancelDownload(DownloadID downloadID)
1786{
1787 downloadManager().cancelDownload(downloadID);
1788}
1789
1790#if PLATFORM(COCOA)
1791void NetworkProcess::publishDownloadProgress(DownloadID downloadID, const URL& url, SandboxExtension::Handle&& sandboxExtensionHandle)
1792{
1793 downloadManager().publishDownloadProgress(downloadID, url, WTFMove(sandboxExtensionHandle));
1794}
1795#endif
1796
1797void NetworkProcess::continueWillSendRequest(DownloadID downloadID, WebCore::ResourceRequest&& request)
1798{
1799 downloadManager().continueWillSendRequest(downloadID, WTFMove(request));
1800}
1801
1802void NetworkProcess::pendingDownloadCanceled(DownloadID downloadID)
1803{
1804 downloadProxyConnection()->send(Messages::DownloadProxy::DidCancel({ }), downloadID.downloadID());
1805}
1806
1807void NetworkProcess::findPendingDownloadLocation(NetworkDataTask& networkDataTask, ResponseCompletionHandler&& completionHandler, const ResourceResponse& response)
1808{
1809 uint64_t destinationID = networkDataTask.pendingDownloadID().downloadID();
1810 downloadProxyConnection()->send(Messages::DownloadProxy::DidReceiveResponse(response), destinationID);
1811
1812 downloadManager().willDecidePendingDownloadDestination(networkDataTask, WTFMove(completionHandler));
1813
1814 // As per https://html.spec.whatwg.org/#as-a-download (step 2), the filename from the Content-Disposition header
1815 // should override the suggested filename from the download attribute.
1816 String suggestedFilename = response.isAttachmentWithFilename() ? response.suggestedFilename() : networkDataTask.suggestedFilename();
1817 suggestedFilename = MIMETypeRegistry::appendFileExtensionIfNecessary(suggestedFilename, response.mimeType());
1818
1819 downloadProxyConnection()->send(Messages::DownloadProxy::DecideDestinationWithSuggestedFilenameAsync(networkDataTask.pendingDownloadID(), suggestedFilename), destinationID);
1820}
1821
1822void NetworkProcess::continueDecidePendingDownloadDestination(DownloadID downloadID, String destination, SandboxExtension::Handle&& sandboxExtensionHandle, bool allowOverwrite)
1823{
1824 if (destination.isEmpty())
1825 downloadManager().cancelDownload(downloadID);
1826 else
1827 downloadManager().continueDecidePendingDownloadDestination(downloadID, destination, WTFMove(sandboxExtensionHandle), allowOverwrite);
1828}
1829
1830void NetworkProcess::setCacheModel(CacheModel cacheModel)
1831{
1832 if (m_hasSetCacheModel && (cacheModel == m_cacheModel))
1833 return;
1834
1835 m_hasSetCacheModel = true;
1836 m_cacheModel = cacheModel;
1837
1838 unsigned urlCacheMemoryCapacity = 0;
1839 uint64_t urlCacheDiskCapacity = 0;
1840 uint64_t diskFreeSize = 0;
1841 if (FileSystem::getVolumeFreeSpace(m_diskCacheDirectory, diskFreeSize)) {
1842 // As a fudge factor, use 1000 instead of 1024, in case the reported byte
1843 // count doesn't align exactly to a megabyte boundary.
1844 diskFreeSize /= KB * 1000;
1845 calculateURLCacheSizes(cacheModel, diskFreeSize, urlCacheMemoryCapacity, urlCacheDiskCapacity);
1846 }
1847
1848 if (m_cache)
1849 m_cache->setCapacity(urlCacheDiskCapacity);
1850}
1851
1852void NetworkProcess::setCanHandleHTTPSServerTrustEvaluation(bool value)
1853{
1854 m_canHandleHTTPSServerTrustEvaluation = value;
1855}
1856
1857void NetworkProcess::getNetworkProcessStatistics(uint64_t callbackID)
1858{
1859 StatisticsData data;
1860
1861 data.statisticsNumbers.set("DownloadsActiveCount", downloadManager().activeDownloadCount());
1862 data.statisticsNumbers.set("OutstandingAuthenticationChallengesCount", authenticationManager().outstandingAuthenticationChallengeCount());
1863
1864 parentProcessConnection()->send(Messages::WebProcessPool::DidGetStatistics(data, callbackID), 0);
1865}
1866
1867void NetworkProcess::setAllowsAnySSLCertificateForWebSocket(bool allows, CompletionHandler<void()>&& completionHandler)
1868{
1869 DeprecatedGlobalSettings::setAllowsAnySSLCertificate(allows);
1870 completionHandler();
1871}
1872
1873void NetworkProcess::logDiagnosticMessage(uint64_t webPageID, const String& message, const String& description, ShouldSample shouldSample)
1874{
1875 if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample))
1876 return;
1877
1878 parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessage(webPageID, message, description, ShouldSample::No), 0);
1879}
1880
1881void NetworkProcess::logDiagnosticMessageWithResult(uint64_t webPageID, const String& message, const String& description, DiagnosticLoggingResultType result, ShouldSample shouldSample)
1882{
1883 if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample))
1884 return;
1885
1886 parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessageWithResult(webPageID, message, description, result, ShouldSample::No), 0);
1887}
1888
1889void NetworkProcess::logDiagnosticMessageWithValue(uint64_t webPageID, const String& message, const String& description, double value, unsigned significantFigures, ShouldSample shouldSample)
1890{
1891 if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample))
1892 return;
1893
1894 parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessageWithValue(webPageID, message, description, value, significantFigures, ShouldSample::No), 0);
1895}
1896
1897void NetworkProcess::terminate()
1898{
1899 platformTerminate();
1900 AuxiliaryProcess::terminate();
1901}
1902
1903void NetworkProcess::processDidTransitionToForeground()
1904{
1905 platformProcessDidTransitionToForeground();
1906}
1907
1908void NetworkProcess::processDidTransitionToBackground()
1909{
1910 platformProcessDidTransitionToBackground();
1911}
1912
1913// FIXME: We can remove this one by adapting RefCounter.
1914class TaskCounter : public RefCounted<TaskCounter> {
1915public:
1916 explicit TaskCounter(Function<void()>&& callback) : m_callback(WTFMove(callback)) { }
1917 ~TaskCounter() { m_callback(); };
1918
1919private:
1920 Function<void()> m_callback;
1921};
1922
1923void NetworkProcess::actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend shouldAcknowledgeWhenReadyToSuspend)
1924{
1925#if PLATFORM(IOS_FAMILY)
1926 m_webSQLiteDatabaseTracker.setIsSuspended(true);
1927#endif
1928
1929 lowMemoryHandler(Critical::Yes);
1930
1931 RefPtr<TaskCounter> delayedTaskCounter;
1932 if (shouldAcknowledgeWhenReadyToSuspend == ShouldAcknowledgeWhenReadyToSuspend::Yes) {
1933 delayedTaskCounter = adoptRef(new TaskCounter([this] {
1934 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::notifyProcessReadyToSuspend() Sending ProcessReadyToSuspend IPC message", this);
1935 if (parentProcessConnection())
1936 parentProcessConnection()->send(Messages::NetworkProcessProxy::ProcessReadyToSuspend(), 0);
1937 }));
1938 }
1939
1940 platformPrepareToSuspend([delayedTaskCounter] { });
1941 platformSyncAllCookies([delayedTaskCounter] { });
1942
1943 for (auto& connection : m_webProcessConnections)
1944 connection->cleanupForSuspension([delayedTaskCounter] { });
1945
1946#if ENABLE(SERVICE_WORKER)
1947 for (auto& server : m_swServers.values())
1948 server->startSuspension([delayedTaskCounter] { });
1949#endif
1950}
1951
1952void NetworkProcess::processWillSuspendImminently()
1953{
1954 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processWillSuspendImminently() BEGIN", this);
1955#if PLATFORM(IOS_FAMILY) && ENABLE(INDEXED_DATABASE)
1956 for (auto& server : m_idbServers.values())
1957 server->tryStop(IDBServer::ShouldForceStop::Yes);
1958#endif
1959 actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::No);
1960 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processWillSuspendImminently() END", this);
1961}
1962
1963void NetworkProcess::prepareToSuspend()
1964{
1965 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::prepareToSuspend()", this);
1966
1967#if PLATFORM(IOS_FAMILY) && ENABLE(INDEXED_DATABASE)
1968 for (auto& server : m_idbServers.values())
1969 server->tryStop(IDBServer::ShouldForceStop::No);
1970#endif
1971 actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::Yes);
1972}
1973
1974void NetworkProcess::cancelPrepareToSuspend()
1975{
1976 // Although it is tempting to send a NetworkProcessProxy::DidCancelProcessSuspension message from here
1977 // we do not because prepareToSuspend() already replied with a NetworkProcessProxy::ProcessReadyToSuspend
1978 // message. And NetworkProcessProxy expects to receive either a NetworkProcessProxy::ProcessReadyToSuspend-
1979 // or NetworkProcessProxy::DidCancelProcessSuspension- message, but not both.
1980 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::cancelPrepareToSuspend()", this);
1981 resume();
1982}
1983
1984void NetworkProcess::applicationDidEnterBackground()
1985{
1986 m_downloadManager.applicationDidEnterBackground();
1987}
1988
1989void NetworkProcess::applicationWillEnterForeground()
1990{
1991 m_downloadManager.applicationWillEnterForeground();
1992}
1993
1994void NetworkProcess::processDidResume()
1995{
1996 RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processDidResume()", this);
1997 resume();
1998}
1999
2000void NetworkProcess::resume()
2001{
2002#if PLATFORM(IOS_FAMILY)
2003 m_webSQLiteDatabaseTracker.setIsSuspended(false);
2004#endif
2005
2006 platformProcessDidResume();
2007 for (auto& connection : m_webProcessConnections)
2008 connection->endSuspension();
2009
2010#if ENABLE(SERVICE_WORKER)
2011 for (auto& server : m_swServers.values())
2012 server->endSuspension();
2013#endif
2014#if PLATFORM(IOS_FAMILY) && ENABLE(INDEXED_DATABASE)
2015 for (auto& server : m_idbServers.values())
2016 server->resume();
2017#endif
2018}
2019
2020void NetworkProcess::prefetchDNS(const String& hostname)
2021{
2022 WebCore::prefetchDNS(hostname);
2023}
2024
2025void NetworkProcess::cacheStorageRootPath(PAL::SessionID sessionID, CacheStorageRootPathCallback&& callback)
2026{
2027 m_cacheStorageParametersCallbacks.ensure(sessionID, [&] {
2028 parentProcessConnection()->send(Messages::NetworkProcessProxy::RetrieveCacheStorageParameters { sessionID }, 0);
2029 return Vector<CacheStorageRootPathCallback> { };
2030 }).iterator->value.append(WTFMove(callback));
2031}
2032
2033void NetworkProcess::setCacheStorageParameters(PAL::SessionID sessionID, String&& cacheStorageDirectory, SandboxExtension::Handle&& handle)
2034{
2035 auto iterator = m_cacheStorageParametersCallbacks.find(sessionID);
2036 if (iterator == m_cacheStorageParametersCallbacks.end())
2037 return;
2038
2039 SandboxExtension::consumePermanently(handle);
2040 auto callbacks = WTFMove(iterator->value);
2041 m_cacheStorageParametersCallbacks.remove(iterator);
2042 for (auto& callback : callbacks)
2043 callback(String { cacheStorageDirectory });
2044}
2045
2046void NetworkProcess::preconnectTo(const URL& url, WebCore::StoredCredentialsPolicy storedCredentialsPolicy)
2047{
2048#if ENABLE(SERVER_PRECONNECT)
2049 NetworkLoadParameters parameters;
2050 parameters.request = ResourceRequest { url };
2051 parameters.sessionID = PAL::SessionID::defaultSessionID();
2052 parameters.storedCredentialsPolicy = storedCredentialsPolicy;
2053 parameters.shouldPreconnectOnly = PreconnectOnly::Yes;
2054
2055 new PreconnectTask(*this, WTFMove(parameters));
2056#else
2057 UNUSED_PARAM(url);
2058 UNUSED_PARAM(storedCredentialsPolicy);
2059#endif
2060}
2061
2062void NetworkProcess::registerURLSchemeAsSecure(const String& scheme) const
2063{
2064 SchemeRegistry::registerURLSchemeAsSecure(scheme);
2065}
2066
2067void NetworkProcess::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme) const
2068{
2069 SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(scheme);
2070}
2071
2072void NetworkProcess::registerURLSchemeAsLocal(const String& scheme) const
2073{
2074 SchemeRegistry::registerURLSchemeAsLocal(scheme);
2075}
2076
2077void NetworkProcess::registerURLSchemeAsNoAccess(const String& scheme) const
2078{
2079 SchemeRegistry::registerURLSchemeAsNoAccess(scheme);
2080}
2081
2082void NetworkProcess::registerURLSchemeAsDisplayIsolated(const String& scheme) const
2083{
2084 SchemeRegistry::registerURLSchemeAsDisplayIsolated(scheme);
2085}
2086
2087void NetworkProcess::registerURLSchemeAsCORSEnabled(const String& scheme) const
2088{
2089 SchemeRegistry::registerURLSchemeAsCORSEnabled(scheme);
2090}
2091
2092void NetworkProcess::registerURLSchemeAsCanDisplayOnlyIfCanRequest(const String& scheme) const
2093{
2094 SchemeRegistry::registerAsCanDisplayOnlyIfCanRequest(scheme);
2095}
2096
2097void NetworkProcess::didSyncAllCookies()
2098{
2099 parentProcessConnection()->send(Messages::NetworkProcessProxy::DidSyncAllCookies(), 0);
2100}
2101
2102#if ENABLE(INDEXED_DATABASE)
2103Ref<IDBServer::IDBServer> NetworkProcess::createIDBServer(PAL::SessionID sessionID)
2104{
2105 String path;
2106 if (!sessionID.isEphemeral()) {
2107 ASSERT(m_idbDatabasePaths.contains(sessionID));
2108 path = m_idbDatabasePaths.get(sessionID);
2109 }
2110
2111 auto server = IDBServer::IDBServer::create(sessionID, path, *this, [this, weakThis = makeWeakPtr(this)](PAL::SessionID sessionID, const auto& origin) -> StorageQuotaManager* {
2112 if (!weakThis)
2113 return nullptr;
2114 return &this->storageQuotaManager(sessionID, origin);
2115 });
2116 server->setPerOriginQuota(m_idbPerOriginQuota);
2117 return server;
2118}
2119
2120IDBServer::IDBServer& NetworkProcess::idbServer(PAL::SessionID sessionID)
2121{
2122 return *m_idbServers.ensure(sessionID, [this, sessionID] {
2123 return this->createIDBServer(sessionID);
2124 }).iterator->value;
2125}
2126
2127void NetworkProcess::ensurePathExists(const String& path)
2128{
2129 ASSERT(!RunLoop::isMain());
2130
2131 if (!FileSystem::makeAllDirectories(path))
2132 LOG_ERROR("Failed to make all directories for path '%s'", path.utf8().data());
2133}
2134
2135void NetworkProcess::postStorageTask(CrossThreadTask&& task)
2136{
2137 ASSERT(RunLoop::isMain());
2138
2139 LockHolder locker(m_storageTaskMutex);
2140
2141 m_storageTasks.append(WTFMove(task));
2142
2143 m_storageTaskQueue->dispatch([this] {
2144 performNextStorageTask();
2145 });
2146}
2147
2148void NetworkProcess::performNextStorageTask()
2149{
2150 ASSERT(!RunLoop::isMain());
2151
2152 CrossThreadTask task;
2153 {
2154 LockHolder locker(m_storageTaskMutex);
2155 ASSERT(!m_storageTasks.isEmpty());
2156 task = m_storageTasks.takeFirst();
2157 }
2158
2159 task.performTask();
2160}
2161
2162void NetworkProcess::accessToTemporaryFileComplete(const String& path)
2163{
2164 // We've either hard linked the temporary blob file to the database directory, copied it there,
2165 // or the transaction is being aborted.
2166 // In any of those cases, we can delete the temporary blob file now.
2167 FileSystem::deleteFile(path);
2168}
2169
2170void NetworkProcess::collectIndexedDatabaseOriginsForVersion(const String& path, HashSet<WebCore::SecurityOriginData>& securityOrigins)
2171{
2172 if (path.isEmpty())
2173 return;
2174
2175 for (auto& topOriginPath : FileSystem::listDirectory(path, "*")) {
2176 auto databaseIdentifier = FileSystem::pathGetFileName(topOriginPath);
2177 if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(databaseIdentifier)) {
2178 securityOrigins.add(WTFMove(*securityOrigin));
2179
2180 for (auto& originPath : FileSystem::listDirectory(topOriginPath, "*")) {
2181 databaseIdentifier = FileSystem::pathGetFileName(originPath);
2182 if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(databaseIdentifier))
2183 securityOrigins.add(WTFMove(*securityOrigin));
2184 }
2185 }
2186 }
2187}
2188
2189HashSet<WebCore::SecurityOriginData> NetworkProcess::indexedDatabaseOrigins(const String& path)
2190{
2191 if (path.isEmpty())
2192 return { };
2193
2194 HashSet<WebCore::SecurityOriginData> securityOrigins;
2195 collectIndexedDatabaseOriginsForVersion(FileSystem::pathByAppendingComponent(path, "v0"), securityOrigins);
2196 collectIndexedDatabaseOriginsForVersion(FileSystem::pathByAppendingComponent(path, "v1"), securityOrigins);
2197
2198 return securityOrigins;
2199}
2200
2201void NetworkProcess::addIndexedDatabaseSession(PAL::SessionID sessionID, String& indexedDatabaseDirectory, SandboxExtension::Handle& handle)
2202{
2203 // *********
2204 // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>)
2205 // *********
2206 auto addResult = m_idbDatabasePaths.add(sessionID, indexedDatabaseDirectory);
2207 if (addResult.isNewEntry) {
2208 SandboxExtension::consumePermanently(handle);
2209 if (!indexedDatabaseDirectory.isEmpty())
2210 postStorageTask(createCrossThreadTask(*this, &NetworkProcess::ensurePathExists, indexedDatabaseDirectory));
2211 }
2212}
2213
2214void NetworkProcess::setIDBPerOriginQuota(uint64_t quota)
2215{
2216 m_idbPerOriginQuota = quota;
2217
2218 for (auto& server : m_idbServers.values())
2219 server->setPerOriginQuota(quota);
2220}
2221#endif // ENABLE(INDEXED_DATABASE)
2222
2223void NetworkProcess::updateQuotaBasedOnSpaceUsageForTesting(PAL::SessionID sessionID, const ClientOrigin& origin)
2224{
2225 auto& manager = storageQuotaManager(sessionID, origin);
2226 manager.resetQuota(m_storageQuotaManagers.find(sessionID)->value.defaultQuota(origin));
2227 manager.updateQuotaBasedOnSpaceUsage();
2228}
2229
2230#if ENABLE(SANDBOX_EXTENSIONS)
2231void NetworkProcess::getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, CompletionHandler<void(SandboxExtension::HandleArray&&)>&& completionHandler)
2232{
2233 parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::GetSandboxExtensionsForBlobFiles(filenames), WTFMove(completionHandler));
2234}
2235#endif // ENABLE(SANDBOX_EXTENSIONS)
2236
2237#if ENABLE(SERVICE_WORKER)
2238WebSWServerToContextConnection* NetworkProcess::connectionToContextProcessFromIPCConnection(IPC::Connection& connection)
2239{
2240 for (auto& serverToContextConnection : m_serverToContextConnections.values()) {
2241 if (serverToContextConnection->ipcConnection() == &connection)
2242 return serverToContextConnection.get();
2243 }
2244 return nullptr;
2245}
2246
2247void NetworkProcess::connectionToContextProcessWasClosed(Ref<WebSWServerToContextConnection>&& serverToContextConnection)
2248{
2249 auto& registrableDomain = serverToContextConnection->registrableDomain();
2250
2251 serverToContextConnection->connectionClosed();
2252 m_serverToContextConnections.remove(registrableDomain);
2253
2254 for (auto& swServer : m_swServers.values())
2255 swServer->markAllWorkersForRegistrableDomainAsTerminated(registrableDomain);
2256
2257 if (needsServerToContextConnectionForRegistrableDomain(registrableDomain)) {
2258 RELEASE_LOG(ServiceWorker, "Connection to service worker process was closed but is still needed, relaunching it");
2259 createServerToContextConnection(registrableDomain, WTF::nullopt);
2260 }
2261}
2262
2263bool NetworkProcess::needsServerToContextConnectionForRegistrableDomain(const RegistrableDomain& registrableDomain) const
2264{
2265 return WTF::anyOf(m_swServers.values(), [&](auto& swServer) {
2266 return swServer->needsServerToContextConnectionForRegistrableDomain(registrableDomain);
2267 });
2268}
2269
2270SWServer& NetworkProcess::swServerForSession(PAL::SessionID sessionID)
2271{
2272 ASSERT(sessionID.isValid());
2273
2274 auto result = m_swServers.ensure(sessionID, [&] {
2275 auto path = m_swDatabasePaths.get(sessionID);
2276 // There should already be a registered path for this PAL::SessionID.
2277 // If there's not, then where did this PAL::SessionID come from?
2278 ASSERT(sessionID.isEphemeral() || !path.isEmpty());
2279
2280 auto value = std::make_unique<SWServer>(makeUniqueRef<WebSWOriginStore>(), WTFMove(path), sessionID);
2281 if (m_shouldDisableServiceWorkerProcessTerminationDelay)
2282 value->disableServiceWorkerProcessTerminationDelay();
2283 return value;
2284 });
2285
2286 return *result.iterator->value;
2287}
2288
2289WebSWOriginStore& NetworkProcess::swOriginStoreForSession(PAL::SessionID sessionID)
2290{
2291 return static_cast<WebSWOriginStore&>(swServerForSession(sessionID).originStore());
2292}
2293
2294WebSWOriginStore* NetworkProcess::existingSWOriginStoreForSession(PAL::SessionID sessionID) const
2295{
2296 auto* swServer = m_swServers.get(sessionID);
2297 if (!swServer)
2298 return nullptr;
2299 return &static_cast<WebSWOriginStore&>(swServer->originStore());
2300}
2301
2302WebSWServerToContextConnection* NetworkProcess::serverToContextConnectionForRegistrableDomain(const RegistrableDomain& registrableDomain)
2303{
2304 return m_serverToContextConnections.get(registrableDomain);
2305}
2306
2307void NetworkProcess::createServerToContextConnection(const RegistrableDomain& registrableDomain, Optional<PAL::SessionID> sessionID)
2308{
2309 if (m_waitingForServerToContextProcessConnection)
2310 return;
2311
2312 m_waitingForServerToContextProcessConnection = true;
2313 if (sessionID)
2314 parentProcessConnection()->send(Messages::NetworkProcessProxy::EstablishWorkerContextConnectionToNetworkProcessForExplicitSession(registrableDomain, *sessionID), 0);
2315 else
2316 parentProcessConnection()->send(Messages::NetworkProcessProxy::EstablishWorkerContextConnectionToNetworkProcess(registrableDomain), 0);
2317}
2318
2319void NetworkProcess::postMessageToServiceWorkerClient(const ServiceWorkerClientIdentifier& destinationIdentifier, MessageWithMessagePorts&& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin)
2320{
2321 if (auto* connection = m_swServerConnections.get(destinationIdentifier.serverConnectionIdentifier))
2322 connection->postMessageToServiceWorkerClient(destinationIdentifier.contextIdentifier, WTFMove(message), sourceIdentifier, sourceOrigin);
2323}
2324
2325void NetworkProcess::postMessageToServiceWorker(WebCore::ServiceWorkerIdentifier destination, WebCore::MessageWithMessagePorts&& message, const WebCore::ServiceWorkerOrClientIdentifier& source, SWServerConnectionIdentifier connectionIdentifier)
2326{
2327 if (auto* connection = m_swServerConnections.get(connectionIdentifier))
2328 connection->postMessageToServiceWorker(destination, WTFMove(message), source);
2329}
2330
2331void NetworkProcess::registerSWServerConnection(WebSWServerConnection& connection)
2332{
2333 ASSERT(parentProcessHasServiceWorkerEntitlement());
2334 ASSERT(!m_swServerConnections.contains(connection.identifier()));
2335 m_swServerConnections.add(connection.identifier(), &connection);
2336 swOriginStoreForSession(connection.sessionID()).registerSWServerConnection(connection);
2337}
2338
2339void NetworkProcess::unregisterSWServerConnection(WebSWServerConnection& connection)
2340{
2341 ASSERT(m_swServerConnections.get(connection.identifier()) == &connection);
2342 m_swServerConnections.remove(connection.identifier());
2343 if (auto* store = existingSWOriginStoreForSession(connection.sessionID()))
2344 store->unregisterSWServerConnection(connection);
2345}
2346
2347void NetworkProcess::swContextConnectionMayNoLongerBeNeeded(WebSWServerToContextConnection& serverToContextConnection)
2348{
2349 auto& registrableDomain = serverToContextConnection.registrableDomain();
2350 if (needsServerToContextConnectionForRegistrableDomain(registrableDomain))
2351 return;
2352
2353 RELEASE_LOG(ServiceWorker, "Service worker process is no longer needed, terminating it");
2354 serverToContextConnection.terminate();
2355
2356 for (auto& swServer : m_swServers.values())
2357 swServer->markAllWorkersForRegistrableDomainAsTerminated(registrableDomain);
2358
2359 serverToContextConnection.connectionClosed();
2360 m_serverToContextConnections.remove(registrableDomain);
2361}
2362
2363void NetworkProcess::disableServiceWorkerProcessTerminationDelay()
2364{
2365 if (m_shouldDisableServiceWorkerProcessTerminationDelay)
2366 return;
2367
2368 m_shouldDisableServiceWorkerProcessTerminationDelay = true;
2369 for (auto& swServer : m_swServers.values())
2370 swServer->disableServiceWorkerProcessTerminationDelay();
2371}
2372
2373void NetworkProcess::addServiceWorkerSession(PAL::SessionID sessionID, String& serviceWorkerRegistrationDirectory, const SandboxExtension::Handle& handle)
2374{
2375 auto addResult = m_swDatabasePaths.add(sessionID, serviceWorkerRegistrationDirectory);
2376 if (addResult.isNewEntry) {
2377 SandboxExtension::consumePermanently(handle);
2378 if (!serviceWorkerRegistrationDirectory.isEmpty())
2379 postStorageTask(createCrossThreadTask(*this, &NetworkProcess::ensurePathExists, serviceWorkerRegistrationDirectory));
2380 }
2381}
2382#endif // ENABLE(SERVICE_WORKER)
2383
2384void NetworkProcess::requestStorageSpace(PAL::SessionID sessionID, const ClientOrigin& origin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(Optional<uint64_t>)>&& callback)
2385{
2386 parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::RequestStorageSpace { sessionID, origin, quota, currentSize, spaceRequired }, WTFMove(callback), 0);
2387}
2388
2389class QuotaUserInitializer final : public WebCore::StorageQuotaUser {
2390public:
2391 explicit QuotaUserInitializer(StorageQuotaManager& manager)
2392 : m_manager(makeWeakPtr(manager))
2393 {
2394 manager.addUser(*this);
2395 }
2396
2397 ~QuotaUserInitializer()
2398 {
2399 if (m_manager)
2400 m_manager->removeUser(*this);
2401 if (m_callback)
2402 m_callback();
2403 }
2404
2405private:
2406 // StorageQuotaUser API.
2407 uint64_t spaceUsed() const final
2408 {
2409 ASSERT_NOT_REACHED();
2410 return 0;
2411 }
2412
2413 void whenInitialized(CompletionHandler<void()>&& callback) final
2414 {
2415 m_callback = WTFMove(callback);
2416 }
2417
2418 WeakPtr<StorageQuotaManager> m_manager;
2419 CompletionHandler<void()> m_callback;
2420};
2421
2422void NetworkProcess::initializeQuotaUsers(StorageQuotaManager& manager, PAL::SessionID sessionID, const ClientOrigin& origin)
2423{
2424 RunLoop::main().dispatch([this, weakThis = makeWeakPtr(this), sessionID, origin, user = std::make_unique<QuotaUserInitializer>(manager)]() mutable {
2425 if (!weakThis)
2426 return;
2427 this->idbServer(sessionID).initializeQuotaUser(origin);
2428 CacheStorage::Engine::initializeQuotaUser(*this, sessionID, origin, [user = WTFMove(user)] { });
2429 });
2430}
2431
2432StorageQuotaManager& NetworkProcess::storageQuotaManager(PAL::SessionID sessionID, const ClientOrigin& origin)
2433{
2434 auto& storageQuotaManagers = m_storageQuotaManagers.ensure(sessionID, [] {
2435 return StorageQuotaManagers { };
2436 }).iterator->value;
2437 return *storageQuotaManagers.managersPerOrigin().ensure(origin, [this, &storageQuotaManagers, sessionID, &origin] {
2438 auto manager = std::make_unique<StorageQuotaManager>(storageQuotaManagers.defaultQuota(origin), [this, sessionID, origin](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
2439 this->requestStorageSpace(sessionID, origin, quota, currentSpace, spaceIncrease, WTFMove(callback));
2440 });
2441 initializeQuotaUsers(*manager, sessionID, origin);
2442 return manager;
2443 }).iterator->value;
2444}
2445
2446#if !PLATFORM(COCOA)
2447void NetworkProcess::originsWithPersistentCredentials(CompletionHandler<void(Vector<WebCore::SecurityOriginData>)>&& completionHandler)
2448{
2449 completionHandler(Vector<WebCore::SecurityOriginData>());
2450}
2451
2452void NetworkProcess::removeCredentialsWithOrigins(const Vector<WebCore::SecurityOriginData>&, CompletionHandler<void()>&& completionHandler)
2453{
2454 completionHandler();
2455}
2456
2457void NetworkProcess::initializeProcess(const AuxiliaryProcessInitializationParameters&)
2458{
2459}
2460
2461void NetworkProcess::initializeProcessName(const AuxiliaryProcessInitializationParameters&)
2462{
2463}
2464
2465void NetworkProcess::initializeSandbox(const AuxiliaryProcessInitializationParameters&, SandboxInitializationParameters&)
2466{
2467}
2468
2469void NetworkProcess::syncAllCookies()
2470{
2471}
2472
2473void NetworkProcess::platformSyncAllCookies(CompletionHandler<void()>&& completionHandler)
2474{
2475 completionHandler();
2476}
2477
2478#endif
2479
2480void NetworkProcess::storeAdClickAttribution(PAL::SessionID sessionID, WebCore::AdClickAttribution&& adClickAttribution)
2481{
2482 if (auto* session = networkSession(sessionID))
2483 session->storeAdClickAttribution(WTFMove(adClickAttribution));
2484}
2485
2486void NetworkProcess::dumpAdClickAttribution(PAL::SessionID sessionID, CompletionHandler<void(String)>&& completionHandler)
2487{
2488 if (auto* session = networkSession(sessionID))
2489 return session->dumpAdClickAttribution(WTFMove(completionHandler));
2490
2491 completionHandler({ });
2492}
2493
2494void NetworkProcess::clearAdClickAttribution(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
2495{
2496 if (auto* session = networkSession(sessionID))
2497 session->clearAdClickAttribution();
2498
2499 completionHandler();
2500}
2501
2502void NetworkProcess::setAdClickAttributionOverrideTimerForTesting(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler)
2503{
2504 if (auto* session = networkSession(sessionID))
2505 session->setAdClickAttributionOverrideTimerForTesting(value);
2506
2507 completionHandler();
2508}
2509
2510void NetworkProcess::setAdClickAttributionConversionURLForTesting(PAL::SessionID sessionID, URL&& url, CompletionHandler<void()>&& completionHandler)
2511{
2512 if (auto* session = networkSession(sessionID))
2513 session->setAdClickAttributionConversionURLForTesting(WTFMove(url));
2514
2515 completionHandler();
2516}
2517
2518void NetworkProcess::markAdClickAttributionsAsExpiredForTesting(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler)
2519{
2520 if (auto* session = networkSession(sessionID))
2521 session->markAdClickAttributionsAsExpiredForTesting();
2522
2523 completionHandler();
2524}
2525
2526void NetworkProcess::addKeptAliveLoad(Ref<NetworkResourceLoader>&& loader)
2527{
2528 if (auto session = m_networkSessions.get(loader->sessionID()))
2529 session->addKeptAliveLoad(WTFMove(loader));
2530}
2531
2532void NetworkProcess::removeKeptAliveLoad(NetworkResourceLoader& loader)
2533{
2534 if (auto session = m_networkSessions.get(loader.sessionID()))
2535 session->removeKeptAliveLoad(loader);
2536}
2537
2538} // namespace WebKit
2539