| /* |
| * Copyright (C) 2012-2020 Apple Inc. All rights reserved. |
| * Copyright (C) 2018 Sony Interactive Entertainment Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "NetworkProcess.h" |
| |
| #include "ArgumentCoders.h" |
| #include "Attachment.h" |
| #include "AuthenticationManager.h" |
| #include "AuxiliaryProcessMessages.h" |
| #include "DataReference.h" |
| #include "Download.h" |
| #include "DownloadProxyMessages.h" |
| #if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER) |
| #include "LegacyCustomProtocolManager.h" |
| #endif |
| #include "Logging.h" |
| #include "NetworkConnectionToWebProcess.h" |
| #include "NetworkContentRuleListManagerMessages.h" |
| #include "NetworkLoad.h" |
| #include "NetworkLoadScheduler.h" |
| #include "NetworkProcessCreationParameters.h" |
| #include "NetworkProcessPlatformStrategies.h" |
| #include "NetworkProcessProxyMessages.h" |
| #include "NetworkResourceLoader.h" |
| #include "NetworkSession.h" |
| #include "NetworkSessionCreationParameters.h" |
| #include "NetworkStorageManager.h" |
| #include "PreconnectTask.h" |
| #include "PrivateClickMeasurementStore.h" |
| #include "RemoteNetworkingContext.h" |
| #include "ShouldGrandfatherStatistics.h" |
| #include "StorageAccessStatus.h" |
| #include "StorageManagerSet.h" |
| #include "WebCookieManager.h" |
| #include "WebPageProxyMessages.h" |
| #include "WebProcessPoolMessages.h" |
| #include "WebResourceLoadStatisticsStore.h" |
| #include "WebSWOriginStore.h" |
| #include "WebSWServerConnection.h" |
| #include "WebSWServerToContextConnection.h" |
| #include "WebsiteDataFetchOption.h" |
| #include "WebsiteDataStore.h" |
| #include "WebsiteDataStoreParameters.h" |
| #include "WebsiteDataType.h" |
| #include <WebCore/ClientOrigin.h> |
| #include <WebCore/CookieJar.h> |
| #include <WebCore/DNS.h> |
| #include <WebCore/DeprecatedGlobalSettings.h> |
| #include <WebCore/DiagnosticLoggingClient.h> |
| #include <WebCore/HTTPCookieAcceptPolicy.h> |
| #include <WebCore/LegacySchemeRegistry.h> |
| #include <WebCore/LogInitialization.h> |
| #include <WebCore/MIMETypeRegistry.h> |
| #include <WebCore/NetworkStateNotifier.h> |
| #include <WebCore/NetworkStorageSession.h> |
| #include <WebCore/ResourceRequest.h> |
| #include <WebCore/RuntimeApplicationChecks.h> |
| #include <WebCore/RuntimeEnabledFeatures.h> |
| #include <WebCore/SecurityOrigin.h> |
| #include <WebCore/SecurityOriginData.h> |
| #include <WebCore/StorageQuotaManager.h> |
| #include <WebCore/UserContentURLPattern.h> |
| #include <wtf/Algorithms.h> |
| #include <wtf/CallbackAggregator.h> |
| #include <wtf/CryptographicallyRandomNumber.h> |
| #include <wtf/OptionSet.h> |
| #include <wtf/ProcessPrivilege.h> |
| #include <wtf/RunLoop.h> |
| #include <wtf/UUID.h> |
| #include <wtf/UniqueRef.h> |
| #include <wtf/text/AtomString.h> |
| |
| #if ENABLE(SEC_ITEM_SHIM) |
| #include "SecItemShim.h" |
| #endif |
| |
| #include "NetworkCache.h" |
| #include "NetworkCacheCoders.h" |
| |
| #if PLATFORM(COCOA) |
| #include "LaunchServicesDatabaseObserver.h" |
| #include "NetworkSessionCocoa.h" |
| #endif |
| |
| #if USE(SOUP) |
| #include "NetworkSessionSoup.h" |
| #include <WebCore/SoupNetworkSession.h> |
| #endif |
| |
| #if USE(CURL) |
| #include <WebCore/CurlContext.h> |
| #endif |
| |
| #if ENABLE(SERVICE_WORKER) |
| #include "WebSWServerToContextConnectionMessages.h" |
| #endif |
| |
| namespace WebKit { |
| using namespace WebCore; |
| |
| static void callExitSoon(IPC::Connection*) |
| { |
| // If the connection has been closed and we haven't responded in the main thread for 10 seconds |
| // the process will exit forcibly. |
| auto watchdogDelay = 10_s; |
| |
| WorkQueue::create("com.apple.WebKit.NetworkProcess.WatchDogQueue")->dispatchAfter(watchdogDelay, [] { |
| // We use _exit here since the watchdog callback is called from another thread and we don't want |
| // global destructors or atexit handlers to be called from this thread while the main thread is busy |
| // doing its thing. |
| RELEASE_LOG_ERROR(IPC, "Exiting process early due to unacknowledged closed-connection"); |
| #if OS(WINDOWS) |
| // Calling _exit in non-main threads may cause a deadlock in WTF::Thread::ThreadHolder::~ThreadHolder. |
| TerminateProcess(GetCurrentProcess(), EXIT_FAILURE); |
| #else |
| _exit(EXIT_FAILURE); |
| #endif |
| }); |
| } |
| |
| static inline MessagePortChannelRegistry createMessagePortChannelRegistry(NetworkProcess& networkProcess) |
| { |
| return MessagePortChannelRegistry { [&networkProcess](auto& messagePortIdentifier, auto processIdentifier, auto&& completionHandler) { |
| auto* connection = networkProcess.webProcessConnection(processIdentifier); |
| if (!connection) { |
| completionHandler(MessagePortChannelProvider::HasActivity::No); |
| return; |
| } |
| |
| connection->checkProcessLocalPortForActivity(messagePortIdentifier, WTFMove(completionHandler)); |
| } }; |
| } |
| |
| NetworkProcess::NetworkProcess(AuxiliaryProcessInitializationParameters&& parameters) |
| : m_downloadManager(*this) |
| , m_storageManagerSet(StorageManagerSet::create()) |
| #if ENABLE(CONTENT_EXTENSIONS) |
| , m_networkContentRuleListManager(*this) |
| #endif |
| #if PLATFORM(IOS_FAMILY) |
| , m_webSQLiteDatabaseTracker([this](bool isHoldingLockedFiles) { setIsHoldingLockedFiles(isHoldingLockedFiles); }) |
| #endif |
| , m_messagePortChannelRegistry(createMessagePortChannelRegistry(*this)) |
| { |
| NetworkProcessPlatformStrategies::initialize(); |
| |
| addSupplement<AuthenticationManager>(); |
| addSupplement<WebCookieManager>(); |
| #if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER) |
| addSupplement<LegacyCustomProtocolManager>(); |
| #endif |
| #if HAVE(LSDATABASECONTEXT) |
| addSupplement<LaunchServicesDatabaseObserver>(); |
| #endif |
| #if PLATFORM(COCOA) && ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER) |
| LegacyCustomProtocolManager::networkProcessCreated(*this); |
| #endif |
| |
| NetworkStateNotifier::singleton().addListener([weakThis = WeakPtr { *this }](bool isOnLine) { |
| if (!weakThis) |
| return; |
| for (auto& webProcessConnection : weakThis->m_webProcessConnections.values()) |
| webProcessConnection->setOnLineState(isOnLine); |
| }); |
| |
| initialize(WTFMove(parameters)); |
| } |
| |
| NetworkProcess::~NetworkProcess() |
| { |
| for (auto& callbacks : m_cacheStorageParametersCallbacks.values()) { |
| for (auto& callback : callbacks) |
| callback(String { }); |
| } |
| } |
| |
| AuthenticationManager& NetworkProcess::authenticationManager() |
| { |
| return *supplement<AuthenticationManager>(); |
| } |
| |
| DownloadManager& NetworkProcess::downloadManager() |
| { |
| return m_downloadManager; |
| } |
| |
| void NetworkProcess::removeNetworkConnectionToWebProcess(NetworkConnectionToWebProcess& connection) |
| { |
| ASSERT(m_webProcessConnections.contains(connection.webProcessIdentifier())); |
| m_webProcessConnections.remove(connection.webProcessIdentifier()); |
| } |
| |
| bool NetworkProcess::shouldTerminate() |
| { |
| // Network process keeps session cookies and credentials, so it should never terminate (as long as UI process connection is alive). |
| return false; |
| } |
| |
| void NetworkProcess::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder) |
| { |
| ASSERT(parentProcessConnection() == &connection); |
| if (parentProcessConnection() != &connection) { |
| WTFLogAlways("Ignored message '%s' because it did not come from the UIProcess (destination=%" PRIu64 ")", description(decoder.messageName()), decoder.destinationID()); |
| ASSERT_NOT_REACHED(); |
| return; |
| } |
| |
| if (messageReceiverMap().dispatchMessage(connection, decoder)) |
| return; |
| |
| if (decoder.messageReceiverName() == Messages::AuxiliaryProcess::messageReceiverName()) { |
| AuxiliaryProcess::didReceiveMessage(connection, decoder); |
| return; |
| } |
| |
| #if ENABLE(CONTENT_EXTENSIONS) |
| if (decoder.messageReceiverName() == Messages::NetworkContentRuleListManager::messageReceiverName()) { |
| m_networkContentRuleListManager.didReceiveMessage(connection, decoder); |
| return; |
| } |
| #endif |
| |
| didReceiveNetworkProcessMessage(connection, decoder); |
| } |
| |
| bool NetworkProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, UniqueRef<IPC::Encoder>& replyEncoder) |
| { |
| ASSERT(parentProcessConnection() == &connection); |
| if (parentProcessConnection() != &connection) { |
| WTFLogAlways("Ignored message '%s' because it did not come from the UIProcess (destination=%" PRIu64 ")", description(decoder.messageName()), decoder.destinationID()); |
| ASSERT_NOT_REACHED(); |
| return false; |
| } |
| |
| if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder)) |
| return true; |
| |
| return didReceiveSyncNetworkProcessMessage(connection, decoder, replyEncoder); |
| } |
| |
| void NetworkProcess::didClose(IPC::Connection&) |
| { |
| ASSERT(RunLoop::isMain()); |
| |
| auto callbackAggregator = CallbackAggregator::create([this] { |
| ASSERT(RunLoop::isMain()); |
| stopRunLoop(); |
| }); |
| |
| // Make sure we flush all cookies to disk before exiting. |
| forEachNetworkSession([&] (auto& networkSession) { |
| platformFlushCookies(networkSession.sessionID(), [callbackAggregator] { }); |
| }); |
| |
| // Make sure reference to NetworkProcess in spaceRequester is removed. |
| auto servers = std::exchange(m_webIDBServers, { }); |
| for (auto& server : servers.values()) |
| server->close([callbackAggregator] { }); |
| } |
| |
| void NetworkProcess::didCreateDownload() |
| { |
| disableTermination(); |
| } |
| |
| void NetworkProcess::didDestroyDownload() |
| { |
| enableTermination(); |
| } |
| |
| IPC::Connection* NetworkProcess::downloadProxyConnection() |
| { |
| return parentProcessConnection(); |
| } |
| |
| AuthenticationManager& NetworkProcess::downloadsAuthenticationManager() |
| { |
| return authenticationManager(); |
| } |
| |
| void NetworkProcess::lowMemoryHandler(Critical critical) |
| { |
| if (m_suppressMemoryPressureHandler) |
| return; |
| |
| WTF::releaseFastMallocFreeMemory(); |
| |
| forEachNetworkSession([](auto& networkSession) { |
| networkSession.clearPrefetchCache(); |
| }); |
| |
| m_storageManagerSet->handleLowMemoryWarning(); |
| |
| #if ENABLE(SERVICE_WORKER) |
| for (auto& swServer : m_swServers.values()) |
| swServer->handleLowMemoryWarning(); |
| #endif |
| } |
| |
| void NetworkProcess::initializeNetworkProcess(NetworkProcessCreationParameters&& parameters) |
| { |
| #if HAVE(SEC_KEY_PROXY) |
| WTF::setProcessPrivileges({ ProcessPrivilege::CanAccessRawCookies }); |
| #else |
| WTF::setProcessPrivileges({ ProcessPrivilege::CanAccessRawCookies, ProcessPrivilege::CanAccessCredentials }); |
| #endif |
| WebCore::NetworkStorageSession::permitProcessToUseCookieAPI(true); |
| platformInitializeNetworkProcess(parameters); |
| |
| WTF::Thread::setCurrentThreadIsUserInitiated(); |
| AtomString::init(); |
| |
| m_suppressMemoryPressureHandler = parameters.shouldSuppressMemoryPressureHandler; |
| if (!m_suppressMemoryPressureHandler) { |
| auto& memoryPressureHandler = MemoryPressureHandler::singleton(); |
| memoryPressureHandler.setLowMemoryHandler([this] (Critical critical, Synchronous) { |
| lowMemoryHandler(critical); |
| }); |
| memoryPressureHandler.install(); |
| } |
| |
| setCacheModel(parameters.cacheModel); |
| |
| setPrivateClickMeasurementEnabled(parameters.enablePrivateClickMeasurement); |
| m_ftpEnabled = parameters.ftpEnabled; |
| |
| for (auto& supplement : m_supplements.values()) |
| supplement->initialize(parameters); |
| |
| for (auto& scheme : parameters.urlSchemesRegisteredAsSecure) |
| registerURLSchemeAsSecure(scheme); |
| |
| for (auto& scheme : parameters.urlSchemesRegisteredAsBypassingContentSecurityPolicy) |
| registerURLSchemeAsBypassingContentSecurityPolicy(scheme); |
| |
| for (auto& scheme : parameters.urlSchemesRegisteredAsLocal) |
| registerURLSchemeAsLocal(scheme); |
| |
| for (auto& scheme : parameters.urlSchemesRegisteredAsNoAccess) |
| registerURLSchemeAsNoAccess(scheme); |
| |
| for (auto&& websiteDataStoreParameters : WTFMove(parameters.websiteDataStoreParameters)) |
| addWebsiteDataStore(WTFMove(websiteDataStoreParameters)); |
| |
| RELEASE_LOG(Process, "%p - NetworkProcess::initializeNetworkProcess: Presenting processPID=%d", this, WebCore::presentingApplicationPID()); |
| } |
| |
| void NetworkProcess::initializeConnection(IPC::Connection* connection) |
| { |
| AuxiliaryProcess::initializeConnection(connection); |
| |
| // We give a chance for didClose() to get called on the main thread but forcefully call _exit() after a delay |
| // in case the main thread is unresponsive or didClose() takes too long. |
| connection->setDidCloseOnConnectionWorkQueueCallback(callExitSoon); |
| |
| for (auto& supplement : m_supplements.values()) |
| supplement->initializeConnection(connection); |
| } |
| |
| void NetworkProcess::createNetworkConnectionToWebProcess(ProcessIdentifier identifier, PAL::SessionID sessionID, CompletionHandler<void(std::optional<IPC::Attachment>&&, HTTPCookieAcceptPolicy)>&& completionHandler) |
| { |
| auto ipcConnection = createIPCConnectionPair(); |
| if (!ipcConnection) { |
| completionHandler({ }, HTTPCookieAcceptPolicy::Never); |
| return; |
| } |
| |
| auto newConnection = NetworkConnectionToWebProcess::create(*this, identifier, sessionID, ipcConnection->first); |
| auto& connection = newConnection.get(); |
| |
| ASSERT(!m_webProcessConnections.contains(identifier)); |
| m_webProcessConnections.add(identifier, WTFMove(newConnection)); |
| |
| auto* storage = storageSession(sessionID); |
| completionHandler(WTFMove(ipcConnection->second), storage ? storage->cookieAcceptPolicy() : HTTPCookieAcceptPolicy::Never); |
| |
| connection.setOnLineState(NetworkStateNotifier::singleton().onLine()); |
| |
| m_storageManagerSet->addConnection(connection.connection()); |
| webIDBServer(sessionID).addConnection(connection.connection(), identifier); |
| if (auto manager = m_storageManagers.get(sessionID)) |
| manager->startReceivingMessageFromConnection(connection.connection()); |
| } |
| |
| void NetworkProcess::clearCachedCredentials(PAL::SessionID sessionID) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* storageSession = networkSession->networkStorageSession()) |
| storageSession->credentialStorage().clearCredentials(); |
| networkSession->clearCredentials(); |
| } |
| } |
| |
| void NetworkProcess::addWebsiteDataStore(WebsiteDataStoreParameters&& parameters) |
| { |
| auto sessionID = parameters.networkSessionParameters.sessionID; |
| |
| addStorageManagerForSession(sessionID, parameters.generalStorageDirectory, parameters.generalStorageDirectoryHandle); |
| addSessionStorageQuotaManager(sessionID, parameters.perOriginStorageQuota, parameters.perThirdPartyOriginStorageQuota, parameters.cacheStorageDirectory, parameters.cacheStorageDirectoryExtensionHandle); |
| |
| addIndexedDatabaseSession(sessionID, parameters.indexedDatabaseDirectory, parameters.indexedDatabaseDirectoryExtensionHandle); |
| |
| #if ENABLE(SERVICE_WORKER) |
| addServiceWorkerSession(sessionID, parameters.serviceWorkerProcessTerminationDelayEnabled, WTFMove(parameters.serviceWorkerRegistrationDirectory), parameters.serviceWorkerRegistrationDirectoryExtensionHandle); |
| #endif |
| |
| m_storageManagerSet->add(sessionID, parameters.localStorageDirectory, parameters.localStorageDirectoryExtensionHandle); |
| |
| RemoteNetworkingContext::ensureWebsiteDataStoreSession(*this, WTFMove(parameters)); |
| } |
| |
| void NetworkProcess::addSessionStorageQuotaManager(PAL::SessionID sessionID, uint64_t defaultQuota, uint64_t defaultThirdPartyQuota, const String& cacheRootPath, SandboxExtension::Handle& cacheRootPathHandle) |
| { |
| Locker locker { m_sessionStorageQuotaManagersLock }; |
| auto isNewEntry = m_sessionStorageQuotaManagers.ensure(sessionID, [defaultQuota, defaultThirdPartyQuota, &cacheRootPath] { |
| return makeUnique<SessionStorageQuotaManager>(cacheRootPath, defaultQuota, defaultThirdPartyQuota); |
| }).isNewEntry; |
| if (isNewEntry) |
| SandboxExtension::consumePermanently(cacheRootPathHandle); |
| else |
| ASSERT_NOT_REACHED(); |
| } |
| |
| void NetworkProcess::removeSessionStorageQuotaManager(PAL::SessionID sessionID) |
| { |
| Locker locker { m_sessionStorageQuotaManagersLock }; |
| ASSERT(m_sessionStorageQuotaManagers.contains(sessionID)); |
| m_sessionStorageQuotaManagers.remove(sessionID); |
| } |
| |
| void NetworkProcess::addStorageManagerForSession(PAL::SessionID sessionID, const String& generalStoragePath, SandboxExtension::Handle& generalStoragePathHandle) |
| { |
| m_storageManagers.ensure(sessionID, [&] { |
| SandboxExtension::consumePermanently(generalStoragePathHandle); |
| return NetworkStorageManager::create(sessionID, generalStoragePath); |
| }); |
| } |
| |
| void NetworkProcess::removeStorageManagerForSession(PAL::SessionID sessionID) |
| { |
| if (auto manager = m_storageManagers.take(sessionID)) |
| manager->close(); |
| } |
| |
| void NetworkProcess::forEachNetworkSession(const Function<void(NetworkSession&)>& functor) |
| { |
| for (auto& session : m_networkSessions.values()) |
| functor(*session); |
| } |
| |
| std::unique_ptr<WebCore::NetworkStorageSession> NetworkProcess::newTestingSession(PAL::SessionID sessionID) |
| { |
| #if PLATFORM(COCOA) |
| // 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>). |
| auto session = WebCore::createPrivateStorageSession(makeString("WebKit Test-", getCurrentProcessID()).createCFString().get()); |
| RetainPtr<CFHTTPCookieStorageRef> cookieStorage; |
| if (WebCore::NetworkStorageSession::processMayUseCookieAPI()) { |
| ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies)); |
| if (session) |
| cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, session.get())); |
| } |
| return makeUnique<WebCore::NetworkStorageSession>(sessionID, WTFMove(session), WTFMove(cookieStorage)); |
| #elif USE(CURL) || USE(SOUP) |
| return makeUnique<WebCore::NetworkStorageSession>(sessionID); |
| #endif |
| } |
| |
| #if PLATFORM(COCOA) |
| void NetworkProcess::ensureSession(PAL::SessionID sessionID, bool shouldUseTestingNetworkSession, const String& identifierBase, RetainPtr<CFHTTPCookieStorageRef>&& cookieStorage) |
| #else |
| void NetworkProcess::ensureSession(PAL::SessionID sessionID, bool shouldUseTestingNetworkSession, const String& identifierBase) |
| #endif |
| { |
| auto addResult = m_networkStorageSessions.add(sessionID, nullptr); |
| if (!addResult.isNewEntry) |
| return; |
| |
| if (shouldUseTestingNetworkSession) { |
| addResult.iterator->value = newTestingSession(sessionID); |
| return; |
| } |
| |
| #if PLATFORM(COCOA) |
| RetainPtr<CFURLStorageSessionRef> storageSession; |
| RetainPtr<CFStringRef> cfIdentifier = makeString(identifierBase, ".PrivateBrowsing.", createCanonicalUUIDString()).createCFString(); |
| if (sessionID.isEphemeral()) |
| storageSession = createPrivateStorageSession(cfIdentifier.get()); |
| else if (sessionID != PAL::SessionID::defaultSessionID()) |
| storageSession = WebCore::NetworkStorageSession::createCFStorageSessionForIdentifier(cfIdentifier.get()); |
| |
| if (NetworkStorageSession::processMayUseCookieAPI()) { |
| ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies)); |
| if (!cookieStorage && storageSession) |
| cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, storageSession.get())); |
| } |
| |
| addResult.iterator->value = makeUnique<NetworkStorageSession>(sessionID, WTFMove(storageSession), WTFMove(cookieStorage)); |
| #elif USE(CURL) || USE(SOUP) |
| addResult.iterator->value = makeUnique<NetworkStorageSession>(sessionID); |
| #endif |
| } |
| |
| void NetworkProcess::cookieAcceptPolicyChanged(HTTPCookieAcceptPolicy newPolicy) |
| { |
| for (auto& connection : m_webProcessConnections.values()) |
| connection->cookieAcceptPolicyChanged(newPolicy); |
| } |
| |
| WebCore::NetworkStorageSession* NetworkProcess::storageSession(PAL::SessionID sessionID) const |
| { |
| return m_networkStorageSessions.get(sessionID); |
| } |
| |
| void NetworkProcess::forEachNetworkStorageSession(const Function<void(WebCore::NetworkStorageSession&)>& functor) |
| { |
| for (auto& storageSession : m_networkStorageSessions.values()) |
| functor(*storageSession); |
| } |
| |
| NetworkSession* NetworkProcess::networkSession(PAL::SessionID sessionID) const |
| { |
| ASSERT(RunLoop::isMain()); |
| return m_networkSessions.get(sessionID); |
| } |
| |
| void NetworkProcess::setSession(PAL::SessionID sessionID, std::unique_ptr<NetworkSession>&& session) |
| { |
| ASSERT(RunLoop::isMain()); |
| m_networkSessions.set(sessionID, WTFMove(session)); |
| } |
| |
| void NetworkProcess::destroySession(PAL::SessionID sessionID) |
| { |
| ASSERT(RunLoop::isMain()); |
| #if !USE(SOUP) && !USE(CURL) |
| // cURL and Soup based ports destroy the default session right before the process exits to avoid leaking |
| // network resources like the cookies database. |
| ASSERT(sessionID != PAL::SessionID::defaultSessionID()); |
| #endif |
| |
| if (auto session = m_networkSessions.take(sessionID)) |
| session->invalidateAndCancel(); |
| m_networkStorageSessions.remove(sessionID); |
| m_sessionsControlledByAutomation.remove(sessionID); |
| CacheStorage::Engine::destroyEngine(*this, sessionID); |
| |
| #if ENABLE(SERVICE_WORKER) |
| m_swServers.remove(sessionID); |
| m_serviceWorkerInfo.remove(sessionID); |
| #endif |
| |
| m_storageManagerSet->remove(sessionID); |
| if (auto server = m_webIDBServers.take(sessionID)) |
| server->close(); |
| removeStorageManagerForSession(sessionID); |
| } |
| |
| #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| void NetworkProcess::dumpResourceLoadStatistics(PAL::SessionID sessionID, CompletionHandler<void(String)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->dumpResourceLoadStatistics(WTFMove(completionHandler)); |
| else |
| completionHandler({ }); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler({ }); |
| } |
| } |
| |
| void NetworkProcess::updatePrevalentDomainsToBlockCookiesFor(PAL::SessionID sessionID, const Vector<RegistrableDomain>& domainsToBlock, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->setPrevalentDomainsToBlockAndDeleteCookiesFor(domainsToBlock); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::isGrandfathered(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->isGrandfathered(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::isPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->isPrevalentResource(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::isVeryPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->isVeryPrevalentResource(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::setAgeCapForClientSideCookies(PAL::SessionID sessionID, std::optional<Seconds> seconds, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->setAgeCapForClientSideCookies(seconds); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setGrandfathered(PAL::SessionID sessionID, const RegistrableDomain& domain, bool isGrandfathered, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setGrandfathered(domain, isGrandfathered, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setPrevalentResource(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setPrevalentResourceForDebugMode(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setPrevalentResourceForDebugMode(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setVeryPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setVeryPrevalentResource(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::clearPrevalentResource(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->clearPrevalentResource(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::scheduleCookieBlockingUpdate(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->scheduleCookieBlockingUpdate(WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::scheduleClearInMemoryAndPersistent(PAL::SessionID sessionID, std::optional<WallTime> modifiedSince, ShouldGrandfatherStatistics shouldGrandfather, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| networkSession->clearIsolatedSessions(); |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) { |
| if (modifiedSince) |
| resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince.value(), shouldGrandfather, WTFMove(completionHandler)); |
| else |
| resourceLoadStatistics->scheduleClearInMemoryAndPersistent(shouldGrandfather, WTFMove(completionHandler)); |
| } else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::getResourceLoadStatisticsDataSummary(PAL::SessionID sessionID, CompletionHandler<void(Vector<WebResourceLoadStatisticsStore::ThirdPartyData>&&)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->aggregatedThirdPartyData(WTFMove(completionHandler)); |
| else |
| completionHandler({ }); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler({ }); |
| } |
| } |
| |
| void NetworkProcess::resetParametersToDefaultValues(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| networkSession->resetCNAMEDomainData(); |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->resetParametersToDefaultValues(WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::scheduleStatisticsAndDataRecordsProcessing(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->scheduleStatisticsAndDataRecordsProcessing(WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::statisticsDatabaseHasAllTables(PAL::SessionID sessionID, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->statisticsDatabaseHasAllTables(WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::setNotifyPagesWhenDataRecordsWereScanned(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setNotifyPagesWhenDataRecordsWereScanned(value, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setIsRunningResourceLoadStatisticsTest(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setIsRunningTest(value, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setSubframeUnderTopFrameDomain(PAL::SessionID sessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setSubframeUnderTopFrameDomain(subFrameDomain, topFrameDomain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::isRegisteredAsRedirectingTo(PAL::SessionID sessionID, const RegistrableDomain& domainRedirectedFrom, const RegistrableDomain& domainRedirectedTo, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->isRegisteredAsRedirectingTo(domainRedirectedFrom, domainRedirectedTo, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::isRegisteredAsSubFrameUnder(PAL::SessionID sessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->isRegisteredAsSubFrameUnder(subFrameDomain, topFrameDomain, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::setSubresourceUnderTopFrameDomain(PAL::SessionID sessionID, const RegistrableDomain& subresourceDomain, const RegistrableDomain& topFrameDomain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setSubresourceUnderTopFrameDomain(subresourceDomain, topFrameDomain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setSubresourceUniqueRedirectTo(PAL::SessionID sessionID, const RegistrableDomain& subresourceDomain, const RegistrableDomain& domainRedirectedTo, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setSubresourceUniqueRedirectTo(subresourceDomain, domainRedirectedTo, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setSubresourceUniqueRedirectFrom(PAL::SessionID sessionID, const RegistrableDomain& subresourceDomain, const RegistrableDomain& domainRedirectedFrom, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setSubresourceUniqueRedirectFrom(subresourceDomain, domainRedirectedFrom, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::isRegisteredAsSubresourceUnder(PAL::SessionID sessionID, const RegistrableDomain& subresourceDomain, const RegistrableDomain& topFrameDomain, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->isRegisteredAsSubresourceUnder(subresourceDomain, topFrameDomain, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::setTopFrameUniqueRedirectTo(PAL::SessionID sessionID, const RegistrableDomain& topFrameDomain, const RegistrableDomain& domainRedirectedTo, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setTopFrameUniqueRedirectTo(topFrameDomain, domainRedirectedTo, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setTopFrameUniqueRedirectFrom(PAL::SessionID sessionID, const RegistrableDomain& topFrameDomain, const RegistrableDomain& domainRedirectedFrom, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setTopFrameUniqueRedirectFrom(topFrameDomain, domainRedirectedFrom, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| |
| void NetworkProcess::setLastSeen(PAL::SessionID sessionID, const RegistrableDomain& domain, Seconds seconds, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setLastSeen(domain, seconds, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::domainIDExistsInDatabase(PAL::SessionID sessionID, int domainID, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->domainIDExistsInDatabase(domainID, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::mergeStatisticForTesting(PAL::SessionID sessionID, const RegistrableDomain& domain, const RegistrableDomain& topFrameDomain1, const RegistrableDomain& topFrameDomain2, Seconds lastSeen, bool hadUserInteraction, Seconds mostRecentUserInteraction, bool isGrandfathered, bool isPrevalent, bool isVeryPrevalent, unsigned dataRecordsRemoved, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->mergeStatisticForTesting(domain, topFrameDomain1, topFrameDomain2, lastSeen, hadUserInteraction, mostRecentUserInteraction, isGrandfathered, isPrevalent, isVeryPrevalent, dataRecordsRemoved, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::insertExpiredStatisticForTesting(PAL::SessionID sessionID, const RegistrableDomain& domain, unsigned numberOfOperatingDaysPassed, bool hadUserInteraction, bool isScheduledForAllButCookieDataRemoval, bool isPrevalent, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->insertExpiredStatisticForTesting(domain, numberOfOperatingDaysPassed, hadUserInteraction, isScheduledForAllButCookieDataRemoval, isPrevalent, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::getAllStorageAccessEntries(PAL::SessionID sessionID, CompletionHandler<void(Vector<String> domains)>&& completionHandler) |
| { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| completionHandler(networkStorageSession->getAllStorageAccessEntries()); |
| else { |
| ASSERT_NOT_REACHED(); |
| completionHandler({ }); |
| } |
| } |
| |
| void NetworkProcess::logFrameNavigation(PAL::SessionID sessionID, const RegistrableDomain& targetDomain, const RegistrableDomain& topFrameDomain, const RegistrableDomain& sourceDomain, bool isRedirect, bool isMainFrame, Seconds delayAfterMainFrameDocumentLoad, bool wasPotentiallyInitiatedByUser) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->logFrameNavigation(targetDomain, topFrameDomain, sourceDomain, isRedirect, isMainFrame, delayAfterMainFrameDocumentLoad, wasPotentiallyInitiatedByUser); |
| } else |
| ASSERT_NOT_REACHED(); |
| } |
| |
| void NetworkProcess::logUserInteraction(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->logUserInteraction(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::hadUserInteraction(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->hasHadUserInteraction(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::isRelationshipOnlyInDatabaseOnce(PAL::SessionID sessionID, const RegistrableDomain& subDomain, const RegistrableDomain& topDomain, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->isRelationshipOnlyInDatabaseOnce(subDomain, topDomain, WTFMove(completionHandler)); |
| else |
| completionHandler(false); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| } |
| |
| void NetworkProcess::clearUserInteraction(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->clearUserInteraction(domain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::hasLocalStorage(PAL::SessionID sessionID, const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler) |
| { |
| if (m_storageManagerSet->contains(sessionID)) { |
| m_storageManagerSet->getLocalStorageOrigins(sessionID, [domain, completionHandler = WTFMove(completionHandler)](auto&& origins) mutable { |
| completionHandler(WTF::anyOf(origins, [&domain](auto& origin) { |
| return domain.matches(origin); |
| })); |
| }); |
| return; |
| } |
| completionHandler(false); |
| } |
| |
| void NetworkProcess::setCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->setCacheMaxAgeCapForPrevalentResources(Seconds { seconds }); |
| else |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setGrandfatheringTime(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setGrandfatheringTime(seconds, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setMaxStatisticsEntries(PAL::SessionID sessionID, uint64_t maximumEntryCount, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setMaxStatisticsEntries(maximumEntryCount, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setMinimumTimeBetweenDataRecordsRemoval(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setMinimumTimeBetweenDataRecordsRemoval(seconds, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setPruneEntriesDownTo(PAL::SessionID sessionID, uint64_t pruneTargetCount, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setPruneEntriesDownTo(pruneTargetCount, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setTimeToLiveUserInteraction(PAL::SessionID sessionID, Seconds seconds, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setTimeToLiveUserInteraction(seconds, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setShouldClassifyResourcesBeforeDataRecordsRemoval(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setShouldClassifyResourcesBeforeDataRecordsRemoval(value, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setResourceLoadStatisticsEnabled(PAL::SessionID sessionID, bool enabled) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->setResourceLoadStatisticsEnabled(enabled); |
| } |
| |
| void NetworkProcess::setResourceLoadStatisticsLogTestingEvent(bool enabled) |
| { |
| forEachNetworkSession([enabled](auto& networkSession) { |
| networkSession.setResourceLoadStatisticsLogTestingEvent(enabled); |
| }); |
| } |
| |
| void NetworkProcess::setResourceLoadStatisticsDebugMode(PAL::SessionID sessionID, bool debugMode, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setResourceLoadStatisticsDebugMode(debugMode, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::isResourceLoadStatisticsEphemeral(PAL::SessionID sessionID, CompletionHandler<void(bool)>&& completionHandler) const |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) { |
| completionHandler(resourceLoadStatistics->isEphemeral()); |
| return; |
| } |
| } else |
| ASSERT_NOT_REACHED(); |
| completionHandler(false); |
| } |
| |
| void NetworkProcess::resetCacheMaxAgeCapForPrevalentResources(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->resetCacheMaxAgeCapForPrevalentResources(); |
| else |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::didCommitCrossSiteLoadWithDataTransfer(PAL::SessionID sessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, OptionSet<WebCore::CrossSiteNavigationDataTransfer::Flag> navigationDataTransfer, WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID) |
| { |
| ASSERT(!navigationDataTransfer.isEmpty()); |
| |
| if (auto* networkStorageSession = storageSession(sessionID)) { |
| if (!networkStorageSession->shouldBlockThirdPartyCookies(fromDomain)) |
| return; |
| |
| if (navigationDataTransfer.contains(CrossSiteNavigationDataTransfer::Flag::DestinationLinkDecoration)) |
| networkStorageSession->didCommitCrossSiteLoadWithDataTransferFromPrevalentResource(toDomain, webPageID); |
| |
| if (navigationDataTransfer.contains(CrossSiteNavigationDataTransfer::Flag::ReferrerLinkDecoration)) |
| parentProcessConnection()->send(Messages::NetworkProcessProxy::DidCommitCrossSiteLoadWithDataTransferFromPrevalentResource(webPageProxyID), 0); |
| } else |
| ASSERT_NOT_REACHED(); |
| |
| if (navigationDataTransfer.contains(CrossSiteNavigationDataTransfer::Flag::DestinationLinkDecoration)) { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->logCrossSiteLoadWithLinkDecoration(fromDomain, toDomain, [] { }); |
| } else |
| ASSERT_NOT_REACHED(); |
| } |
| } |
| |
| void NetworkProcess::setCrossSiteLoadWithLinkDecorationForTesting(PAL::SessionID sessionID, const RegistrableDomain& fromDomain, const RegistrableDomain& toDomain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->logCrossSiteLoadWithLinkDecoration(fromDomain, toDomain, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::resetCrossSiteLoadsWithLinkDecorationForTesting(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->resetCrossSiteLoadsWithLinkDecorationForTesting(); |
| else |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::hasIsolatedSession(PAL::SessionID sessionID, const WebCore::RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler) const |
| { |
| bool result = false; |
| if (auto* networkSession = this->networkSession(sessionID)) |
| result = networkSession->hasIsolatedSession(domain); |
| completionHandler(result); |
| } |
| |
| #if ENABLE(APP_BOUND_DOMAINS) |
| void NetworkProcess::setAppBoundDomainsForResourceLoadStatistics(PAL::SessionID sessionID, HashSet<WebCore::RegistrableDomain>&& appBoundDomains, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) { |
| resourceLoadStatistics->setAppBoundDomains(WTFMove(appBoundDomains), WTFMove(completionHandler)); |
| return; |
| } |
| } |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| #endif |
| |
| void NetworkProcess::setShouldDowngradeReferrerForTesting(bool enabled, CompletionHandler<void()>&& completionHandler) |
| { |
| forEachNetworkSession([enabled](auto& networkSession) { |
| networkSession.setShouldDowngradeReferrerForTesting(enabled); |
| }); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setThirdPartyCookieBlockingMode(PAL::SessionID sessionID, WebCore::ThirdPartyCookieBlockingMode blockingMode, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->setThirdPartyCookieBlockingMode(blockingMode); |
| else |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setShouldEnbleSameSiteStrictEnforcementForTesting(PAL::SessionID sessionID, WebCore::SameSiteStrictEnforcementEnabled enabled, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->setShouldEnbleSameSiteStrictEnforcement(enabled); |
| else |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setFirstPartyWebsiteDataRemovalModeForTesting(PAL::SessionID sessionID, WebCore::FirstPartyWebsiteDataRemovalMode mode, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->setFirstPartyWebsiteDataRemovalMode(mode, WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setToSameSiteStrictCookiesForTesting(PAL::SessionID sessionID, const WebCore::RegistrableDomain& domain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->setAllCookiesToSameSiteStrict(domain, WTFMove(completionHandler)); |
| else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| |
| void NetworkProcess::setFirstPartyHostCNAMEDomainForTesting(PAL::SessionID sessionID, String&& firstPartyHost, WebCore::RegistrableDomain&& cnameDomain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->setFirstPartyHostCNAMEDomain(WTFMove(firstPartyHost), WTFMove(cnameDomain)); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setThirdPartyCNAMEDomainForTesting(PAL::SessionID sessionID, WebCore::RegistrableDomain&& domain, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->setThirdPartyCNAMEDomainForTesting(WTFMove(domain)); |
| completionHandler(); |
| } |
| #endif // ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| |
| void NetworkProcess::setPrivateClickMeasurementEnabled(bool enabled) |
| { |
| m_privateClickMeasurementEnabled = enabled; |
| } |
| |
| bool NetworkProcess::privateClickMeasurementEnabled() const |
| { |
| return m_privateClickMeasurementEnabled; |
| } |
| |
| void NetworkProcess::setPrivateClickMeasurementDebugMode(PAL::SessionID sessionID, bool enabled) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->setPrivateClickMeasurementDebugMode(enabled); |
| } |
| |
| void NetworkProcess::preconnectTo(PAL::SessionID sessionID, WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID, const URL& url, const String& userAgent, WebCore::StoredCredentialsPolicy storedCredentialsPolicy, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, LastNavigationWasAppInitiated lastNavigationWasAppInitiated) |
| { |
| LOG(Network, "(NetworkProcess) Preconnecting to URL %s (storedCredentialsPolicy %i)", url.string().utf8().data(), (int)storedCredentialsPolicy); |
| |
| #if ENABLE(SERVER_PRECONNECT) |
| #if ENABLE(LEGACY_CUSTOM_PROTOCOL_MANAGER) |
| if (supplement<LegacyCustomProtocolManager>()->supportsScheme(url.protocol().toString())) |
| return; |
| #endif |
| |
| auto* networkSession = this->networkSession(sessionID); |
| if (!networkSession) |
| return; |
| |
| NetworkLoadParameters parameters; |
| parameters.request = ResourceRequest { url }; |
| parameters.request.setIsAppInitiated(lastNavigationWasAppInitiated == LastNavigationWasAppInitiated::Yes); |
| parameters.request.setFirstPartyForCookies(url); |
| parameters.request.setPriority(WebCore::ResourceLoadPriority::VeryHigh); |
| parameters.webPageProxyID = webPageProxyID; |
| parameters.webPageID = webPageID; |
| parameters.isNavigatingToAppBoundDomain = isNavigatingToAppBoundDomain; |
| if (!userAgent.isEmpty()) { |
| // FIXME: we add user-agent to the preconnect request because otherwise the preconnect |
| // gets thrown away by CFNetwork when using an HTTPS proxy (<rdar://problem/59434166>). |
| parameters.request.setHTTPUserAgent(userAgent); |
| } |
| parameters.storedCredentialsPolicy = storedCredentialsPolicy; |
| parameters.shouldPreconnectOnly = PreconnectOnly::Yes; |
| |
| networkSession->networkLoadScheduler().startedPreconnectForMainResource(url, userAgent); |
| auto task = new PreconnectTask(*networkSession, WTFMove(parameters), [weakNetworkSession = WeakPtr { *networkSession }, url, userAgent](const WebCore::ResourceError& error) { |
| if (weakNetworkSession) |
| weakNetworkSession->networkLoadScheduler().finishedPreconnectForMainResource(url, userAgent, error); |
| }); |
| task->setTimeout(10_s); |
| task->start(); |
| #else |
| UNUSED_PARAM(url); |
| UNUSED_PARAM(userAgent); |
| UNUSED_PARAM(storedCredentialsPolicy); |
| #endif |
| } |
| |
| bool NetworkProcess::sessionIsControlledByAutomation(PAL::SessionID sessionID) const |
| { |
| return m_sessionsControlledByAutomation.contains(sessionID); |
| } |
| |
| void NetworkProcess::setSessionIsControlledByAutomation(PAL::SessionID sessionID, bool controlled) |
| { |
| if (controlled) |
| m_sessionsControlledByAutomation.add(sessionID); |
| else |
| m_sessionsControlledByAutomation.remove(sessionID); |
| } |
| |
| static void fetchDiskCacheEntries(NetworkCache::Cache* cache, PAL::SessionID sessionID, OptionSet<WebsiteDataFetchOption> fetchOptions, CompletionHandler<void(Vector<WebsiteData::Entry>)>&& completionHandler) |
| { |
| if (!cache) { |
| RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] () mutable { |
| completionHandler({ }); |
| }); |
| return; |
| } |
| |
| HashMap<SecurityOriginData, uint64_t> originsAndSizes; |
| cache->traverse([fetchOptions, completionHandler = WTFMove(completionHandler), originsAndSizes = WTFMove(originsAndSizes)](auto* traversalEntry) mutable { |
| if (!traversalEntry) { |
| Vector<WebsiteData::Entry> entries; |
| |
| for (auto& originAndSize : originsAndSizes) |
| entries.append(WebsiteData::Entry { originAndSize.key, WebsiteDataType::DiskCache, originAndSize.value }); |
| |
| RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), entries = WTFMove(entries)] () mutable { |
| completionHandler(entries); |
| }); |
| |
| return; |
| } |
| |
| auto url = traversalEntry->entry.response().url(); |
| auto result = originsAndSizes.add({url.protocol().toString(), url.host().toString(), url.port()}, 0); |
| |
| if (fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes)) |
| result.iterator->value += traversalEntry->entry.sourceStorageRecord().header.size() + traversalEntry->recordInfo.bodySize; |
| }); |
| } |
| |
| void NetworkProcess::fetchWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, OptionSet<WebsiteDataFetchOption> fetchOptions, CompletionHandler<void(WebsiteData&&)>&& completionHandler) |
| { |
| struct CallbackAggregator final : public ThreadSafeRefCounted<CallbackAggregator> { |
| explicit CallbackAggregator(CompletionHandler<void(WebsiteData&&)>&& completionHandler) |
| : m_completionHandler(WTFMove(completionHandler)) |
| { |
| } |
| |
| ~CallbackAggregator() |
| { |
| RunLoop::main().dispatch([completionHandler = WTFMove(m_completionHandler), websiteData = WTFMove(m_websiteData)] () mutable { |
| completionHandler(WTFMove(websiteData)); |
| }); |
| } |
| |
| CompletionHandler<void(WebsiteData&&)> m_completionHandler; |
| WebsiteData m_websiteData; |
| }; |
| |
| auto callbackAggregator = adoptRef(*new CallbackAggregator(WTFMove(completionHandler))); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::Cookies)) { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->getHostnamesWithCookies(callbackAggregator->m_websiteData.hostNamesWithCookies); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::Credentials)) { |
| if (storageSession(sessionID)) { |
| auto securityOrigins = storageSession(sessionID)->credentialStorage().originsWithCredentials(); |
| for (auto& securityOrigin : securityOrigins) |
| callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::Credentials, 0 }); |
| } |
| auto securityOrigins = WebCore::CredentialStorage::originsWithSessionCredentials(); |
| for (auto& securityOrigin : securityOrigins) |
| callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::Credentials, 0 }); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) { |
| CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [callbackAggregator](auto entries) mutable { |
| callbackAggregator->m_websiteData.entries.appendVector(entries); |
| }); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManagerSet->contains(sessionID)) { |
| m_storageManagerSet->getSessionStorageOrigins(sessionID, [callbackAggregator](auto&& origins) { |
| while (!origins.isEmpty()) |
| callbackAggregator->m_websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::SessionStorage, 0 }); |
| }); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManagerSet->contains(sessionID)) { |
| m_storageManagerSet->getLocalStorageOrigins(sessionID, [callbackAggregator](auto&& origins) { |
| while (!origins.isEmpty()) |
| callbackAggregator->m_websiteData.entries.append(WebsiteData::Entry { origins.takeAny(), WebsiteDataType::LocalStorage, 0 }); |
| }); |
| } |
| |
| #if PLATFORM(COCOA) || USE(SOUP) |
| if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) |
| callbackAggregator->m_websiteData.hostNamesWithHSTSCache = hostNamesWithHSTSCache(sessionID); |
| #endif |
| |
| auto path = m_idbDatabasePaths.get(sessionID); |
| if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) { |
| webIDBServer(sessionID).getOrigins([callbackAggregator](auto&& origins) { |
| while (!origins.isEmpty()) |
| callbackAggregator->m_websiteData.entries.append({ origins.takeAny(), WebsiteDataType::IndexedDBDatabases, 0 }); |
| }); |
| } |
| |
| #if ENABLE(SERVICE_WORKER) |
| path = m_serviceWorkerInfo.get(sessionID).databasePath; |
| if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) { |
| swServerForSession(sessionID).getOriginsWithRegistrations([callbackAggregator](const HashSet<SecurityOriginData>& securityOrigins) mutable { |
| for (auto& origin : securityOrigins) |
| callbackAggregator->m_websiteData.entries.append({ origin, WebsiteDataType::ServiceWorkerRegistrations, 0 }); |
| }); |
| } |
| #endif |
| if (websiteDataTypes.contains(WebsiteDataType::DiskCache)) { |
| forEachNetworkSession([sessionID, fetchOptions, &callbackAggregator](auto& session) { |
| fetchDiskCacheEntries(session.cache(), sessionID, fetchOptions, [callbackAggregator](auto entries) mutable { |
| callbackAggregator->m_websiteData.entries.appendVector(entries); |
| }); |
| }); |
| } |
| |
| #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE) |
| if (websiteDataTypes.contains(WebsiteDataType::AlternativeServices)) { |
| if (auto* session = networkSession(sessionID)) { |
| for (auto& origin : session->hostNamesWithAlternativeServices()) |
| callbackAggregator->m_websiteData.entries.append({ origin, WebsiteDataType::AlternativeServices, 0 }); |
| } |
| } |
| #endif |
| |
| #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| if (websiteDataTypes.contains(WebsiteDataType::ResourceLoadStatistics)) { |
| if (auto* session = networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = session->resourceLoadStatistics()) { |
| resourceLoadStatistics->registrableDomains([callbackAggregator](auto&& domains) mutable { |
| while (!domains.isEmpty()) |
| callbackAggregator->m_websiteData.registrableDomainsWithResourceLoadStatistics.add(domains.takeLast()); |
| }); |
| } |
| } |
| } |
| #endif |
| } |
| |
| void NetworkProcess::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, WallTime modifiedSince, CompletionHandler<void()>&& completionHandler) |
| { |
| #if PLATFORM(COCOA) || USE(SOUP) |
| if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) |
| clearHSTSCache(sessionID, modifiedSince); |
| #endif |
| |
| if (websiteDataTypes.contains(WebsiteDataType::Cookies)) { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->deleteAllCookiesModifiedSince(modifiedSince); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::Credentials)) { |
| if (auto* session = storageSession(sessionID)) |
| session->credentialStorage().clearCredentials(); |
| WebCore::CredentialStorage::clearSessionCredentials(); |
| } |
| |
| auto clearTasksHandler = WTF::CallbackAggregator::create(WTFMove(completionHandler)); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) |
| CacheStorage::Engine::clearAllCaches(*this, sessionID, [clearTasksHandler] { }); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManagerSet->contains(sessionID)) |
| m_storageManagerSet->deleteSessionStorage(sessionID, [clearTasksHandler] { }); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManagerSet->contains(sessionID)) |
| m_storageManagerSet->deleteLocalStorageModifiedSince(sessionID, modifiedSince, [clearTasksHandler] { }); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases) && !sessionID.isEphemeral()) |
| webIDBServer(sessionID).closeAndDeleteDatabasesModifiedSince(modifiedSince, [clearTasksHandler] { }); |
| |
| #if ENABLE(SERVICE_WORKER) |
| bool clearServiceWorkers = websiteDataTypes.contains(WebsiteDataType::DOMCache) || websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations); |
| if (clearServiceWorkers && !sessionID.isEphemeral()) |
| swServerForSession(sessionID).clearAll([clearTasksHandler] { }); |
| #endif |
| |
| #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| if (websiteDataTypes.contains(WebsiteDataType::ResourceLoadStatistics)) { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) { |
| auto deletedTypesRaw = websiteDataTypes.toRaw(); |
| auto monitoredTypesRaw = WebResourceLoadStatisticsStore::monitoredDataTypes().toRaw(); |
| |
| // If we are deleting all of the data types that the resource load statistics store monitors |
| // we do not need to re-grandfather old data. |
| auto shouldGrandfather = ((monitoredTypesRaw & deletedTypesRaw) == monitoredTypesRaw) ? ShouldGrandfatherStatistics::No : ShouldGrandfatherStatistics::Yes; |
| |
| resourceLoadStatistics->scheduleClearInMemoryAndPersistent(modifiedSince, shouldGrandfather, [clearTasksHandler] { }); |
| } |
| } |
| } |
| #endif |
| |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->removeNetworkWebsiteData(modifiedSince, std::nullopt, [clearTasksHandler] { }); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DiskCache) && !sessionID.isEphemeral()) |
| clearDiskCache(modifiedSince, [clearTasksHandler] { }); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::PrivateClickMeasurements)) { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->clearPrivateClickMeasurement([clearTasksHandler] { }); |
| } |
| |
| #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE) |
| if (websiteDataTypes.contains(WebsiteDataType::AlternativeServices)) { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->clearAlternativeServices(modifiedSince); |
| } |
| #endif |
| } |
| |
| static void clearDiskCacheEntries(NetworkCache::Cache* cache, const Vector<SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler) |
| { |
| if (!cache) { |
| RunLoop::main().dispatch(WTFMove(completionHandler)); |
| return; |
| } |
| |
| HashSet<RefPtr<SecurityOrigin>> originsToDelete; |
| for (auto& origin : origins) |
| originsToDelete.add(origin.securityOrigin()); |
| |
| Vector<NetworkCache::Key> cacheKeysToDelete; |
| cache->traverse([cache, completionHandler = WTFMove(completionHandler), originsToDelete = WTFMove(originsToDelete), cacheKeysToDelete = WTFMove(cacheKeysToDelete)](auto* traversalEntry) mutable { |
| if (traversalEntry) { |
| if (originsToDelete.contains(SecurityOrigin::create(traversalEntry->entry.response().url()))) |
| cacheKeysToDelete.append(traversalEntry->entry.key()); |
| return; |
| } |
| |
| cache->remove(cacheKeysToDelete, WTFMove(completionHandler)); |
| return; |
| }); |
| } |
| |
| void NetworkProcess::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, const Vector<SecurityOriginData>& originDatas, const Vector<String>& cookieHostNames, const Vector<String>& HSTSCacheHostNames, const Vector<RegistrableDomain>& registrableDomains, CompletionHandler<void()>&& completionHandler) |
| { |
| if (websiteDataTypes.contains(WebsiteDataType::Cookies)) { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->deleteCookiesForHostnames(cookieHostNames); |
| } |
| |
| #if PLATFORM(COCOA) || USE(SOUP) |
| if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) |
| deleteHSTSCacheForHostNames(sessionID, HSTSCacheHostNames); |
| #endif |
| |
| #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE) |
| if (websiteDataTypes.contains(WebsiteDataType::AlternativeServices)) { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| Vector<String> hosts; |
| hosts.reserveInitialCapacity(originDatas.size()); |
| for (auto& origin : originDatas) |
| hosts.uncheckedAppend(origin.host); |
| networkSession->deleteAlternativeServicesForHostNames(hosts); |
| } |
| } |
| #endif |
| |
| auto clearTasksHandler = WTF::CallbackAggregator::create(WTFMove(completionHandler)); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::PrivateClickMeasurements)) { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| for (auto& originData : originDatas) |
| networkSession->clearPrivateClickMeasurementForRegistrableDomain(RegistrableDomain::uncheckedCreateFromHost(originData.host), [clearTasksHandler] { }); |
| } |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) { |
| for (auto& originData : originDatas) |
| CacheStorage::Engine::clearCachesForOrigin(*this, sessionID, SecurityOriginData { originData }, [clearTasksHandler] { }); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::SessionStorage) && m_storageManagerSet->contains(sessionID)) |
| m_storageManagerSet->deleteSessionStorageForOrigins(sessionID, originDatas, [clearTasksHandler] { }); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::LocalStorage) && m_storageManagerSet->contains(sessionID)) |
| m_storageManagerSet->deleteLocalStorageForOrigins(sessionID, originDatas, [clearTasksHandler] { }); |
| |
| if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases) && !sessionID.isEphemeral()) |
| webIDBServer(sessionID).closeAndDeleteDatabasesForOrigins(originDatas, [clearTasksHandler] { }); |
| |
| #if ENABLE(SERVICE_WORKER) |
| bool clearServiceWorkers = websiteDataTypes.contains(WebsiteDataType::DOMCache) || websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations); |
| if (clearServiceWorkers && !sessionID.isEphemeral()) { |
| auto& server = swServerForSession(sessionID); |
| for (auto& originData : originDatas) |
| server.clear(originData, [clearTasksHandler] { }); |
| } |
| #endif |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DiskCache) && !sessionID.isEphemeral()) { |
| forEachNetworkSession([originDatas, &clearTasksHandler](auto& session) { |
| clearDiskCacheEntries(session.cache(), originDatas, [clearTasksHandler] { }); |
| }); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::Credentials)) { |
| if (auto* session = storageSession(sessionID)) { |
| for (auto& originData : originDatas) |
| session->credentialStorage().removeCredentialsWithOrigin(originData); |
| } |
| WebCore::CredentialStorage::removeSessionCredentialsWithOrigins(originDatas); |
| } |
| |
| #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| if (websiteDataTypes.contains(WebsiteDataType::ResourceLoadStatistics)) { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| for (auto& domain : registrableDomains) { |
| if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics()) |
| resourceLoadStatistics->removeDataForDomain(domain, [clearTasksHandler] { }); |
| } |
| } |
| } |
| #endif |
| |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| HashSet<WebCore::RegistrableDomain> domainsToDeleteNetworkDataFor; |
| for (auto& originData : originDatas) |
| domainsToDeleteNetworkDataFor.add(WebCore::RegistrableDomain::uncheckedCreateFromHost(originData.host)); |
| for (auto& cookieHostName : cookieHostNames) |
| domainsToDeleteNetworkDataFor.add(WebCore::RegistrableDomain::uncheckedCreateFromHost(cookieHostName)); |
| for (auto& cacheHostName : HSTSCacheHostNames) |
| domainsToDeleteNetworkDataFor.add(WebCore::RegistrableDomain::uncheckedCreateFromHost(cacheHostName)); |
| for (auto& domain : registrableDomains) |
| domainsToDeleteNetworkDataFor.add(domain); |
| |
| networkSession->removeNetworkWebsiteData(std::nullopt, WTFMove(domainsToDeleteNetworkDataFor), [clearTasksHandler] { }); |
| } |
| } |
| |
| #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| static Vector<String> filterForRegistrableDomains(const Vector<RegistrableDomain>& registrableDomains, const HashSet<String>& foundValues) |
| { |
| Vector<String> result; |
| for (const auto& value : foundValues) { |
| if (registrableDomains.contains(RegistrableDomain::uncheckedCreateFromHost(value))) |
| result.append(value); |
| } |
| |
| return result; |
| } |
| |
| static Vector<WebsiteData::Entry> filterForRegistrableDomains(const Vector<RegistrableDomain>& registrableDomains, const Vector<WebsiteData::Entry>& foundValues) |
| { |
| Vector<WebsiteData::Entry> result; |
| for (const auto& value : foundValues) { |
| if (registrableDomains.contains(RegistrableDomain::uncheckedCreateFromHost(value.origin.host))) |
| result.append(value); |
| } |
| |
| return result; |
| } |
| |
| static Vector<WebCore::SecurityOriginData> filterForRegistrableDomains(const HashSet<WebCore::SecurityOriginData>& origins, const Vector<RegistrableDomain>& domainsToDelete, HashSet<RegistrableDomain>& domainsDeleted) |
| { |
| Vector<SecurityOriginData> originsDeleted; |
| for (const auto& origin : origins) { |
| auto domain = RegistrableDomain::uncheckedCreateFromHost(origin.host); |
| if (!domainsToDelete.contains(domain)) |
| continue; |
| originsDeleted.append(origin); |
| domainsDeleted.add(domain); |
| } |
| |
| return originsDeleted; |
| } |
| |
| void NetworkProcess::deleteAndRestrictWebsiteDataForRegistrableDomains(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, RegistrableDomainsToDeleteOrRestrictWebsiteDataFor&& domains, bool shouldNotifyPage, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler) |
| { |
| OptionSet<WebsiteDataFetchOption> fetchOptions = WebsiteDataFetchOption::DoNotCreateProcesses; |
| |
| struct CallbackAggregator final : public ThreadSafeRefCounted<CallbackAggregator> { |
| explicit CallbackAggregator(CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler) |
| : m_completionHandler(WTFMove(completionHandler)) |
| { |
| } |
| |
| ~CallbackAggregator() |
| { |
| RunLoop::main().dispatch([completionHandler = WTFMove(m_completionHandler), domains = WTFMove(m_domains)] () mutable { |
| completionHandler(domains); |
| }); |
| } |
| |
| CompletionHandler<void(const HashSet<RegistrableDomain>&)> m_completionHandler; |
| HashSet<RegistrableDomain> m_domains; |
| }; |
| |
| auto callbackAggregator = adoptRef(*new CallbackAggregator([this, completionHandler = WTFMove(completionHandler), shouldNotifyPage] (const HashSet<RegistrableDomain>& domainsWithData) mutable { |
| if (shouldNotifyPage) |
| parentProcessConnection()->send(Messages::NetworkProcessProxy::NotifyWebsiteDataDeletionForRegistrableDomainsFinished(), 0); |
| |
| RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), domainsWithData = crossThreadCopy(domainsWithData)] () mutable { |
| completionHandler(domainsWithData); |
| }); |
| })); |
| |
| HashSet<String> hostNamesWithCookies; |
| HashSet<String> hostNamesWithHSTSCache; |
| Vector<String> hostnamesWithCookiesToDelete; |
| auto domainsToDeleteAllNonCookieWebsiteDataFor = domains.domainsToDeleteAllNonCookieWebsiteDataFor; |
| if (websiteDataTypes.contains(WebsiteDataType::Cookies)) { |
| if (auto* networkStorageSession = storageSession(sessionID)) { |
| networkStorageSession->getHostnamesWithCookies(hostNamesWithCookies); |
| |
| hostnamesWithCookiesToDelete = filterForRegistrableDomains(domains.domainsToDeleteAllCookiesFor, hostNamesWithCookies); |
| networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, WebCore::IncludeHttpOnlyCookies::Yes); |
| |
| for (const auto& host : hostnamesWithCookiesToDelete) |
| callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(host)); |
| |
| hostnamesWithCookiesToDelete = filterForRegistrableDomains(domains.domainsToDeleteAllButHttpOnlyCookiesFor, hostNamesWithCookies); |
| networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, WebCore::IncludeHttpOnlyCookies::No); |
| |
| for (const auto& host : hostnamesWithCookiesToDelete) |
| callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(host)); |
| } |
| } |
| |
| Vector<String> hostnamesWithHSTSToDelete; |
| #if PLATFORM(COCOA) || USE(SOUP) |
| if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) { |
| hostNamesWithHSTSCache = this->hostNamesWithHSTSCache(sessionID); |
| hostnamesWithHSTSToDelete = filterForRegistrableDomains(domainsToDeleteAllNonCookieWebsiteDataFor, hostNamesWithHSTSCache); |
| |
| for (const auto& host : hostnamesWithHSTSToDelete) |
| callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(host)); |
| |
| deleteHSTSCacheForHostNames(sessionID, hostnamesWithHSTSToDelete); |
| } |
| #endif |
| |
| #if HAVE(CFNETWORK_ALTERNATIVE_SERVICE) |
| if (websiteDataTypes.contains(WebsiteDataType::AlternativeServices)) { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| Vector<String> registrableDomainsToDelete; |
| registrableDomainsToDelete.reserveInitialCapacity(domainsToDeleteAllNonCookieWebsiteDataFor.size()); |
| for (auto& domain : domainsToDeleteAllNonCookieWebsiteDataFor) |
| registrableDomainsToDelete.uncheckedAppend(domain.string()); |
| networkSession->deleteAlternativeServicesForHostNames(registrableDomainsToDelete); |
| } |
| } |
| #endif |
| |
| if (websiteDataTypes.contains(WebsiteDataType::Credentials)) { |
| if (auto* session = storageSession(sessionID)) { |
| auto origins = session->credentialStorage().originsWithCredentials(); |
| auto originsToDelete = filterForRegistrableDomains(origins, domainsToDeleteAllNonCookieWebsiteDataFor, callbackAggregator->m_domains); |
| for (auto& origin : originsToDelete) |
| session->credentialStorage().removeCredentialsWithOrigin(origin); |
| } |
| |
| auto origins = WebCore::CredentialStorage::originsWithSessionCredentials(); |
| auto originsToDelete = filterForRegistrableDomains(origins, domainsToDeleteAllNonCookieWebsiteDataFor, callbackAggregator->m_domains); |
| WebCore::CredentialStorage::removeSessionCredentialsWithOrigins(originsToDelete); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) { |
| CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [this, domainsToDeleteAllNonCookieWebsiteDataFor, sessionID, callbackAggregator](auto entries) mutable { |
| |
| auto entriesToDelete = filterForRegistrableDomains(domainsToDeleteAllNonCookieWebsiteDataFor, entries); |
| |
| for (const auto& entry : entriesToDelete) |
| callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host)); |
| |
| for (auto& entry : entriesToDelete) |
| CacheStorage::Engine::clearCachesForOrigin(*this, sessionID, SecurityOriginData { entry.origin }, [callbackAggregator] { }); |
| }); |
| } |
| |
| if (m_storageManagerSet->contains(sessionID)) { |
| if (websiteDataTypes.contains(WebsiteDataType::SessionStorage)) { |
| m_storageManagerSet->getSessionStorageOrigins(sessionID, [protectedThis = Ref { *this }, this, sessionID, callbackAggregator, domainsToDeleteAllNonCookieWebsiteDataFor](auto&& origins) { |
| if (!m_storageManagerSet->contains(sessionID)) |
| return; |
| |
| auto originsToDelete = filterForRegistrableDomains(origins, domainsToDeleteAllNonCookieWebsiteDataFor, callbackAggregator->m_domains); |
| m_storageManagerSet->deleteSessionStorageForOrigins(sessionID, originsToDelete, [callbackAggregator] { }); |
| }); |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::LocalStorage)) { |
| m_storageManagerSet->getLocalStorageOrigins(sessionID, [protectedThis = Ref { *this }, this, sessionID, callbackAggregator, domainsToDeleteAllNonCookieWebsiteDataFor](auto&& origins) { |
| if (!m_storageManagerSet->contains(sessionID)) |
| return; |
| |
| auto originsToDelete = filterForRegistrableDomains(origins, domainsToDeleteAllNonCookieWebsiteDataFor, callbackAggregator->m_domains); |
| m_storageManagerSet->deleteLocalStorageForOrigins(sessionID, originsToDelete, [callbackAggregator] { }); |
| }); |
| } |
| } |
| |
| auto path = m_idbDatabasePaths.get(sessionID); |
| if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) { |
| webIDBServer(sessionID).getOrigins([this, protectedThis = Ref { *this }, sessionID, callbackAggregator, domainsToDeleteAllNonCookieWebsiteDataFor](auto&& origins) { |
| if (!m_webIDBServers.contains(sessionID)) |
| return; |
| |
| auto originsToDelete = filterForRegistrableDomains(origins, domainsToDeleteAllNonCookieWebsiteDataFor, callbackAggregator->m_domains); |
| webIDBServer(sessionID).closeAndDeleteDatabasesForOrigins(originsToDelete, [callbackAggregator] { }); |
| }); |
| } |
| |
| #if ENABLE(SERVICE_WORKER) |
| path = m_serviceWorkerInfo.get(sessionID).databasePath; |
| bool clearServiceWorkers = websiteDataTypes.contains(WebsiteDataType::DOMCache) || websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations); |
| if (clearServiceWorkers && !path.isEmpty()) { |
| swServerForSession(sessionID).getOriginsWithRegistrations([this, sessionID, domainsToDeleteAllNonCookieWebsiteDataFor, callbackAggregator](const HashSet<SecurityOriginData>& securityOrigins) mutable { |
| for (auto& securityOrigin : securityOrigins) { |
| if (!domainsToDeleteAllNonCookieWebsiteDataFor.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host))) |
| continue; |
| callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)); |
| swServerForSession(sessionID).clear(securityOrigin, [callbackAggregator] { }); |
| } |
| }); |
| } |
| #endif |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DiskCache)) { |
| forEachNetworkSession([sessionID, fetchOptions, &domainsToDeleteAllNonCookieWebsiteDataFor, &callbackAggregator](auto& session) { |
| /* hack: gcc 8.4 will segfault if the WeakPtr is instantiated within the lambda captures */ |
| auto ws = WeakPtr { session }; |
| fetchDiskCacheEntries(session.cache(), sessionID, fetchOptions, [domainsToDeleteAllNonCookieWebsiteDataFor, callbackAggregator, session = WTFMove(ws)](auto entries) mutable { |
| if (!session) |
| return; |
| |
| Vector<SecurityOriginData> entriesToDelete; |
| for (auto& entry : entries) { |
| if (!domainsToDeleteAllNonCookieWebsiteDataFor.contains(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host))) |
| continue; |
| entriesToDelete.append(entry.origin); |
| callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host)); |
| } |
| clearDiskCacheEntries(session->cache(), entriesToDelete, [callbackAggregator] { }); |
| }); |
| }); |
| } |
| |
| auto dataTypesForUIProcess = WebsiteData::filter(websiteDataTypes, WebsiteDataProcessType::UI); |
| if (!dataTypesForUIProcess.isEmpty() && !domainsToDeleteAllNonCookieWebsiteDataFor.isEmpty()) { |
| CompletionHandler<void(const HashSet<RegistrableDomain>&)> completionHandler = [callbackAggregator] (const HashSet<RegistrableDomain>& domains) { |
| for (auto& domain : domains) |
| callbackAggregator->m_domains.add(domain); |
| }; |
| parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::DeleteWebsiteDataInUIProcessForRegistrableDomains(sessionID, dataTypesForUIProcess, fetchOptions, domainsToDeleteAllNonCookieWebsiteDataFor), WTFMove(completionHandler)); |
| } |
| } |
| |
| void NetworkProcess::deleteCookiesForTesting(PAL::SessionID sessionID, RegistrableDomain domain, bool includeHttpOnlyCookies, CompletionHandler<void()>&& completionHandler) |
| { |
| OptionSet<WebsiteDataType> cookieType = WebsiteDataType::Cookies; |
| RegistrableDomainsToDeleteOrRestrictWebsiteDataFor toDeleteFor; |
| if (includeHttpOnlyCookies) |
| toDeleteFor.domainsToDeleteAllCookiesFor.append(domain); |
| else |
| toDeleteFor.domainsToDeleteAllButHttpOnlyCookiesFor.append(domain); |
| |
| deleteAndRestrictWebsiteDataForRegistrableDomains(sessionID, cookieType, WTFMove(toDeleteFor), true, [completionHandler = WTFMove(completionHandler)] (const HashSet<RegistrableDomain>& domainsDeletedFor) mutable { |
| UNUSED_PARAM(domainsDeletedFor); |
| completionHandler(); |
| }); |
| } |
| |
| void NetworkProcess::registrableDomainsWithWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, bool shouldNotifyPage, CompletionHandler<void(HashSet<RegistrableDomain>&&)>&& completionHandler) |
| { |
| OptionSet<WebsiteDataFetchOption> fetchOptions = WebsiteDataFetchOption::DoNotCreateProcesses; |
| |
| struct CallbackAggregator final : public ThreadSafeRefCounted<CallbackAggregator> { |
| explicit CallbackAggregator(CompletionHandler<void(HashSet<RegistrableDomain>&&)>&& completionHandler) |
| : m_completionHandler(WTFMove(completionHandler)) |
| { |
| } |
| |
| ~CallbackAggregator() |
| { |
| RunLoop::main().dispatch([completionHandler = WTFMove(m_completionHandler), websiteData = WTFMove(m_websiteData)] () mutable { |
| HashSet<RegistrableDomain> domains; |
| for (const auto& hostnameWithCookies : websiteData.hostNamesWithCookies) |
| domains.add(RegistrableDomain::uncheckedCreateFromHost(hostnameWithCookies)); |
| |
| for (const auto& hostnameWithHSTS : websiteData.hostNamesWithHSTSCache) |
| domains.add(RegistrableDomain::uncheckedCreateFromHost(hostnameWithHSTS)); |
| |
| for (const auto& entry : websiteData.entries) |
| domains.add(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host)); |
| |
| completionHandler(WTFMove(domains)); |
| }); |
| } |
| |
| CompletionHandler<void(HashSet<RegistrableDomain>&&)> m_completionHandler; |
| WebsiteData m_websiteData; |
| }; |
| |
| auto callbackAggregator = adoptRef(*new CallbackAggregator([this, completionHandler = WTFMove(completionHandler), shouldNotifyPage] (HashSet<RegistrableDomain>&& domainsWithData) mutable { |
| if (shouldNotifyPage) |
| parentProcessConnection()->send(Messages::NetworkProcessProxy::NotifyWebsiteDataScanForRegistrableDomainsFinished(), 0); |
| |
| RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), domainsWithData = crossThreadCopy(domainsWithData)] () mutable { |
| completionHandler(WTFMove(domainsWithData)); |
| }); |
| })); |
| |
| auto& websiteData = callbackAggregator->m_websiteData; |
| |
| if (websiteDataTypes.contains(WebsiteDataType::Cookies)) { |
| if (auto* networkStorageSession = storageSession(sessionID)) |
| networkStorageSession->getHostnamesWithCookies(websiteData.hostNamesWithCookies); |
| } |
| |
| #if PLATFORM(COCOA) || USE(SOUP) |
| if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) |
| websiteData.hostNamesWithHSTSCache = hostNamesWithHSTSCache(sessionID); |
| #endif |
| |
| if (websiteDataTypes.contains(WebsiteDataType::Credentials)) { |
| if (auto* networkStorageSession = storageSession(sessionID)) { |
| auto securityOrigins = networkStorageSession->credentialStorage().originsWithCredentials(); |
| for (auto& securityOrigin : securityOrigins) |
| callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::Credentials, 0 }); |
| } |
| } |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) { |
| CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [callbackAggregator](auto entries) mutable { |
| callbackAggregator->m_websiteData.entries.appendVector(entries); |
| }); |
| } |
| |
| auto path = m_idbDatabasePaths.get(sessionID); |
| if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) { |
| webIDBServer(sessionID).getOrigins([callbackAggregator](auto&& origins) { |
| while (!origins.isEmpty()) |
| callbackAggregator->m_websiteData.entries.append({ origins.takeAny(), WebsiteDataType::IndexedDBDatabases, 0 }); |
| }); |
| } |
| |
| #if ENABLE(SERVICE_WORKER) |
| path = m_serviceWorkerInfo.get(sessionID).databasePath; |
| if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) { |
| swServerForSession(sessionID).getOriginsWithRegistrations([callbackAggregator](const HashSet<SecurityOriginData>& securityOrigins) mutable { |
| for (auto& securityOrigin : securityOrigins) |
| callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::ServiceWorkerRegistrations, 0 }); |
| }); |
| } |
| #endif |
| |
| if (websiteDataTypes.contains(WebsiteDataType::DiskCache)) { |
| forEachNetworkSession([sessionID, fetchOptions, &callbackAggregator](auto& session) { |
| fetchDiskCacheEntries(session.cache(), sessionID, fetchOptions, [callbackAggregator](auto entries) mutable { |
| callbackAggregator->m_websiteData.entries.appendVector(entries); |
| }); |
| }); |
| } |
| } |
| #endif // ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| |
| CacheStorage::Engine* NetworkProcess::findCacheEngine(PAL::SessionID sessionID) |
| { |
| return m_cacheEngines.get(sessionID); |
| } |
| |
| CacheStorage::Engine& NetworkProcess::ensureCacheEngine(PAL::SessionID sessionID, Function<Ref<CacheStorage::Engine>()>&& functor) |
| { |
| return m_cacheEngines.ensure(sessionID, WTFMove(functor)).iterator->value; |
| } |
| |
| void NetworkProcess::removeCacheEngine(PAL::SessionID sessionID) |
| { |
| m_cacheEngines.remove(sessionID); |
| } |
| |
| void NetworkProcess::downloadRequest(PAL::SessionID sessionID, DownloadID downloadID, const ResourceRequest& request, std::optional<NavigatingToAppBoundDomain> isNavigatingToAppBoundDomain, const String& suggestedFilename) |
| { |
| downloadManager().startDownload(sessionID, downloadID, request, isNavigatingToAppBoundDomain, suggestedFilename); |
| } |
| |
| void NetworkProcess::resumeDownload(PAL::SessionID sessionID, DownloadID downloadID, const IPC::DataReference& resumeData, const String& path, WebKit::SandboxExtension::Handle&& sandboxExtensionHandle, CallDownloadDidStart callDownloadDidStart) |
| { |
| downloadManager().resumeDownload(sessionID, downloadID, resumeData, path, WTFMove(sandboxExtensionHandle), callDownloadDidStart); |
| } |
| |
| void NetworkProcess::cancelDownload(DownloadID downloadID, CompletionHandler<void(const IPC::DataReference&)>&& completionHandler) |
| { |
| downloadManager().cancelDownload(downloadID, WTFMove(completionHandler)); |
| } |
| |
| #if PLATFORM(COCOA) |
| void NetworkProcess::publishDownloadProgress(DownloadID downloadID, const URL& url, SandboxExtension::Handle&& sandboxExtensionHandle) |
| { |
| downloadManager().publishDownloadProgress(downloadID, url, WTFMove(sandboxExtensionHandle)); |
| } |
| #endif |
| |
| void NetworkProcess::continueWillSendRequest(DownloadID downloadID, WebCore::ResourceRequest&& request) |
| { |
| downloadManager().continueWillSendRequest(downloadID, WTFMove(request)); |
| } |
| |
| void NetworkProcess::findPendingDownloadLocation(NetworkDataTask& networkDataTask, ResponseCompletionHandler&& completionHandler, const ResourceResponse& response) |
| { |
| uint64_t destinationID = networkDataTask.pendingDownloadID().toUInt64(); |
| |
| String suggestedFilename = networkDataTask.suggestedFilename(); |
| |
| downloadProxyConnection()->sendWithAsyncReply(Messages::DownloadProxy::DecideDestinationWithSuggestedFilename(response, suggestedFilename), [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler), networkDataTask = Ref { networkDataTask }] (String&& destination, SandboxExtension::Handle&& sandboxExtensionHandle, AllowOverwrite allowOverwrite) mutable { |
| auto downloadID = networkDataTask->pendingDownloadID(); |
| if (destination.isEmpty()) |
| return completionHandler(PolicyAction::Ignore); |
| networkDataTask->setPendingDownloadLocation(destination, WTFMove(sandboxExtensionHandle), allowOverwrite == AllowOverwrite::Yes); |
| completionHandler(PolicyAction::Download); |
| if (networkDataTask->state() == NetworkDataTask::State::Canceling || networkDataTask->state() == NetworkDataTask::State::Completed) |
| return; |
| |
| if (downloadManager().download(downloadID)) { |
| // The completion handler already called dataTaskBecameDownloadTask(). |
| return; |
| } |
| |
| downloadManager().downloadDestinationDecided(downloadID, WTFMove(networkDataTask)); |
| }, destinationID); |
| } |
| |
| void NetworkProcess::setCacheModelSynchronouslyForTesting(CacheModel cacheModel, CompletionHandler<void()>&& completionHandler) |
| { |
| setCacheModel(cacheModel); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setCacheModel(CacheModel cacheModel) |
| { |
| if (m_hasSetCacheModel && (cacheModel == m_cacheModel)) |
| return; |
| |
| m_hasSetCacheModel = true; |
| m_cacheModel = cacheModel; |
| |
| forEachNetworkSession([](auto& session) { |
| if (auto* cache = session.cache()) |
| cache->updateCapacity(); |
| }); |
| } |
| |
| void NetworkProcess::setAllowsAnySSLCertificateForWebSocket(bool allows, CompletionHandler<void()>&& completionHandler) |
| { |
| // FIXME: Stop using this when HAVE(NSURLSESSION_WEBSOCKET) is true. |
| DeprecatedGlobalSettings::setAllowsAnySSLCertificate(allows); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::allowTLSCertificateChainForLocalPCMTesting(PAL::SessionID sessionID, const WebCore::CertificateInfo& certificateInfo) |
| { |
| if (auto* networkSession = m_networkSessions.get(sessionID)) |
| networkSession->allowTLSCertificateChainForLocalPCMTesting(certificateInfo); |
| } |
| |
| void NetworkProcess::logDiagnosticMessage(WebPageProxyIdentifier webPageProxyID, const String& message, const String& description, ShouldSample shouldSample) |
| { |
| if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample)) |
| return; |
| |
| parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessage(webPageProxyID, message, description, ShouldSample::No), 0); |
| } |
| |
| void NetworkProcess::logDiagnosticMessageWithResult(WebPageProxyIdentifier webPageProxyID, const String& message, const String& description, DiagnosticLoggingResultType result, ShouldSample shouldSample) |
| { |
| if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample)) |
| return; |
| |
| parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessageWithResult(webPageProxyID, message, description, result, ShouldSample::No), 0); |
| } |
| |
| void NetworkProcess::logDiagnosticMessageWithValue(WebPageProxyIdentifier webPageProxyID, const String& message, const String& description, double value, unsigned significantFigures, ShouldSample shouldSample) |
| { |
| if (!DiagnosticLoggingClient::shouldLogAfterSampling(shouldSample)) |
| return; |
| |
| parentProcessConnection()->send(Messages::NetworkProcessProxy::LogDiagnosticMessageWithValue(webPageProxyID, message, description, value, significantFigures, ShouldSample::No), 0); |
| } |
| |
| void NetworkProcess::terminate() |
| { |
| platformTerminate(); |
| AuxiliaryProcess::terminate(); |
| } |
| |
| void NetworkProcess::processWillSuspendImminentlyForTestingSync(CompletionHandler<void()>&& completionHandler) |
| { |
| prepareToSuspend(true, WTFMove(completionHandler)); |
| } |
| |
| void NetworkProcess::suspendIDBServers(bool isSuspensionImminent) |
| { |
| m_shouldSuspendIDBServers = true; |
| ++m_suspensionIdentifier; |
| |
| bool allSuspended = true; |
| auto condition = isSuspensionImminent ? WebIDBServer::SuspensionCondition::Always : WebIDBServer::SuspensionCondition::IfIdle; |
| for (auto& server : m_webIDBServers.values()) |
| allSuspended &= server->suspend(condition); |
| |
| if (allSuspended) |
| return; |
| |
| RunLoop::main().dispatchAfter(5_s, [this, weakThis = WeakPtr { *this }, suspensionIdentifier = m_suspensionIdentifier] { |
| if (!weakThis) |
| return; |
| |
| if (!m_shouldSuspendIDBServers || suspensionIdentifier != m_suspensionIdentifier) |
| return; |
| |
| for (auto& server : m_webIDBServers.values()) |
| server->suspend(WebIDBServer::SuspensionCondition::Always); |
| }); |
| } |
| |
| void NetworkProcess::prepareToSuspend(bool isSuspensionImminent, CompletionHandler<void()>&& completionHandler) |
| { |
| RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::prepareToSuspend(), isSuspensionImminent=%d", this, isSuspensionImminent); |
| |
| #if PLATFORM(IOS_FAMILY) |
| suspendIDBServers(isSuspensionImminent); |
| #endif |
| |
| lowMemoryHandler(Critical::Yes); |
| |
| RefPtr<CallbackAggregator> callbackAggregator = CallbackAggregator::create([this, completionHandler = WTFMove(completionHandler)]() mutable { |
| RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::prepareToSuspend() Process is ready to suspend", this); |
| UNUSED_VARIABLE(this); |
| completionHandler(); |
| }); |
| |
| #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| WebResourceLoadStatisticsStore::suspend([callbackAggregator] { }); |
| #endif |
| PCM::Store::prepareForProcessToSuspend([callbackAggregator] { }); |
| |
| forEachNetworkSession([&] (auto& networkSession) { |
| platformFlushCookies(networkSession.sessionID(), [callbackAggregator] { }); |
| }); |
| |
| for (auto& connection : m_webProcessConnections.values()) |
| connection->cleanupForSuspension([callbackAggregator] { }); |
| |
| #if ENABLE(SERVICE_WORKER) |
| for (auto& server : m_swServers.values()) { |
| ASSERT(m_swServers.get(server->sessionID()) == server.get()); |
| server->startSuspension([callbackAggregator] { }); |
| } |
| #endif |
| |
| m_storageManagerSet->suspend([callbackAggregator] { }); |
| } |
| |
| void NetworkProcess::applicationDidEnterBackground() |
| { |
| m_downloadManager.applicationDidEnterBackground(); |
| } |
| |
| void NetworkProcess::applicationWillEnterForeground() |
| { |
| m_downloadManager.applicationWillEnterForeground(); |
| } |
| |
| void NetworkProcess::processDidResume() |
| { |
| RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processDidResume()", this); |
| resume(); |
| } |
| |
| void NetworkProcess::resume() |
| { |
| for (auto& connection : m_webProcessConnections.values()) |
| connection->endSuspension(); |
| |
| #if ENABLE(INTELLIGENT_TRACKING_PREVENTION) |
| WebResourceLoadStatisticsStore::resume(); |
| #endif |
| PCM::Store::processDidResume(); |
| |
| #if ENABLE(SERVICE_WORKER) |
| for (auto& server : m_swServers.values()) |
| server->endSuspension(); |
| #endif |
| #if PLATFORM(IOS_FAMILY) |
| for (auto& server : m_webIDBServers.values()) |
| server->resume(); |
| m_shouldSuspendIDBServers = false; |
| #endif |
| |
| m_storageManagerSet->resume(); |
| } |
| |
| void NetworkProcess::prefetchDNS(const String& hostname) |
| { |
| WebCore::prefetchDNS(hostname); |
| } |
| |
| void NetworkProcess::cacheStorageRootPath(PAL::SessionID sessionID, CacheStorageRootPathCallback&& callback) |
| { |
| m_cacheStorageParametersCallbacks.ensure(sessionID, [&] { |
| parentProcessConnection()->send(Messages::NetworkProcessProxy::RetrieveCacheStorageParameters { sessionID }, 0); |
| return Vector<CacheStorageRootPathCallback> { }; |
| }).iterator->value.append(WTFMove(callback)); |
| } |
| |
| void NetworkProcess::setCacheStorageParameters(PAL::SessionID sessionID, String&& cacheStorageDirectory, SandboxExtension::Handle&& handle) |
| { |
| auto iterator = m_cacheStorageParametersCallbacks.find(sessionID); |
| if (iterator == m_cacheStorageParametersCallbacks.end()) |
| return; |
| |
| SandboxExtension::consumePermanently(handle); |
| auto callbacks = WTFMove(iterator->value); |
| m_cacheStorageParametersCallbacks.remove(iterator); |
| for (auto& callback : callbacks) |
| callback(String { cacheStorageDirectory }); |
| } |
| |
| void NetworkProcess::registerURLSchemeAsSecure(const String& scheme) const |
| { |
| LegacySchemeRegistry::registerURLSchemeAsSecure(scheme); |
| } |
| |
| void NetworkProcess::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme) const |
| { |
| LegacySchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(scheme); |
| } |
| |
| void NetworkProcess::registerURLSchemeAsLocal(const String& scheme) const |
| { |
| LegacySchemeRegistry::registerURLSchemeAsLocal(scheme); |
| } |
| |
| void NetworkProcess::registerURLSchemeAsNoAccess(const String& scheme) const |
| { |
| LegacySchemeRegistry::registerURLSchemeAsNoAccess(scheme); |
| } |
| |
| Ref<WebIDBServer> NetworkProcess::createWebIDBServer(PAL::SessionID sessionID) |
| { |
| String path; |
| if (!sessionID.isEphemeral()) { |
| ASSERT(m_idbDatabasePaths.contains(sessionID)); |
| path = m_idbDatabasePaths.get(sessionID); |
| } |
| |
| auto spaceRequester = [protectedThis = Ref { *this }, sessionID](const auto& origin, uint64_t spaceRequested) { |
| return protectedThis->storageQuotaManager(sessionID, origin)->requestSpaceOnBackgroundThread(spaceRequested); |
| }; |
| |
| auto result = WebIDBServer::create(sessionID, path, WTFMove(spaceRequester)); |
| if (m_shouldSuspendIDBServers) |
| result->suspend(WebIDBServer::SuspensionCondition::Always); |
| return result; |
| } |
| |
| WebIDBServer& NetworkProcess::webIDBServer(PAL::SessionID sessionID) |
| { |
| return *m_webIDBServers.ensure(sessionID, [this, sessionID] { |
| return this->createWebIDBServer(sessionID); |
| }).iterator->value; |
| } |
| |
| void NetworkProcess::addIndexedDatabaseSession(PAL::SessionID sessionID, String& indexedDatabaseDirectory, SandboxExtension::Handle& handle) |
| { |
| // ********* |
| // IMPORTANT: Do not change the directory structure for indexed databases on disk without first consulting a reviewer from Apple (<rdar://problem/17454712>) |
| // ********* |
| auto addResult = m_idbDatabasePaths.add(sessionID, indexedDatabaseDirectory); |
| if (addResult.isNewEntry) { |
| SandboxExtension::consumePermanently(handle); |
| setSessionStorageQuotaManagerIDBRootPath(sessionID, indexedDatabaseDirectory); |
| } |
| } |
| |
| void NetworkProcess::setSessionStorageQuotaManagerIDBRootPath(PAL::SessionID sessionID, const String& idbRootPath) |
| { |
| Locker locker { m_sessionStorageQuotaManagersLock }; |
| auto* sessionStorageQuotaManager = m_sessionStorageQuotaManagers.get(sessionID); |
| ASSERT(sessionStorageQuotaManager); |
| sessionStorageQuotaManager->setIDBRootPath(idbRootPath); |
| } |
| |
| void NetworkProcess::syncLocalStorage(CompletionHandler<void()>&& completionHandler) |
| { |
| m_storageManagerSet->waitUntilSyncingLocalStorageFinished(); |
| completionHandler(); |
| } |
| |
| void NetworkProcess::resetQuota(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| Locker locker { m_sessionStorageQuotaManagersLock }; |
| if (auto* sessionStorageQuotaManager = m_sessionStorageQuotaManagers.get(sessionID)) { |
| for (auto storageQuotaManager : sessionStorageQuotaManager->existingStorageQuotaManagers()) |
| storageQuotaManager->resetQuotaForTesting(); |
| } |
| completionHandler(); |
| } |
| |
| void NetworkProcess::clearStorage(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto manager = m_storageManagers.get(sessionID)) |
| manager->clearStorageForTesting(WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } |
| |
| void NetworkProcess::renameOriginInWebsiteData(PAL::SessionID sessionID, const URL& oldName, const URL& newName, OptionSet<WebsiteDataType> dataTypes, CompletionHandler<void()>&& completionHandler) |
| { |
| auto aggregator = CallbackAggregator::create(WTFMove(completionHandler)); |
| auto oldOrigin = WebCore::SecurityOriginData::fromURL(oldName); |
| auto newOrigin = WebCore::SecurityOriginData::fromURL(newName); |
| |
| if (oldOrigin.isEmpty() || newOrigin.isEmpty()) |
| return; |
| |
| if (dataTypes.contains(WebsiteDataType::LocalStorage)) { |
| if (m_storageManagerSet->contains(sessionID)) |
| m_storageManagerSet->renameOrigin(sessionID, oldName, newName, [aggregator] { }); |
| } |
| |
| if (dataTypes.contains(WebsiteDataType::IndexedDBDatabases)) { |
| auto path = m_idbDatabasePaths.get(sessionID); |
| if (!path.isEmpty()) |
| webIDBServer(sessionID).renameOrigin(oldOrigin, newOrigin, [aggregator] { }); |
| } |
| } |
| |
| #if ENABLE(SERVICE_WORKER) |
| void NetworkProcess::forEachSWServer(const Function<void(SWServer&)>& callback) |
| { |
| for (auto& server : m_swServers.values()) |
| callback(*server); |
| } |
| |
| SWServer& NetworkProcess::swServerForSession(PAL::SessionID sessionID) |
| { |
| auto result = m_swServers.ensure(sessionID, [&] { |
| auto info = m_serviceWorkerInfo.get(sessionID); |
| auto path = info.databasePath; |
| // There should already be a registered path for this PAL::SessionID. |
| // If there's not, then where did this PAL::SessionID come from? |
| ASSERT(sessionID.isEphemeral() || !path.isEmpty()); |
| |
| #if ENABLE(APP_BOUND_DOMAINS) |
| auto appBoundDomainsCallback = [this, sessionID](auto&& completionHandler) { |
| parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::GetAppBoundDomains { sessionID }, WTFMove(completionHandler), 0); |
| }; |
| #else |
| auto appBoundDomainsCallback = [] (auto&& completionHandler) { |
| completionHandler({ }); |
| }; |
| #endif |
| bool shouldRunServiceWorkersOnMainThreadForTesting = false; |
| if (auto* session = networkSession(sessionID)) |
| shouldRunServiceWorkersOnMainThreadForTesting = session->shouldRunServiceWorkersOnMainThreadForTesting(); |
| return makeUnique<SWServer>(makeUniqueRef<WebSWOriginStore>(), info.processTerminationDelayEnabled, WTFMove(path), sessionID, shouldRunServiceWorkersOnMainThreadForTesting, parentProcessHasServiceWorkerEntitlement(), [this, sessionID](auto&& jobData, bool shouldRefreshCache, auto&& request, auto&& completionHandler) mutable { |
| ServiceWorkerSoftUpdateLoader::start(networkSession(sessionID), WTFMove(jobData), shouldRefreshCache, WTFMove(request), WTFMove(completionHandler)); |
| }, [this, sessionID](auto& registrableDomain, std::optional<ScriptExecutionContextIdentifier> serviceWorkerPageIdentifier, auto&& completionHandler) { |
| ASSERT(!registrableDomain.isEmpty()); |
| parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::EstablishWorkerContextConnectionToNetworkProcess { registrableDomain, serviceWorkerPageIdentifier, sessionID }, WTFMove(completionHandler), 0); |
| }, WTFMove(appBoundDomainsCallback)); |
| }); |
| return *result.iterator->value; |
| } |
| |
| WebSWOriginStore* NetworkProcess::existingSWOriginStoreForSession(PAL::SessionID sessionID) const |
| { |
| auto* swServer = m_swServers.get(sessionID); |
| if (!swServer) |
| return nullptr; |
| return &static_cast<WebSWOriginStore&>(swServer->originStore()); |
| } |
| |
| void NetworkProcess::registerSWServerConnection(WebSWServerConnection& connection) |
| { |
| auto* store = existingSWOriginStoreForSession(connection.sessionID()); |
| ASSERT(store); |
| if (store) |
| store->registerSWServerConnection(connection); |
| } |
| |
| void NetworkProcess::unregisterSWServerConnection(WebSWServerConnection& connection) |
| { |
| if (auto* store = existingSWOriginStoreForSession(connection.sessionID())) |
| store->unregisterSWServerConnection(connection); |
| } |
| |
| void NetworkProcess::addServiceWorkerSession(PAL::SessionID sessionID, bool processTerminationDelayEnabled, String&& serviceWorkerRegistrationDirectory, const SandboxExtension::Handle& handle) |
| { |
| ServiceWorkerInfo info { |
| WTFMove(serviceWorkerRegistrationDirectory), |
| processTerminationDelayEnabled |
| }; |
| auto addResult = m_serviceWorkerInfo.add(sessionID, WTFMove(info)); |
| if (addResult.isNewEntry) |
| SandboxExtension::consumePermanently(handle); |
| } |
| |
| void NetworkProcess::processPushMessage(PAL::SessionID sessionID, const std::optional<IPC::DataReference>& ipcData, URL&& registrationURL, CompletionHandler<void(bool)>&& callback) |
| { |
| std::optional<Vector<uint8_t>> data; |
| if (ipcData) |
| data = Vector<uint8_t> { ipcData->data(), ipcData->size() }; |
| swServerForSession(sessionID).processPushMessage(WTFMove(data), WTFMove(registrationURL), WTFMove(callback)); |
| } |
| #endif // ENABLE(SERVICE_WORKER) |
| |
| void NetworkProcess::deletePushAndNotificationRegistration(PAL::SessionID sessionID, const SecurityOriginData& origin, CompletionHandler<void(const String&)>&& callback) |
| { |
| #if ENABLE(BUILT_IN_NOTIFICATIONS) |
| if (auto* session = networkSession(sessionID)) { |
| session->notificationManager().deletePushAndNotificationRegistration(origin, WTFMove(callback)); |
| return; |
| } |
| #endif |
| callback("Cannot find network session"); |
| } |
| |
| void NetworkProcess::getOriginsWithPushAndNotificationPermissions(PAL::SessionID sessionID, CompletionHandler<void(const Vector<WebCore::SecurityOriginData>&)>&& callback) |
| { |
| #if ENABLE(BUILT_IN_NOTIFICATIONS) |
| if (auto* session = networkSession(sessionID)) { |
| session->notificationManager().getOriginsWithPushAndNotificationPermissions(WTFMove(callback)); |
| return; |
| } |
| #endif |
| callback({ }); |
| } |
| |
| void NetworkProcess::requestStorageSpace(PAL::SessionID sessionID, const ClientOrigin& origin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(std::optional<uint64_t>)>&& callback) |
| { |
| parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::RequestStorageSpace { sessionID, origin, quota, currentSize, spaceRequired }, WTFMove(callback), 0); |
| } |
| |
| RefPtr<StorageQuotaManager> NetworkProcess::storageQuotaManager(PAL::SessionID sessionID, const ClientOrigin& origin) |
| { |
| Locker locker { m_sessionStorageQuotaManagersLock }; |
| auto* sessionStorageQuotaManager = m_sessionStorageQuotaManagers.get(sessionID); |
| if (!sessionStorageQuotaManager) |
| return nullptr; |
| |
| String idbRootPath = sessionStorageQuotaManager->idbRootPath(); |
| StorageQuotaManager::UsageGetter usageGetter = [cacheRootPath = sessionStorageQuotaManager->cacheRootPath().isolatedCopy(), idbRootPath = idbRootPath.isolatedCopy(), origin = origin.isolatedCopy()]() { |
| ASSERT(!isMainRunLoop()); |
| |
| return CacheStorage::Engine::diskUsage(cacheRootPath, origin) + IDBServer::IDBServer::diskUsage(idbRootPath, origin); |
| }; |
| StorageQuotaManager::QuotaIncreaseRequester quotaIncreaseRequester = [this, weakThis = WeakPtr { *this }, sessionID, origin] (uint64_t currentQuota, uint64_t currentSpace, uint64_t requestedIncrease, auto&& callback) { |
| ASSERT(isMainRunLoop()); |
| if (!weakThis) |
| callback({ }); |
| requestStorageSpace(sessionID, origin, currentQuota, currentSpace, requestedIncrease, WTFMove(callback)); |
| }; |
| |
| auto originStorageQuotaManager = sessionStorageQuotaManager->ensureOriginStorageQuotaManager(origin, sessionStorageQuotaManager->defaultQuota(origin), WTFMove(usageGetter), WTFMove(quotaIncreaseRequester)).ptr(); |
| return originStorageQuotaManager; |
| } |
| |
| #if !PLATFORM(COCOA) |
| void NetworkProcess::initializeProcess(const AuxiliaryProcessInitializationParameters&) |
| { |
| } |
| |
| void NetworkProcess::initializeProcessName(const AuxiliaryProcessInitializationParameters&) |
| { |
| } |
| |
| void NetworkProcess::initializeSandbox(const AuxiliaryProcessInitializationParameters&, SandboxInitializationParameters&) |
| { |
| } |
| |
| void NetworkProcess::flushCookies(PAL::SessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| completionHandler(); |
| } |
| |
| void NetworkProcess::platformFlushCookies(PAL::SessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| completionHandler(); |
| } |
| |
| #endif |
| |
| void NetworkProcess::storePrivateClickMeasurement(PAL::SessionID sessionID, WebCore::PrivateClickMeasurement&& privateClickMeasurement) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->storePrivateClickMeasurement(WTFMove(privateClickMeasurement)); |
| } |
| |
| void NetworkProcess::dumpPrivateClickMeasurement(PAL::SessionID sessionID, CompletionHandler<void(String)>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| return session->dumpPrivateClickMeasurement(WTFMove(completionHandler)); |
| |
| completionHandler({ }); |
| } |
| |
| void NetworkProcess::clearPrivateClickMeasurement(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->clearPrivateClickMeasurement(WTFMove(completionHandler)); |
| else |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setPrivateClickMeasurementOverrideTimerForTesting(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->setPrivateClickMeasurementOverrideTimerForTesting(value); |
| |
| completionHandler(); |
| } |
| |
| void NetworkProcess::simulateResourceLoadStatisticsSessionRestart(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| // FIXME: Rename this to simulatePrivateClickMeasurementSessionRestart. |
| if (auto* session = networkSession(sessionID)) { |
| session->recreatePrivateClickMeasurementStore([session = WeakPtr { *session }, completionHandler = WTFMove(completionHandler)] () mutable { |
| if (session) |
| session->firePrivateClickMeasurementTimerImmediatelyForTesting(); |
| completionHandler(); |
| }); |
| return; |
| } |
| completionHandler(); |
| } |
| |
| void NetworkProcess::markAttributedPrivateClickMeasurementsAsExpiredForTesting(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) { |
| session->markAttributedPrivateClickMeasurementsAsExpiredForTesting(WTFMove(completionHandler)); |
| return; |
| } |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setPrivateClickMeasurementEphemeralMeasurementForTesting(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->setPrivateClickMeasurementEphemeralMeasurementForTesting(value); |
| |
| completionHandler(); |
| } |
| |
| |
| void NetworkProcess::setPrivateClickMeasurementTokenPublicKeyURLForTesting(PAL::SessionID sessionID, URL&& url, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->setPrivateClickMeasurementTokenPublicKeyURLForTesting(WTFMove(url)); |
| |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setPrivateClickMeasurementTokenSignatureURLForTesting(PAL::SessionID sessionID, URL&& url, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->setPrivateClickMeasurementTokenSignatureURLForTesting(WTFMove(url)); |
| |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setPrivateClickMeasurementAttributionReportURLsForTesting(PAL::SessionID sessionID, URL&& sourceURL, URL&& destinationURL, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->setPrivateClickMeasurementAttributionReportURLsForTesting(WTFMove(sourceURL), WTFMove(destinationURL)); |
| |
| completionHandler(); |
| } |
| |
| void NetworkProcess::markPrivateClickMeasurementsAsExpiredForTesting(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->markPrivateClickMeasurementsAsExpiredForTesting(); |
| |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setPCMFraudPreventionValuesForTesting(PAL::SessionID sessionID, String&& unlinkableToken, String&& secretToken, String&& signature, String&& keyID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->setPCMFraudPreventionValuesForTesting(WTFMove(unlinkableToken), WTFMove(secretToken), WTFMove(signature), WTFMove(keyID)); |
| |
| completionHandler(); |
| } |
| |
| void NetworkProcess::setPrivateClickMeasurementAppBundleIDForTesting(PAL::SessionID sessionID, String&& appBundleIDForTesting, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* session = networkSession(sessionID)) |
| session->setPrivateClickMeasurementAppBundleIDForTesting(WTFMove(appBundleIDForTesting)); |
| |
| completionHandler(); |
| } |
| |
| void NetworkProcess::addKeptAliveLoad(Ref<NetworkResourceLoader>&& loader) |
| { |
| if (auto* session = networkSession(loader->sessionID())) |
| session->addKeptAliveLoad(WTFMove(loader)); |
| } |
| |
| void NetworkProcess::removeKeptAliveLoad(NetworkResourceLoader& loader) |
| { |
| if (auto* session = networkSession(loader.sessionID())) |
| session->removeKeptAliveLoad(loader); |
| } |
| |
| void NetworkProcess::getLocalStorageOriginDetails(PAL::SessionID sessionID, CompletionHandler<void(Vector<LocalStorageDatabaseTracker::OriginDetails>&&)>&& completionHandler) |
| { |
| if (!m_storageManagerSet->contains(sessionID)) { |
| LOG_ERROR("Cannot get local storage information for an unknown session"); |
| completionHandler({ }); |
| return; |
| } |
| |
| m_storageManagerSet->getLocalStorageOriginDetails(sessionID, WTFMove(completionHandler)); |
| } |
| |
| void NetworkProcess::connectionToWebProcessClosed(IPC::Connection& connection, PAL::SessionID sessionID) |
| { |
| m_storageManagerSet->removeConnection(connection); |
| |
| if (auto* server = m_webIDBServers.get(sessionID)) |
| server->removeConnection(connection); |
| |
| if (auto manager = m_storageManagers.get(sessionID)) |
| manager->stopReceivingMessageFromConnection(connection); |
| } |
| |
| NetworkConnectionToWebProcess* NetworkProcess::webProcessConnection(ProcessIdentifier identifier) const |
| { |
| return m_webProcessConnections.get(identifier); |
| } |
| |
| const Seconds NetworkProcess::defaultServiceWorkerFetchTimeout = 70_s; |
| void NetworkProcess::setServiceWorkerFetchTimeoutForTesting(Seconds timeout, CompletionHandler<void()>&& completionHandler) |
| { |
| m_serviceWorkerFetchTimeout = timeout; |
| completionHandler(); |
| } |
| |
| void NetworkProcess::resetServiceWorkerFetchTimeoutForTesting(CompletionHandler<void()>&& completionHandler) |
| { |
| m_serviceWorkerFetchTimeout = defaultServiceWorkerFetchTimeout; |
| completionHandler(); |
| } |
| |
| static constexpr auto delayMax = 100_ms; |
| static constexpr auto delayMin = 10_ms; |
| Seconds NetworkProcess::randomClosedPortDelay() |
| { |
| return delayMin + Seconds::fromMilliseconds(static_cast<double>(cryptographicallyRandomNumber())) % delayMax; |
| } |
| |
| #if ENABLE(APP_BOUND_DOMAINS) |
| void NetworkProcess::hasAppBoundSession(PAL::SessionID sessionID, CompletionHandler<void(bool)>&& completionHandler) const |
| { |
| bool result = false; |
| if (auto* networkSession = this->networkSession(sessionID)) |
| result = networkSession->hasAppBoundSession(); |
| completionHandler(result); |
| } |
| |
| void NetworkProcess::clearAppBoundSession(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| networkSession->clearAppBoundSession(); |
| completionHandler(); |
| } else { |
| ASSERT_NOT_REACHED(); |
| completionHandler(); |
| } |
| } |
| #endif |
| |
| void NetworkProcess::broadcastConsoleMessage(PAL::SessionID sessionID, JSC::MessageSource source, JSC::MessageLevel level, const String& message) |
| { |
| for (auto& networkConnectionToWebProcess : m_webProcessConnections.values()) { |
| if (networkConnectionToWebProcess->sessionID() == sessionID) |
| networkConnectionToWebProcess->broadcastConsoleMessage(source, level, message); |
| } |
| } |
| |
| void NetworkProcess::updateBundleIdentifier(String&& bundleIdentifier, CompletionHandler<void()>&& completionHandler) |
| { |
| #if PLATFORM(COCOA) |
| WebCore::clearApplicationBundleIdentifierTestingOverride(); |
| WebCore::setApplicationBundleIdentifierOverride(bundleIdentifier); |
| #endif |
| completionHandler(); |
| } |
| |
| void NetworkProcess::clearBundleIdentifier(CompletionHandler<void()>&& completionHandler) |
| { |
| #if PLATFORM(COCOA) |
| WebCore::clearApplicationBundleIdentifierTestingOverride(); |
| #endif |
| completionHandler(); |
| } |
| |
| bool NetworkProcess::shouldDisableCORSForRequestTo(PageIdentifier pageIdentifier, const URL& url) const |
| { |
| return WTF::anyOf(m_extensionCORSDisablingPatterns.get(pageIdentifier), [&] (const auto& pattern) { |
| return pattern.matches(url); |
| }); |
| } |
| |
| void NetworkProcess::setCORSDisablingPatterns(PageIdentifier pageIdentifier, Vector<String>&& patterns) |
| { |
| Vector<UserContentURLPattern> parsedPatterns; |
| parsedPatterns.reserveInitialCapacity(patterns.size()); |
| for (auto&& pattern : WTFMove(patterns)) { |
| UserContentURLPattern parsedPattern(WTFMove(pattern)); |
| if (parsedPattern.isValid()) |
| parsedPatterns.uncheckedAppend(WTFMove(parsedPattern)); |
| } |
| parsedPatterns.shrinkToFit(); |
| if (parsedPatterns.isEmpty()) { |
| m_extensionCORSDisablingPatterns.remove(pageIdentifier); |
| return; |
| } |
| m_extensionCORSDisablingPatterns.set(pageIdentifier, WTFMove(parsedPatterns)); |
| } |
| |
| #if PLATFORM(COCOA) |
| void NetworkProcess::appPrivacyReportTestingData(PAL::SessionID sessionID, CompletionHandler<void(const AppPrivacyReportTestingData&)>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) { |
| completionHandler(networkSession->appPrivacyReportTestingData()); |
| return; |
| } |
| completionHandler({ }); |
| } |
| |
| void NetworkProcess::clearAppPrivacyReportTestingData(PAL::SessionID sessionID, CompletionHandler<void()>&& completionHandler) |
| { |
| if (auto* networkSession = this->networkSession(sessionID)) |
| networkSession->appPrivacyReportTestingData().clearAppPrivacyReportTestingData(); |
| |
| completionHandler(); |
| } |
| #endif |
| |
| #if ENABLE(WEB_RTC) |
| RTCDataChannelRemoteManagerProxy& NetworkProcess::rtcDataChannelProxy() |
| { |
| ASSERT(isMainRunLoop()); |
| if (!m_rtcDataChannelProxy) |
| m_rtcDataChannelProxy = RTCDataChannelRemoteManagerProxy::create(); |
| return *m_rtcDataChannelProxy; |
| } |
| #endif |
| |
| void NetworkProcess::addWebPageNetworkParameters(PAL::SessionID sessionID, WebPageProxyIdentifier pageID, WebPageNetworkParameters&& parameters) |
| { |
| auto session = networkSession(sessionID); |
| if (!session) |
| return; |
| |
| session->addWebPageNetworkParameters(pageID, WTFMove(parameters)); |
| } |
| |
| void NetworkProcess::removeWebPageNetworkParameters(PAL::SessionID sessionID, WebPageProxyIdentifier pageID) |
| { |
| auto session = networkSession(sessionID); |
| if (!session) |
| return; |
| |
| session->removeWebPageNetworkParameters(pageID); |
| } |
| |
| void NetworkProcess::countNonDefaultSessionSets(PAL::SessionID sessionID, CompletionHandler<void(size_t)>&& completionHandler) |
| { |
| auto session = networkSession(sessionID); |
| if (!session) |
| return completionHandler(0); |
| |
| completionHandler(session->countNonDefaultSessionSets()); |
| } |
| |
| } // namespace WebKit |