Cache API and IDB space usages should be initialized on first quota check
[WebKit-https.git] / Source / WebKit / NetworkProcess / NetworkProcess.cpp
index c75b3bc..b5b7bec 100644 (file)
@@ -313,6 +313,7 @@ void NetworkProcess::initializeNetworkProcess(NetworkProcessCreationParameters&&
         switchToNewTestingSession();
 
     WebCore::RuntimeEnabledFeatures::sharedFeatures().setIsITPDatabaseEnabled(parameters.shouldEnableITPDatabase);
+    WebCore::RuntimeEnabledFeatures::sharedFeatures().setIsITPFirstPartyWebsiteDataRemovalEnabled(parameters.isITPFirstPartyWebsiteDataRemovalEnabled);
 
     SandboxExtension::consumePermanently(parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectoryExtensionHandle);
 
@@ -361,6 +362,8 @@ void NetworkProcess::initializeNetworkProcess(NetworkProcessCreationParameters&&
 
     for (auto& scheme : parameters.urlSchemesRegisteredAsCanDisplayOnlyIfCanRequest)
         registerURLSchemeAsCanDisplayOnlyIfCanRequest(scheme);
+    
+    m_downloadMonitorSpeedMultiplier = parameters.downloadMonitorSpeedMultiplier;
 
     RELEASE_LOG(Process, "%p - NetworkProcess::initializeNetworkProcess: Presenting process = %d", this, WebCore::presentingApplicationPID());
 }
@@ -377,7 +380,7 @@ void NetworkProcess::initializeConnection(IPC::Connection* connection)
         supplement->initializeConnection(connection);
 }
 
-void NetworkProcess::createNetworkConnectionToWebProcess(bool isServiceWorkerProcess, WebCore::SecurityOriginData&& securityOrigin)
+void NetworkProcess::createNetworkConnectionToWebProcess(bool isServiceWorkerProcess, WebCore::RegistrableDomain&& registrableDomain)
 {
 #if USE(UNIX_DOMAIN_SOCKETS)
     IPC::Connection::SocketPair socketPair = IPC::Connection::createPlatformConnection();
@@ -429,8 +432,8 @@ void NetworkProcess::createNetworkConnectionToWebProcess(bool isServiceWorkerPro
     if (isServiceWorkerProcess && !m_webProcessConnections.isEmpty()) {
         ASSERT(parentProcessHasServiceWorkerEntitlement());
         ASSERT(m_waitingForServerToContextProcessConnection);
-        auto contextConnection = WebSWServerToContextConnection::create(*this, securityOrigin, m_webProcessConnections.last()->connection());
-        auto addResult = m_serverToContextConnections.add(WTFMove(securityOrigin), contextConnection.copyRef());
+        auto contextConnection = WebSWServerToContextConnection::create(*this, registrableDomain, m_webProcessConnections.last()->connection());
+        auto addResult = m_serverToContextConnections.add(WTFMove(registrableDomain), contextConnection.copyRef());
         ASSERT_UNUSED(addResult, addResult.isNewEntry);
 
         m_waitingForServerToContextProcessConnection = false;
@@ -440,7 +443,7 @@ void NetworkProcess::createNetworkConnectionToWebProcess(bool isServiceWorkerPro
     }
 #else
     UNUSED_PARAM(isServiceWorkerProcess);
-    UNUSED_PARAM(securityOrigin);
+    UNUSED_PARAM(registrableDomain);
 #endif
 }
 
@@ -786,6 +789,19 @@ void NetworkProcess::setNotifyPagesWhenDataRecordsWereScanned(PAL::SessionID ses
     }
 }
 
+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::setNotifyPagesWhenTelemetryWasCaptured(PAL::SessionID sessionID, bool value, CompletionHandler<void()>&& completionHandler)
 {
     if (auto* networkSession = this->networkSession(sessionID)) {
@@ -964,11 +980,11 @@ void NetworkProcess::hasStorageAccess(PAL::SessionID sessionID, const Registrabl
     }
 }
 
-void NetworkProcess::requestStorageAccess(PAL::SessionID sessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, Optional<uint64_t> frameID, uint64_t pageID, bool promptEnabled, CompletionHandler<void(StorageAccessStatus)>&& completionHandler)
+void NetworkProcess::requestStorageAccess(PAL::SessionID sessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, Optional<uint64_t> frameID, uint64_t pageID, CompletionHandler<void(StorageAccessStatus)>&& completionHandler)
 {
     if (auto* networkSession = this->networkSession(sessionID)) {
         if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
-            resourceLoadStatistics->requestStorageAccess(subFrameDomain, topFrameDomain, frameID.value(), pageID, promptEnabled, WTFMove(completionHandler));
+            resourceLoadStatistics->requestStorageAccess(subFrameDomain, topFrameDomain, frameID.value(), pageID, WTFMove(completionHandler));
         else
             completionHandler(StorageAccessStatus::CannotRequestAccess);
     } else {
@@ -977,11 +993,11 @@ void NetworkProcess::requestStorageAccess(PAL::SessionID sessionID, const Regist
     }
 }
 
-void NetworkProcess::requestStorageAccessGranted(PAL::SessionID sessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, uint64_t frameID, uint64_t pageID, bool promptEnabled, CompletionHandler<void(bool)>&& completionHandler)
+void NetworkProcess::requestStorageAccessGranted(PAL::SessionID sessionID, const RegistrableDomain& subFrameDomain, const RegistrableDomain& topFrameDomain, uint64_t frameID, uint64_t pageID, CompletionHandler<void(bool)>&& completionHandler)
 {
     if (auto* networkSession = this->networkSession(sessionID)) {
         if (auto* resourceLoadStatistics = networkSession->resourceLoadStatistics())
-            resourceLoadStatistics->requestStorageAccessGranted(subFrameDomain, topFrameDomain, frameID, pageID, promptEnabled, WTFMove(completionHandler));
+            resourceLoadStatistics->requestStorageAccessGranted(subFrameDomain, topFrameDomain, frameID, pageID, WTFMove(completionHandler));
         else
             completionHandler(false);
     } else {
@@ -1205,6 +1221,19 @@ void NetworkProcess::committedCrossSiteLoadWithLinkDecoration(PAL::SessionID ses
     }
 }
 
+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))
@@ -1391,6 +1420,9 @@ void NetworkProcess::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<Websi
 
     if (websiteDataTypes.contains(WebsiteDataType::DiskCache) && !sessionID.isEphemeral())
         clearDiskCache(modifiedSince, [clearTasksHandler = WTFMove(clearTasksHandler)] { });
+
+    if (websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases) || websiteDataTypes.contains(WebsiteDataType::DOMCache))
+        clearStorageQuota(sessionID);
 }
 
 static void clearDiskCacheEntries(NetworkCache::Cache* cache, const Vector<SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
@@ -1455,6 +1487,18 @@ void NetworkProcess::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, Optio
 
     if (websiteDataTypes.contains(WebsiteDataType::DiskCache) && !sessionID.isEphemeral())
         clearDiskCacheEntries(cache(), originDatas, [clearTasksHandler = WTFMove(clearTasksHandler)] { });
+
+    // FIXME: Implement storage quota clearing for these origins.
+}
+
+void NetworkProcess::clearStorageQuota(PAL::SessionID sessionID)
+{
+    auto iterator = m_storageQuotaManagers.find(sessionID);
+    if (iterator == m_storageQuotaManagers.end())
+        return;
+
+    for (auto& manager : iterator->value.managersPerOrigin.values())
+        manager->resetQuota(iterator->value.defaultQuota);
 }
 
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
@@ -1480,7 +1524,7 @@ static Vector<WebsiteData::Entry> filterForRegistrableDomains(const Vector<Regis
     return result;
 }
 
-void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, Vector<RegistrableDomain>&& domains, bool shouldNotifyPage, IncludeHttpOnlyCookies includeHttpOnlyCookies, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
+void NetworkProcess::deleteWebsiteDataForRegistrableDomains(PAL::SessionID sessionID, OptionSet<WebsiteDataType> websiteDataTypes, HashMap<RegistrableDomain, WebsiteDataToRemove>&& domains, bool shouldNotifyPage, CompletionHandler<void(const HashSet<RegistrableDomain>&)>&& completionHandler)
 {
     OptionSet<WebsiteDataFetchOption> fetchOptions = WebsiteDataFetchOption::DoNotCreateProcesses;
 
@@ -1522,13 +1566,37 @@ void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataSt
 
     auto& websiteDataStore = callbackAggregator->m_websiteData;
 
+    Vector<RegistrableDomain> domainsToDeleteCookiesFor;
+    Vector<RegistrableDomain> domainsToDeleteAllButHttpOnlyCookiesFor;
+    Vector<RegistrableDomain> domainsToDeleteAllButCookiesFor;
     Vector<String> hostnamesWithCookiesToDelete;
     if (websiteDataTypes.contains(WebsiteDataType::Cookies)) {
+        for (auto& domain : domains.keys()) {
+            domainsToDeleteAllButCookiesFor.append(domain);
+            switch (domains.get(domain)) {
+            case WebsiteDataToRemove::All:
+                domainsToDeleteCookiesFor.append(domain);
+                break;
+            case WebsiteDataToRemove::AllButHttpOnlyCookies:
+                domainsToDeleteAllButHttpOnlyCookiesFor.append(domain);
+                break;
+            case WebsiteDataToRemove::AllButCookies:
+                // Already added.
+                break;
+            }
+        }
         if (auto* networkStorageSession = storageSession(sessionID)) {
             networkStorageSession->getHostnamesWithCookies(websiteDataStore.hostNamesWithCookies);
-            hostnamesWithCookiesToDelete = filterForRegistrableDomains(domains, websiteDataStore.hostNamesWithCookies);
-            networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, includeHttpOnlyCookies);
+
+            hostnamesWithCookiesToDelete = filterForRegistrableDomains(domainsToDeleteCookiesFor, websiteDataStore.hostNamesWithCookies);
+            networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, WebCore::IncludeHttpOnlyCookies::Yes);
+
+            hostnamesWithCookiesToDelete = filterForRegistrableDomains(domainsToDeleteAllButHttpOnlyCookiesFor, websiteDataStore.hostNamesWithCookies);
+            networkStorageSession->deleteCookiesForHostnames(hostnamesWithCookiesToDelete, WebCore::IncludeHttpOnlyCookies::No);
         }
+    } else {
+        for (auto& domain : domains.keys())
+            domainsToDeleteAllButCookiesFor.append(domain);
     }
 
     Vector<String> hostnamesWithHSTSToDelete;
@@ -1536,7 +1604,7 @@ void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataSt
     if (websiteDataTypes.contains(WebsiteDataType::HSTSCache)) {
         if (auto* networkStorageSession = storageSession(sessionID)) {
             getHostNamesWithHSTSCache(*networkStorageSession, websiteDataStore.hostNamesWithHSTSCache);
-            hostnamesWithHSTSToDelete = filterForRegistrableDomains(domains, websiteDataStore.hostNamesWithHSTSCache);
+            hostnamesWithHSTSToDelete = filterForRegistrableDomains(domainsToDeleteAllButCookiesFor, websiteDataStore.hostNamesWithHSTSCache);
             deleteHSTSCacheForHostNames(*networkStorageSession, hostnamesWithHSTSToDelete);
         }
     }
@@ -1551,9 +1619,9 @@ void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataSt
     */
     
     if (websiteDataTypes.contains(WebsiteDataType::DOMCache)) {
-        CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [this, domains, sessionID, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
+        CacheStorage::Engine::fetchEntries(*this, sessionID, fetchOptions.contains(WebsiteDataFetchOption::ComputeSizes), [this, domainsToDeleteAllButCookiesFor, sessionID, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
             
-            auto entriesToDelete = filterForRegistrableDomains(domains, entries);
+            auto entriesToDelete = filterForRegistrableDomains(domainsToDeleteAllButCookiesFor, entries);
 
             callbackAggregator->m_websiteData.entries.appendVector(entriesToDelete);
             
@@ -1566,11 +1634,11 @@ void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataSt
     auto path = m_idbDatabasePaths.get(sessionID);
     if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::IndexedDBDatabases)) {
         // FIXME: Pick the right database store based on the session ID.
-        postStorageTask(CrossThreadTask([this, sessionID, callbackAggregator = callbackAggregator.copyRef(), path = WTFMove(path), domains]() mutable {
-            RunLoop::main().dispatch([this, sessionID, domains = crossThreadCopy(domains), callbackAggregator = callbackAggregator.copyRef(), securityOrigins = indexedDatabaseOrigins(path)] {
+        postStorageTask(CrossThreadTask([this, sessionID, callbackAggregator = callbackAggregator.copyRef(), path = WTFMove(path), domainsToDeleteAllButCookiesFor]() mutable {
+            RunLoop::main().dispatch([this, sessionID, domainsToDeleteAllButCookiesFor = crossThreadCopy(domainsToDeleteAllButCookiesFor), callbackAggregator = callbackAggregator.copyRef(), securityOrigins = indexedDatabaseOrigins(path)] {
                 Vector<SecurityOriginData> entriesToDelete;
                 for (const auto& securityOrigin : securityOrigins) {
-                    if (!domains.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
+                    if (!domainsToDeleteAllButCookiesFor.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
                         continue;
 
                     entriesToDelete.append(securityOrigin);
@@ -1586,9 +1654,9 @@ void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataSt
 #if ENABLE(SERVICE_WORKER)
     path = m_swDatabasePaths.get(sessionID);
     if (!path.isEmpty() && websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations)) {
-        swServerForSession(sessionID).getOriginsWithRegistrations([this, sessionID, domains, callbackAggregator = callbackAggregator.copyRef()](const HashSet<SecurityOriginData>& securityOrigins) mutable {
+        swServerForSession(sessionID).getOriginsWithRegistrations([this, sessionID, domainsToDeleteAllButCookiesFor, callbackAggregator = callbackAggregator.copyRef()](const HashSet<SecurityOriginData>& securityOrigins) mutable {
             for (auto& securityOrigin : securityOrigins) {
-                if (!domains.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
+                if (!domainsToDeleteAllButCookiesFor.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
                     continue;
                 callbackAggregator->m_websiteData.entries.append({ securityOrigin, WebsiteDataType::ServiceWorkerRegistrations, 0 });
                 swServerForSession(sessionID).clear(securityOrigin, [callbackAggregator = callbackAggregator.copyRef()] { });
@@ -1598,11 +1666,11 @@ void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataSt
 #endif
     
     if (websiteDataTypes.contains(WebsiteDataType::DiskCache)) {
-        fetchDiskCacheEntries(cache(), sessionID, fetchOptions, [this, domains, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
+        fetchDiskCacheEntries(cache(), sessionID, fetchOptions, [this, domainsToDeleteAllButCookiesFor, callbackAggregator = callbackAggregator.copyRef()](auto entries) mutable {
 
             Vector<SecurityOriginData> entriesToDelete;
             for (auto& entry : entries) {
-                if (!domains.contains(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host)))
+                if (!domainsToDeleteAllButCookiesFor.contains(RegistrableDomain::uncheckedCreateFromHost(entry.origin.host)))
                     continue;
                 entriesToDelete.append(entry.origin);
                 callbackAggregator->m_websiteData.entries.append(entry);
@@ -1615,8 +1683,9 @@ void NetworkProcess::deleteWebsiteDataForRegistrableDomainsInAllPersistentDataSt
 void NetworkProcess::deleteCookiesForTesting(PAL::SessionID sessionID, RegistrableDomain domain, bool includeHttpOnlyCookies, CompletionHandler<void()>&& completionHandler)
 {
     OptionSet<WebsiteDataType> cookieType = WebsiteDataType::Cookies;
-
-    deleteWebsiteDataForRegistrableDomainsInAllPersistentDataStores(sessionID, cookieType, { domain }, true, includeHttpOnlyCookies ? IncludeHttpOnlyCookies::Yes : IncludeHttpOnlyCookies::No, [completionHandler = WTFMove(completionHandler)] (const HashSet<RegistrableDomain>& domainsDeletedFor) mutable {
+    HashMap<RegistrableDomain, WebsiteDataToRemove> toDeleteFor;
+    toDeleteFor.add(domain, includeHttpOnlyCookies ? WebsiteDataToRemove::All : WebsiteDataToRemove::AllButHttpOnlyCookies);
+    deleteWebsiteDataForRegistrableDomains(sessionID, cookieType, WTFMove(toDeleteFor), true, [completionHandler = WTFMove(completionHandler)] (const HashSet<RegistrableDomain>& domainsDeletedFor) mutable {
         UNUSED_PARAM(domainsDeletedFor);
         completionHandler();
     });
@@ -1927,6 +1996,16 @@ void NetworkProcess::cancelPrepareToSuspend()
         connection->endSuspension();
 }
 
+void NetworkProcess::applicationDidEnterBackground()
+{
+    m_downloadManager.applicationDidEnterBackground();
+}
+
+void NetworkProcess::applicationWillEnterForeground()
+{
+    m_downloadManager.applicationWillEnterForeground();
+}
+
 void NetworkProcess::processDidResume()
 {
     RELEASE_LOG(ProcessSuspension, "%p - NetworkProcess::processDidResume()", this);
@@ -1950,9 +2029,12 @@ void NetworkProcess::cacheStorageRootPath(PAL::SessionID sessionID, CacheStorage
 
 void NetworkProcess::setCacheStorageParameters(PAL::SessionID sessionID, uint64_t quota, String&& cacheStorageDirectory, SandboxExtension::Handle&& handle)
 {
-    m_storageQuotaManagers.ensure(sessionID, [] {
+    auto& managers =  m_storageQuotaManagers.ensure(sessionID, [] {
         return StorageQuotaManagers { };
-    }).iterator->value.defaultQuota = quota;
+    }).iterator->value;
+    managers.defaultQuota = quota;
+    // FIXME: Pass default third party quota as a parameter.
+    managers.defaultThirdPartyQuota = quota / 10;
 
     auto iterator = m_cacheStorageParametersCallbacks.find(sessionID);
     if (iterator == m_cacheStorageParametersCallbacks.end())
@@ -2022,24 +2104,32 @@ void NetworkProcess::didSyncAllCookies()
 }
 
 #if ENABLE(INDEXED_DATABASE)
-IDBServer::IDBServer& NetworkProcess::idbServer(PAL::SessionID sessionID)
+Ref<IDBServer::IDBServer> NetworkProcess::createIDBServer(PAL::SessionID sessionID)
 {
-    auto addResult = m_idbServers.add(sessionID, nullptr);
-    if (!addResult.isNewEntry) {
-        ASSERT(addResult.iterator->value);
-        return *addResult.iterator->value;
+    String path;
+    if (!sessionID.isEphemeral()) {
+        ASSERT(m_idbDatabasePaths.contains(sessionID));
+        path = m_idbDatabasePaths.get(sessionID);
     }
-    
-    auto path = m_idbDatabasePaths.get(sessionID);
-    // There should already be a registered path for this PAL::SessionID.
-    // If there's not, then where did this PAL::SessionID come from?
-    ASSERT(!path.isEmpty());
-    
-    addResult.iterator->value = IDBServer::IDBServer::create(path, *this, [this](bool isHoldingLockedFiles) {
-        notifyHoldingLockedFiles(isHoldingLockedFiles);
+
+    auto server = IDBServer::IDBServer::create(sessionID, path, *this, [this, weakThis = makeWeakPtr(this)](PAL::SessionID sessionID, const auto& origin) -> StorageQuotaManager* {
+        if (!weakThis)
+            return nullptr;
+        return &this->storageQuotaManager(sessionID, origin);
+    }, [this, weakThis = makeWeakPtr(this)](bool isHoldingLockedFiles) {
+        if (!weakThis)
+            return;
+        this->notifyHoldingLockedFiles(isHoldingLockedFiles);
     });
-    addResult.iterator->value->setPerOriginQuota(m_idbPerOriginQuota);
-    return *addResult.iterator->value;
+    server->setPerOriginQuota(m_idbPerOriginQuota);
+    return server;
+}
+
+IDBServer::IDBServer& NetworkProcess::idbServer(PAL::SessionID sessionID)
+{
+    return *m_idbServers.ensure(sessionID, [this, sessionID] {
+        return this->createIDBServer(sessionID);
+    }).iterator->value;
 }
 
 void NetworkProcess::ensurePathExists(const String& path)
@@ -2085,23 +2175,33 @@ void NetworkProcess::accessToTemporaryFileComplete(const String& path)
     FileSystem::deleteFile(path);
 }
 
-HashSet<WebCore::SecurityOriginData> NetworkProcess::indexedDatabaseOrigins(const String& path)
+void NetworkProcess::collectIndexedDatabaseOriginsForVersion(const String& path, HashSet<WebCore::SecurityOriginData>& securityOrigins)
 {
     if (path.isEmpty())
-        return { };
-    
-    HashSet<WebCore::SecurityOriginData> securityOrigins;
+        return;
+
     for (auto& topOriginPath : FileSystem::listDirectory(path, "*")) {
         auto databaseIdentifier = FileSystem::pathGetFileName(topOriginPath);
-        if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(databaseIdentifier))
+        if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(databaseIdentifier)) {
             securityOrigins.add(WTFMove(*securityOrigin));
         
-        for (auto& originPath : FileSystem::listDirectory(topOriginPath, "*")) {
-            databaseIdentifier = FileSystem::pathGetFileName(originPath);
-            if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(databaseIdentifier))
-                securityOrigins.add(WTFMove(*securityOrigin));
+            for (auto& originPath : FileSystem::listDirectory(topOriginPath, "*")) {
+                databaseIdentifier = FileSystem::pathGetFileName(originPath);
+                if (auto securityOrigin = SecurityOriginData::fromDatabaseIdentifier(databaseIdentifier))
+                    securityOrigins.add(WTFMove(*securityOrigin));
+            }
         }
     }
+}
+
+HashSet<WebCore::SecurityOriginData> NetworkProcess::indexedDatabaseOrigins(const String& path)
+{
+    if (path.isEmpty())
+        return { };
+    
+    HashSet<WebCore::SecurityOriginData> securityOrigins;
+    collectIndexedDatabaseOriginsForVersion(FileSystem::pathByAppendingComponent(path, "v0"), securityOrigins);
+    collectIndexedDatabaseOriginsForVersion(FileSystem::pathByAppendingComponent(path, "v1"), securityOrigins);
 
     return securityOrigins;
 }
@@ -2128,6 +2228,13 @@ void NetworkProcess::setIDBPerOriginQuota(uint64_t quota)
 }
 #endif // ENABLE(INDEXED_DATABASE)
 
+void NetworkProcess::updateQuotaBasedOnSpaceUsageForTesting(PAL::SessionID sessionID, const ClientOrigin& origin)
+{
+    auto& manager = storageQuotaManager(sessionID, origin);
+    manager.resetQuota(m_storageQuotaManagers.find(sessionID)->value.defaultQuota);
+    manager.updateQuotaBasedOnSpaceUsage();
+}
+
 #if ENABLE(SANDBOX_EXTENSIONS)
 void NetworkProcess::getSandboxExtensionsForBlobFiles(const Vector<String>& filenames, CompletionHandler<void(SandboxExtension::HandleArray&&)>&& completionHandler)
 {
@@ -2147,24 +2254,24 @@ WebSWServerToContextConnection* NetworkProcess::connectionToContextProcessFromIP
 
 void NetworkProcess::connectionToContextProcessWasClosed(Ref<WebSWServerToContextConnection>&& serverToContextConnection)
 {
-    auto& securityOrigin = serverToContextConnection->securityOrigin();
+    auto& registrableDomain = serverToContextConnection->registrableDomain();
     
     serverToContextConnection->connectionClosed();
-    m_serverToContextConnections.remove(securityOrigin);
+    m_serverToContextConnections.remove(registrableDomain);
     
     for (auto& swServer : m_swServers.values())
-        swServer->markAllWorkersForOriginAsTerminated(securityOrigin);
+        swServer->markAllWorkersForRegistrableDomainAsTerminated(registrableDomain);
     
-    if (needsServerToContextConnectionForOrigin(securityOrigin)) {
+    if (needsServerToContextConnectionForRegistrableDomain(registrableDomain)) {
         RELEASE_LOG(ServiceWorker, "Connection to service worker process was closed but is still needed, relaunching it");
-        createServerToContextConnection(securityOrigin, WTF::nullopt);
+        createServerToContextConnection(registrableDomain, WTF::nullopt);
     }
 }
 
-bool NetworkProcess::needsServerToContextConnectionForOrigin(const SecurityOriginData& securityOrigin) const
+bool NetworkProcess::needsServerToContextConnectionForRegistrableDomain(const RegistrableDomain& registrableDomain) const
 {
     return WTF::anyOf(m_swServers.values(), [&](auto& swServer) {
-        return swServer->needsServerToContextConnectionForOrigin(securityOrigin);
+        return swServer->needsServerToContextConnectionForRegistrableDomain(registrableDomain);
     });
 }
 
@@ -2200,21 +2307,21 @@ WebSWOriginStore* NetworkProcess::existingSWOriginStoreForSession(PAL::SessionID
     return &static_cast<WebSWOriginStore&>(swServer->originStore());
 }
 
-WebSWServerToContextConnection* NetworkProcess::serverToContextConnectionForOrigin(const SecurityOriginData& securityOrigin)
+WebSWServerToContextConnection* NetworkProcess::serverToContextConnectionForRegistrableDomain(const RegistrableDomain& registrableDomain)
 {
-    return m_serverToContextConnections.get(securityOrigin);
+    return m_serverToContextConnections.get(registrableDomain);
 }
 
-void NetworkProcess::createServerToContextConnection(const SecurityOriginData& securityOrigin, Optional<PAL::SessionID> sessionID)
+void NetworkProcess::createServerToContextConnection(const RegistrableDomain& registrableDomain, Optional<PAL::SessionID> sessionID)
 {
     if (m_waitingForServerToContextProcessConnection)
         return;
     
     m_waitingForServerToContextProcessConnection = true;
     if (sessionID)
-        parentProcessConnection()->send(Messages::NetworkProcessProxy::EstablishWorkerContextConnectionToNetworkProcessForExplicitSession(securityOrigin, *sessionID), 0);
+        parentProcessConnection()->send(Messages::NetworkProcessProxy::EstablishWorkerContextConnectionToNetworkProcessForExplicitSession(registrableDomain, *sessionID), 0);
     else
-        parentProcessConnection()->send(Messages::NetworkProcessProxy::EstablishWorkerContextConnectionToNetworkProcess(securityOrigin), 0);
+        parentProcessConnection()->send(Messages::NetworkProcessProxy::EstablishWorkerContextConnectionToNetworkProcess(registrableDomain), 0);
 }
 
 void NetworkProcess::postMessageToServiceWorkerClient(const ServiceWorkerClientIdentifier& destinationIdentifier, MessageWithMessagePorts&& message, ServiceWorkerIdentifier sourceIdentifier, const String& sourceOrigin)
@@ -2247,18 +2354,18 @@ void NetworkProcess::unregisterSWServerConnection(WebSWServerConnection& connect
 
 void NetworkProcess::swContextConnectionMayNoLongerBeNeeded(WebSWServerToContextConnection& serverToContextConnection)
 {
-    auto& securityOrigin = serverToContextConnection.securityOrigin();
-    if (needsServerToContextConnectionForOrigin(securityOrigin))
+    auto& registrableDomain = serverToContextConnection.registrableDomain();
+    if (needsServerToContextConnectionForRegistrableDomain(registrableDomain))
         return;
     
     RELEASE_LOG(ServiceWorker, "Service worker process is no longer needed, terminating it");
     serverToContextConnection.terminate();
     
     for (auto& swServer : m_swServers.values())
-        swServer->markAllWorkersForOriginAsTerminated(securityOrigin);
+        swServer->markAllWorkersForRegistrableDomainAsTerminated(registrableDomain);
     
     serverToContextConnection.connectionClosed();
-    m_serverToContextConnections.remove(securityOrigin);
+    m_serverToContextConnections.remove(registrableDomain);
 }
 
 void NetworkProcess::disableServiceWorkerProcessTerminationDelay()
@@ -2287,15 +2394,61 @@ void NetworkProcess::requestStorageSpace(PAL::SessionID sessionID, const ClientO
     parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::RequestStorageSpace { sessionID, origin, quota, currentSize, spaceRequired }, WTFMove(callback), 0);
 }
 
+class QuotaUserInitializer final : public WebCore::StorageQuotaUser {
+public:
+    explicit QuotaUserInitializer(StorageQuotaManager& manager)
+        : m_manager(makeWeakPtr(manager))
+    {
+        manager.addUser(*this);
+    }
+
+    ~QuotaUserInitializer()
+    {
+        if (m_manager)
+            m_manager->removeUser(*this);
+        if (m_callback)
+            m_callback();
+    }
+
+private:
+    // StorageQuotaUser API.
+    uint64_t spaceUsed() const final
+    {
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+
+    void whenInitialized(CompletionHandler<void()>&& callback) final
+    {
+        m_callback = WTFMove(callback);
+    }
+
+    WeakPtr<StorageQuotaManager> m_manager;
+    CompletionHandler<void()> m_callback;
+};
+
+void NetworkProcess::initializeQuotaUsers(StorageQuotaManager& manager, PAL::SessionID sessionID, const ClientOrigin& origin)
+{
+    RunLoop::main().dispatch([this, weakThis = makeWeakPtr(this), sessionID, origin, user = std::make_unique<QuotaUserInitializer>(manager)]() mutable {
+        if (!weakThis)
+            return;
+        this->idbServer(sessionID).initializeQuotaUser(origin);
+        CacheStorage::Engine::initializeQuotaUser(*this, sessionID, origin, [user = WTFMove(user)] { });
+    });
+}
+
 StorageQuotaManager& NetworkProcess::storageQuotaManager(PAL::SessionID sessionID, const ClientOrigin& origin)
 {
     auto& storageQuotaManagers = m_storageQuotaManagers.ensure(sessionID, [] {
         return StorageQuotaManagers { };
     }).iterator->value;
     return *storageQuotaManagers.managersPerOrigin.ensure(origin, [this, &storageQuotaManagers, sessionID, &origin] {
-        return std::make_unique<StorageQuotaManager>(storageQuotaManagers.defaultQuota, [this, sessionID, origin](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
+        auto quota = origin.topOrigin == origin.clientOrigin ? storageQuotaManagers.defaultQuota : storageQuotaManagers.defaultThirdPartyQuota;
+        auto manager = std::make_unique<StorageQuotaManager>(quota, [this, sessionID, origin](uint64_t quota, uint64_t currentSpace, uint64_t spaceIncrease, auto callback) {
             this->requestStorageSpace(sessionID, origin, quota, currentSpace, spaceIncrease, WTFMove(callback));
         });
+        initializeQuotaUsers(*manager, sessionID, origin);
+        return manager;
     }).iterator->value;
 }