WebResourceLoadStatisticsStore.cpp [plain text]
#include "config.h"
#include "WebResourceLoadStatisticsStore.h"
#include "Logging.h"
#include "ResourceLoadStatisticsMemoryStore.h"
#include "ResourceLoadStatisticsPersistentStorage.h"
#include "WebFrameProxy.h"
#include "WebPageProxy.h"
#include "WebProcessMessages.h"
#include "WebProcessProxy.h"
#include "WebResourceLoadStatisticsStoreMessages.h"
#include "WebResourceLoadStatisticsTelemetry.h"
#include "WebsiteDataFetchOption.h"
#include "WebsiteDataStore.h"
#include <WebCore/ResourceLoadStatistics.h>
#include <wtf/CallbackAggregator.h>
#include <wtf/CrossThreadCopier.h>
#include <wtf/NeverDestroyed.h>
#include <wtf/threads/BinarySemaphore.h>
namespace WebKit {
using namespace WebCore;
template<typename T> static inline String isolatedPrimaryDomain(const T& value)
{
return ResourceLoadStatistics::primaryDomain(value).isolatedCopy();
}
static bool areDomainsAssociated(WebPageProxy* page, const String& firstDomain, const String& secondDomain)
{
bool needsSiteSpecificQuirks = page && page->preferences().needsSiteSpecificQuirks();
return ResourceLoadStatistics::areDomainsAssociated(needsSiteSpecificQuirks, firstDomain, secondDomain);
}
const OptionSet<WebsiteDataType>& WebResourceLoadStatisticsStore::monitoredDataTypes()
{
static NeverDestroyed<OptionSet<WebsiteDataType>> dataTypes(std::initializer_list<WebsiteDataType>({
WebsiteDataType::Cookies,
WebsiteDataType::DOMCache,
WebsiteDataType::IndexedDBDatabases,
WebsiteDataType::LocalStorage,
WebsiteDataType::MediaKeys,
WebsiteDataType::OfflineWebApplicationCache,
#if ENABLE(NETSCAPE_PLUGIN_API)
WebsiteDataType::PlugInData,
#endif
WebsiteDataType::SearchFieldRecentSearches,
WebsiteDataType::SessionStorage,
#if ENABLE(SERVICE_WORKER)
WebsiteDataType::ServiceWorkerRegistrations,
#endif
WebsiteDataType::WebSQLDatabases,
}));
ASSERT(RunLoop::isMain());
return dataTypes;
}
void WebResourceLoadStatisticsStore::setNotifyPagesWhenDataRecordsWereScanned(bool value)
{
ASSERT(RunLoop::isMain());
postTask([this, value] {
if (m_memoryStore)
m_memoryStore->setNotifyPagesWhenDataRecordsWereScanned(value);
});
}
void WebResourceLoadStatisticsStore::setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
{
ASSERT(RunLoop::isMain());
postTask([this, value] {
if (m_memoryStore)
m_memoryStore->setShouldClassifyResourcesBeforeDataRecordsRemoval(value);
});
}
void WebResourceLoadStatisticsStore::setShouldSubmitTelemetry(bool value)
{
ASSERT(RunLoop::isMain());
postTask([this, value] {
if (m_memoryStore)
m_memoryStore->setShouldSubmitTelemetry(value);
});
}
WebResourceLoadStatisticsStore::WebResourceLoadStatisticsStore(WebsiteDataStore& websiteDataStore)
: m_websiteDataStore(makeWeakPtr(websiteDataStore))
, m_statisticsQueue(WorkQueue::create("WebResourceLoadStatisticsStore Process Data Queue", WorkQueue::Type::Serial, WorkQueue::QOS::Utility))
, m_dailyTasksTimer(RunLoop::main(), this, &WebResourceLoadStatisticsStore::performDailyTasks)
{
ASSERT(RunLoop::isMain());
postTask([this, resourceLoadStatisticsDirectory = websiteDataStore.resolvedResourceLoadStatisticsDirectory().isolatedCopy()] {
m_memoryStore = std::make_unique<ResourceLoadStatisticsMemoryStore>(*this, m_statisticsQueue);
m_persistentStorage = std::make_unique<ResourceLoadStatisticsPersistentStorage>(*m_memoryStore, m_statisticsQueue, resourceLoadStatisticsDirectory);
});
m_dailyTasksTimer.startRepeating(24_h);
}
WebResourceLoadStatisticsStore::~WebResourceLoadStatisticsStore()
{
ASSERT(RunLoop::isMain());
flushAndDestroyPersistentStore();
}
inline void WebResourceLoadStatisticsStore::postTask(WTF::Function<void()>&& task)
{
ASSERT(RunLoop::isMain());
m_statisticsQueue->dispatch([protectedThis = makeRef(*this), task = WTFMove(task)] {
task();
});
}
inline void WebResourceLoadStatisticsStore::postTaskReply(WTF::Function<void()>&& reply)
{
ASSERT(!RunLoop::isMain());
RunLoop::main().dispatch([reply = WTFMove(reply)] {
reply();
});
}
void WebResourceLoadStatisticsStore::flushAndDestroyPersistentStore()
{
ASSERT(RunLoop::isMain());
if (!m_persistentStorage && !m_memoryStore)
return;
BinarySemaphore semaphore;
m_statisticsQueue->dispatch([&semaphore, this] {
m_persistentStorage = nullptr;
m_memoryStore = nullptr;
semaphore.signal();
});
semaphore.wait(WallTime::infinity());
}
void WebResourceLoadStatisticsStore::setResourceLoadStatisticsDebugMode(bool value)
{
ASSERT(RunLoop::isMain());
postTask([this, value] {
if (m_memoryStore)
m_memoryStore->setResourceLoadStatisticsDebugMode(value);
});
}
void WebResourceLoadStatisticsStore::scheduleStatisticsAndDataRecordsProcessing()
{
ASSERT(RunLoop::isMain());
postTask([this] {
if (m_memoryStore)
m_memoryStore->processStatisticsAndDataRecords();
});
}
void WebResourceLoadStatisticsStore::resourceLoadStatisticsUpdated(Vector<WebCore::ResourceLoadStatistics>&& origins)
{
ASSERT(RunLoop::isMain());
postTask([this, origins = WTFMove(origins)]() mutable {
if (!m_memoryStore)
return;
m_memoryStore->mergeStatistics(WTFMove(origins));
m_memoryStore->cancelPendingStatisticsProcessingRequest();
m_memoryStore->updateCookiePartitioning([]() { });
m_memoryStore->processStatisticsAndDataRecords();
});
}
void WebResourceLoadStatisticsStore::hasStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, CompletionHandler<void (bool)>&& completionHandler)
{
ASSERT(subFrameHost != topFrameHost);
ASSERT(RunLoop::isMain());
postTask([this, subFramePrimaryDomain = isolatedPrimaryDomain(subFrameHost), topFramePrimaryDomain = isolatedPrimaryDomain(topFrameHost), frameID, pageID, completionHandler = WTFMove(completionHandler)] () mutable {
if (!m_memoryStore) {
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler(false);
});
return;
}
m_memoryStore->hasStorageAccess(subFramePrimaryDomain, topFramePrimaryDomain, frameID, pageID, [completionHandler = WTFMove(completionHandler)](bool hasStorageAccess) mutable {
postTaskReply([completionHandler = WTFMove(completionHandler), hasStorageAccess] {
completionHandler(hasStorageAccess);
});
});
});
}
void WebResourceLoadStatisticsStore::callHasStorageAccessForFrameHandler(const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, CompletionHandler<void(bool hasAccess)>&& callback)
{
ASSERT(RunLoop::isMain());
#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
if (m_websiteDataStore) {
m_websiteDataStore->hasStorageAccessForFrameHandler(resourceDomain, firstPartyDomain, frameID, pageID, WTFMove(callback));
return;
}
#endif
callback(false);
}
void WebResourceLoadStatisticsStore::requestStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool promptEnabled, CompletionHandler<void(StorageAccessStatus)>&& completionHandler)
{
ASSERT(subFrameHost != topFrameHost);
ASSERT(RunLoop::isMain());
auto subFramePrimaryDomain = isolatedPrimaryDomain(subFrameHost);
auto topFramePrimaryDomain = isolatedPrimaryDomain(topFrameHost);
if (subFramePrimaryDomain == topFramePrimaryDomain) {
completionHandler(StorageAccessStatus::HasAccess);
return;
}
postTask([this, subFramePrimaryDomain = crossThreadCopy(subFramePrimaryDomain), topFramePrimaryDomain = crossThreadCopy(topFramePrimaryDomain), frameID, pageID, promptEnabled, completionHandler = WTFMove(completionHandler)] () mutable {
if (!m_memoryStore) {
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler(StorageAccessStatus::CannotRequestAccess);
});
return;
}
m_memoryStore->requestStorageAccess(WTFMove(subFramePrimaryDomain), WTFMove(topFramePrimaryDomain), frameID, pageID, promptEnabled, [completionHandler = WTFMove(completionHandler)](StorageAccessStatus status) mutable {
postTaskReply([completionHandler = WTFMove(completionHandler), status] {
completionHandler(status);
});
});
});
}
void WebResourceLoadStatisticsStore::requestStorageAccessUnderOpener(String&& primaryDomainInNeedOfStorageAccess, uint64_t openerPageID, String&& openerPrimaryDomain, bool isTriggeredByUserGesture)
{
ASSERT(RunLoop::isMain());
postTask([this, primaryDomainInNeedOfStorageAccess = WTFMove(primaryDomainInNeedOfStorageAccess), openerPageID, openerPrimaryDomain = WTFMove(openerPrimaryDomain), isTriggeredByUserGesture]() mutable {
if (m_memoryStore)
m_memoryStore->requestStorageAccessUnderOpener(WTFMove(primaryDomainInNeedOfStorageAccess), openerPageID, WTFMove(openerPrimaryDomain), isTriggeredByUserGesture);
});
}
void WebResourceLoadStatisticsStore::grantStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool userWasPromptedNow, CompletionHandler<void(bool)>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, subFrameHost = crossThreadCopy(subFrameHost), topFrameHost = crossThreadCopy(topFrameHost), frameID, pageID, userWasPromptedNow, completionHandler = WTFMove(completionHandler)] () mutable {
if (!m_memoryStore) {
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler(false);
});
return;
}
m_memoryStore->grantStorageAccess(WTFMove(subFrameHost), WTFMove(topFrameHost), frameID, pageID, userWasPromptedNow, [completionHandler = WTFMove(completionHandler)](bool wasGrantedAccess) mutable {
postTaskReply([completionHandler = WTFMove(completionHandler), wasGrantedAccess] {
completionHandler(wasGrantedAccess);
});
});
});
}
void WebResourceLoadStatisticsStore::callGrantStorageAccessHandler(const String& subFramePrimaryDomain, const String& topFramePrimaryDomain, std::optional<uint64_t> frameID, uint64_t pageID, CompletionHandler<void(bool)>&& callback)
{
ASSERT(RunLoop::isMain());
#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
if (m_websiteDataStore) {
m_websiteDataStore->grantStorageAccessHandler(subFramePrimaryDomain, topFramePrimaryDomain, frameID, pageID, WTFMove(callback));
return;
}
#endif
callback(false);
}
void WebResourceLoadStatisticsStore::didCreateNetworkProcess()
{
ASSERT(RunLoop::isMain());
postTask([this] {
if (!m_memoryStore)
return;
m_memoryStore->didCreateNetworkProcess();
});
}
void WebResourceLoadStatisticsStore::removeAllStorageAccess()
{
ASSERT(RunLoop::isMain());
#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
if (m_websiteDataStore)
m_websiteDataStore->removeAllStorageAccessHandler();
#endif
}
void WebResourceLoadStatisticsStore::applicationWillTerminate()
{
flushAndDestroyPersistentStore();
}
void WebResourceLoadStatisticsStore::performDailyTasks()
{
ASSERT(RunLoop::isMain());
postTask([this] {
if (!m_memoryStore)
return;
m_memoryStore->includeTodayAsOperatingDateIfNecessary();
m_memoryStore->calculateAndSubmitTelemetry();
});
}
void WebResourceLoadStatisticsStore::submitTelemetry()
{
ASSERT(RunLoop::isMain());
postTask([this] {
if (m_memoryStore)
WebResourceLoadStatisticsTelemetry::calculateAndSubmit(*m_memoryStore);
});
}
void WebResourceLoadStatisticsStore::logFrameNavigation(const WebFrameProxy& frame, const URL& pageURL, const WebCore::ResourceRequest& request, const WebCore::URL& redirectURL)
{
ASSERT(RunLoop::isMain());
auto sourceURL = redirectURL;
bool isRedirect = !redirectURL.isNull();
if (!isRedirect) {
sourceURL = frame.url();
if (sourceURL.isNull())
sourceURL = pageURL;
}
auto& targetURL = request.url();
if (!targetURL.isValid() || !pageURL.isValid())
return;
auto targetHost = targetURL.host();
auto mainFrameHost = pageURL.host();
if (targetHost.isEmpty() || mainFrameHost.isEmpty() || targetHost == sourceURL.host())
return;
auto* page = frame.page();
auto targetPrimaryDomain = ResourceLoadStatistics::primaryDomain(targetURL);
auto mainFramePrimaryDomain = ResourceLoadStatistics::primaryDomain(pageURL);
auto sourcePrimaryDomain = ResourceLoadStatistics::primaryDomain(sourceURL);
bool areTargetAndMainFrameDomainsAssociated = areDomainsAssociated(page, targetPrimaryDomain, mainFramePrimaryDomain);
bool areTargetAndSourceDomainsAssociated = areDomainsAssociated(page, targetPrimaryDomain, sourcePrimaryDomain);
postTask([this, targetPrimaryDomain = targetPrimaryDomain.isolatedCopy(), mainFramePrimaryDomain = mainFramePrimaryDomain.isolatedCopy(), sourcePrimaryDomain = sourcePrimaryDomain.isolatedCopy(), targetHost = targetHost.toString().isolatedCopy(), mainFrameHost = mainFrameHost.toString().isolatedCopy(), areTargetAndMainFrameDomainsAssociated, areTargetAndSourceDomainsAssociated, isRedirect, isMainFrame = frame.isMainFrame()] {
if (m_memoryStore)
m_memoryStore->logFrameNavigation(targetPrimaryDomain, mainFramePrimaryDomain, sourcePrimaryDomain, targetHost, mainFrameHost, areTargetAndMainFrameDomainsAssociated, areTargetAndSourceDomainsAssociated, isRedirect, isMainFrame);
});
}
void WebResourceLoadStatisticsStore::logUserInteraction(const URL& url, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler();
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->logUserInteraction(primaryDomain);
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::logNonRecentUserInteraction(const URL& url, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler();
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->logNonRecentUserInteraction(primaryDomain);
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::clearUserInteraction(const URL& url, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler();
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->clearUserInteraction(primaryDomain);
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::hasHadUserInteraction(const URL& url, CompletionHandler<void (bool)>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler(false);
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)] () mutable {
bool hadUserInteraction = m_memoryStore ? m_memoryStore->hasHadUserInteraction(primaryDomain) : false;
postTaskReply([hadUserInteraction, completionHandler = WTFMove(completionHandler)] {
completionHandler(hadUserInteraction);
});
});
}
void WebResourceLoadStatisticsStore::setLastSeen(const URL& url, Seconds seconds, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler();
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), seconds, completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->setLastSeen(primaryDomain, seconds);
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::setPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler();
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->setPrevalentResource(primaryDomain);
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::setVeryPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler();
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->setVeryPrevalentResource(primaryDomain);
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::isPrevalentResource(const URL& url, CompletionHandler<void (bool)>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler(false);
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)] () mutable {
bool isPrevalentResource = m_memoryStore ? m_memoryStore->isPrevalentResource(primaryDomain) : false;
postTaskReply([isPrevalentResource, completionHandler = WTFMove(completionHandler)] {
completionHandler(isPrevalentResource);
});
});
}
void WebResourceLoadStatisticsStore::isVeryPrevalentResource(const URL& url, CompletionHandler<void(bool)>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler(false);
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)] () mutable {
bool isVeryPrevalentResource = m_memoryStore ? m_memoryStore->isVeryPrevalentResource(primaryDomain) : false;
postTaskReply([isVeryPrevalentResource, completionHandler = WTFMove(completionHandler)] {
completionHandler(isVeryPrevalentResource);
});
});
}
void WebResourceLoadStatisticsStore::isRegisteredAsSubFrameUnder(const URL& subFrame, const URL& topFrame, CompletionHandler<void (bool)>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, subFramePrimaryDomain = isolatedPrimaryDomain(subFrame), topFramePrimaryDomain = isolatedPrimaryDomain(topFrame), completionHandler = WTFMove(completionHandler)] () mutable {
bool isRegisteredAsSubFrameUnder = m_memoryStore ? m_memoryStore->isRegisteredAsSubFrameUnder(subFramePrimaryDomain, topFramePrimaryDomain) : false;
postTaskReply([isRegisteredAsSubFrameUnder, completionHandler = WTFMove(completionHandler)] {
completionHandler(isRegisteredAsSubFrameUnder);
});
});
}
void WebResourceLoadStatisticsStore::isRegisteredAsRedirectingTo(const URL& hostRedirectedFrom, const URL& hostRedirectedTo, CompletionHandler<void (bool)>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, hostRedirectedFromPrimaryDomain = isolatedPrimaryDomain(hostRedirectedFrom), hostRedirectedToPrimaryDomain = isolatedPrimaryDomain(hostRedirectedTo), completionHandler = WTFMove(completionHandler)] () mutable {
bool isRegisteredAsRedirectingTo = m_memoryStore ? m_memoryStore->isRegisteredAsRedirectingTo(hostRedirectedFromPrimaryDomain, hostRedirectedToPrimaryDomain) : false;
postTaskReply([isRegisteredAsRedirectingTo, completionHandler = WTFMove(completionHandler)] {
completionHandler(isRegisteredAsRedirectingTo);
});
});
}
void WebResourceLoadStatisticsStore::clearPrevalentResource(const URL& url, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler();
return;
}
postTask([this, primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->clearPrevalentResource(primaryDomain);
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::setGrandfathered(const URL& url, bool value)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty())
return;
postTask([this, primaryDomain = isolatedPrimaryDomain(url), value] {
if (m_memoryStore)
m_memoryStore->setGrandfathered(primaryDomain, value);
});
}
void WebResourceLoadStatisticsStore::isGrandfathered(const URL& url, CompletionHandler<void (bool)>&& completionHandler)
{
ASSERT(RunLoop::isMain());
if (url.isBlankURL() || url.isEmpty()) {
completionHandler(false);
return;
}
postTask([this, completionHandler = WTFMove(completionHandler), primaryDomain = isolatedPrimaryDomain(url)] () mutable {
bool isGrandFathered = m_memoryStore ? m_memoryStore->isGrandfathered(primaryDomain) : false;
postTaskReply([isGrandFathered, completionHandler = WTFMove(completionHandler)] {
completionHandler(isGrandFathered);
});
});
}
void WebResourceLoadStatisticsStore::setSubframeUnderTopFrameOrigin(const URL& subframe, const URL& topFrame)
{
ASSERT(RunLoop::isMain());
if (subframe.isBlankURL() || subframe.isEmpty() || topFrame.isBlankURL() || topFrame.isEmpty())
return;
postTask([this, primaryTopFrameDomain = isolatedPrimaryDomain(topFrame), primarySubFrameDomain = isolatedPrimaryDomain(subframe)] {
if (m_memoryStore)
m_memoryStore->setSubframeUnderTopFrameOrigin(primarySubFrameDomain, primaryTopFrameDomain);
});
}
void WebResourceLoadStatisticsStore::setSubresourceUnderTopFrameOrigin(const URL& subresource, const URL& topFrame)
{
ASSERT(RunLoop::isMain());
if (subresource.isBlankURL() || subresource.isEmpty() || topFrame.isBlankURL() || topFrame.isEmpty())
return;
postTask([this, primaryTopFrameDomain = isolatedPrimaryDomain(topFrame), primarySubresourceDomain = isolatedPrimaryDomain(subresource)] {
if (m_memoryStore)
m_memoryStore->setSubresourceUnderTopFrameOrigin(primarySubresourceDomain, primaryTopFrameDomain);
});
}
void WebResourceLoadStatisticsStore::setSubresourceUniqueRedirectTo(const URL& subresource, const URL& hostNameRedirectedTo)
{
ASSERT(RunLoop::isMain());
if (subresource.isBlankURL() || subresource.isEmpty() || hostNameRedirectedTo.isBlankURL() || hostNameRedirectedTo.isEmpty())
return;
postTask([this, primaryRedirectDomain = isolatedPrimaryDomain(hostNameRedirectedTo), primarySubresourceDomain = isolatedPrimaryDomain(subresource)] {
if (m_memoryStore)
m_memoryStore->setSubresourceUniqueRedirectTo(primarySubresourceDomain, primaryRedirectDomain);
});
}
void WebResourceLoadStatisticsStore::setSubresourceUniqueRedirectFrom(const URL& subresource, const URL& hostNameRedirectedFrom)
{
ASSERT(RunLoop::isMain());
if (subresource.isBlankURL() || subresource.isEmpty() || hostNameRedirectedFrom.isBlankURL() || hostNameRedirectedFrom.isEmpty())
return;
postTask([this, primaryRedirectDomain = isolatedPrimaryDomain(hostNameRedirectedFrom), primarySubresourceDomain = isolatedPrimaryDomain(subresource)] {
if (m_memoryStore)
m_memoryStore->setSubresourceUniqueRedirectFrom(primarySubresourceDomain, primaryRedirectDomain);
});
}
void WebResourceLoadStatisticsStore::setTopFrameUniqueRedirectTo(const URL& topFrameHostName, const URL& hostNameRedirectedTo)
{
ASSERT(RunLoop::isMain());
if (topFrameHostName.isBlankURL() || topFrameHostName.isEmpty() || hostNameRedirectedTo.isBlankURL() || hostNameRedirectedTo.isEmpty())
return;
postTask([this, primaryRedirectDomain = isolatedPrimaryDomain(hostNameRedirectedTo), topFramePrimaryDomain = isolatedPrimaryDomain(topFrameHostName)] {
if (m_memoryStore)
m_memoryStore->setTopFrameUniqueRedirectTo(topFramePrimaryDomain, primaryRedirectDomain);
});
}
void WebResourceLoadStatisticsStore::setTopFrameUniqueRedirectFrom(const URL& topFrameHostName, const URL& hostNameRedirectedFrom)
{
ASSERT(RunLoop::isMain());
if (topFrameHostName.isBlankURL() || topFrameHostName.isEmpty() || hostNameRedirectedFrom.isBlankURL() || hostNameRedirectedFrom.isEmpty())
return;
postTask([this, primaryRedirectDomain = isolatedPrimaryDomain(hostNameRedirectedFrom), topFramePrimaryDomain = isolatedPrimaryDomain(topFrameHostName)] {
if (m_memoryStore)
m_memoryStore->setTopFrameUniqueRedirectFrom(topFramePrimaryDomain, primaryRedirectDomain);
});
}
void WebResourceLoadStatisticsStore::scheduleCookiePartitioningUpdate(CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, completionHandler = WTFMove(completionHandler)] () mutable {
if (!m_memoryStore) {
postTaskReply([completionHandler = WTFMove(completionHandler)]() {
completionHandler();
});
return;
}
m_memoryStore->updateCookiePartitioning([completionHandler = WTFMove(completionHandler)]() mutable {
postTaskReply([completionHandler = WTFMove(completionHandler)]() {
completionHandler();
});
});
});
}
void WebResourceLoadStatisticsStore::scheduleCookiePartitioningUpdateForDomains(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst shouldClearFirst, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, domainsToPartition = crossThreadCopy(domainsToPartition), domainsToBlock = crossThreadCopy(domainsToBlock), domainsToNeitherPartitionNorBlock = crossThreadCopy(domainsToNeitherPartitionNorBlock), shouldClearFirst, completionHandler = WTFMove(completionHandler)] () mutable {
if (!m_memoryStore) {
postTaskReply([completionHandler = WTFMove(completionHandler)]() {
completionHandler();
});
return;
}
m_memoryStore->updateCookiePartitioningForDomains(domainsToPartition, domainsToBlock, domainsToNeitherPartitionNorBlock, shouldClearFirst, [completionHandler = WTFMove(completionHandler)]() mutable {
postTaskReply([completionHandler = WTFMove(completionHandler)]() {
completionHandler();
});
});
});
}
void WebResourceLoadStatisticsStore::scheduleClearPartitioningStateForDomains(const Vector<String>& domains, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, domains = crossThreadCopy(domains), completionHandler = WTFMove(completionHandler)] () mutable {
if (!m_memoryStore) {
postTaskReply([completionHandler = WTFMove(completionHandler)]() {
completionHandler();
});
return;
}
m_memoryStore->clearPartitioningStateForDomains(domains, [completionHandler = WTFMove(completionHandler)]() mutable {
postTaskReply([completionHandler = WTFMove(completionHandler)]() {
completionHandler();
});
});
});
}
#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
void WebResourceLoadStatisticsStore::scheduleCookiePartitioningStateReset()
{
ASSERT(RunLoop::isMain());
postTask([this] {
if (m_memoryStore)
m_memoryStore->resetCookiePartitioningState();
});
}
#endif
void WebResourceLoadStatisticsStore::scheduleClearInMemory(CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->clear();
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::scheduleClearInMemoryAndPersistent(ShouldGrandfather shouldGrandfather, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, shouldGrandfather, completionHandler = WTFMove(completionHandler)] () mutable {
if (m_memoryStore)
m_memoryStore->clear();
if (m_persistentStorage)
m_persistentStorage->clear();
CompletionHandler<void()> callCompletionHandlerOnMainThread = [completionHandler = WTFMove(completionHandler)]() mutable {
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
};
if (shouldGrandfather == ShouldGrandfather::Yes && m_memoryStore)
m_memoryStore->grandfatherExistingWebsiteData(WTFMove(callCompletionHandlerOnMainThread));
else
callCompletionHandlerOnMainThread();
});
}
void WebResourceLoadStatisticsStore::scheduleClearInMemoryAndPersistent(WallTime modifiedSince, ShouldGrandfather shouldGrandfather, CompletionHandler<void()>&& callback)
{
ASSERT(RunLoop::isMain());
UNUSED_PARAM(modifiedSince);
scheduleClearInMemoryAndPersistent(shouldGrandfather, WTFMove(callback));
}
void WebResourceLoadStatisticsStore::setTimeToLiveUserInteraction(Seconds seconds)
{
ASSERT(RunLoop::isMain());
postTask([this, seconds] {
if (m_memoryStore)
m_memoryStore->setTimeToLiveUserInteraction(seconds);
});
}
void WebResourceLoadStatisticsStore::setTimeToLiveCookiePartitionFree(Seconds seconds)
{
ASSERT(RunLoop::isMain());
postTask([this, seconds] {
if (m_memoryStore)
m_memoryStore->setTimeToLiveCookiePartitionFree(seconds);
});
}
void WebResourceLoadStatisticsStore::setMinimumTimeBetweenDataRecordsRemoval(Seconds seconds)
{
ASSERT(RunLoop::isMain());
postTask([this, seconds] {
if (m_memoryStore)
m_memoryStore->setMinimumTimeBetweenDataRecordsRemoval(seconds);
});
}
void WebResourceLoadStatisticsStore::setGrandfatheringTime(Seconds seconds)
{
ASSERT(RunLoop::isMain());
postTask([this, seconds] {
if (m_memoryStore)
m_memoryStore->setGrandfatheringTime(seconds);
});
}
void WebResourceLoadStatisticsStore::callUpdatePrevalentDomainsToPartitionOrBlockCookiesHandler(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst shouldClearFirst, CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
if (m_websiteDataStore) {
m_websiteDataStore->updatePrevalentDomainsToPartitionOrBlockCookies(domainsToPartition, domainsToBlock, domainsToNeitherPartitionNorBlock, shouldClearFirst, WTFMove(completionHandler));
return;
}
#endif
completionHandler();
}
void WebResourceLoadStatisticsStore::callRemoveDomainsHandler(const Vector<String>& domains)
{
ASSERT(RunLoop::isMain());
#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
if (m_websiteDataStore)
m_websiteDataStore->removePrevalentDomains(domains);
#endif
}
void WebResourceLoadStatisticsStore::setMaxStatisticsEntries(size_t maximumEntryCount)
{
ASSERT(RunLoop::isMain());
postTask([this, maximumEntryCount] {
if (m_memoryStore)
m_memoryStore->setMaxStatisticsEntries(maximumEntryCount);
});
}
void WebResourceLoadStatisticsStore::setPruneEntriesDownTo(size_t pruneTargetCount)
{
ASSERT(RunLoop::isMain());
postTask([this, pruneTargetCount] {
if (m_memoryStore)
m_memoryStore->setPruneEntriesDownTo(pruneTargetCount);
});
}
void WebResourceLoadStatisticsStore::resetParametersToDefaultValues(CompletionHandler<void()>&& completionHandler)
{
ASSERT(RunLoop::isMain());
postTask([this, completionHandler = WTFMove(completionHandler)]() mutable {
if (m_memoryStore)
m_memoryStore->resetParametersToDefaultValues();
postTaskReply([completionHandler = WTFMove(completionHandler)] {
completionHandler();
});
});
}
void WebResourceLoadStatisticsStore::logTestingEvent(const String& event)
{
ASSERT(RunLoop::isMain());
if (m_statisticsTestingCallback)
m_statisticsTestingCallback(event);
}
}