blob: f67b6288ce49b57df6328146ec65f032aa46521d [file] [log] [blame]
/*
* Copyright (C) 2016-2018 Apple Inc. All rights reserved.
*
* 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.
*/
#pragma once
#include "Connection.h"
#include "ResourceLoadStatisticsClassifier.h"
#include "ResourceLoadStatisticsPersistentStorage.h"
#include "WebsiteDataType.h"
#include <wtf/CompletionHandler.h>
#include <wtf/HashSet.h>
#include <wtf/MonotonicTime.h>
#include <wtf/RunLoop.h>
#include <wtf/Vector.h>
#include <wtf/WallTime.h>
#include <wtf/text/WTFString.h>
#if HAVE(CORE_PREDICTION)
#include "ResourceLoadStatisticsClassifierCocoa.h"
#endif
namespace WTF {
class WorkQueue;
}
namespace WebCore {
class KeyedDecoder;
class KeyedEncoder;
class URL;
struct ResourceLoadStatistics;
}
namespace WebKit {
class OperatingDate;
class WebProcessProxy;
enum class ShouldClearFirst;
class WebResourceLoadStatisticsStore final : public IPC::Connection::WorkQueueMessageReceiver {
public:
using UpdatePrevalentDomainsToPartitionOrBlockCookiesHandler = WTF::Function<void(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst)>;
using HasStorageAccessForFrameHandler = WTF::Function<void(const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, WTF::Function<void(bool hasAccess)>&& callback)>;
using GrantStorageAccessHandler = WTF::Function<void(const String& resourceDomain, const String& firstPartyDomain, std::optional<uint64_t> frameID, uint64_t pageID, WTF::Function<void(bool wasGranted)>&& callback)>;
using RemoveAllStorageAccessHandler = WTF::Function<void()>;
using RemovePrevalentDomainsHandler = WTF::Function<void (const Vector<String>&)>;
static Ref<WebResourceLoadStatisticsStore> create(const String& resourceLoadStatisticsDirectory, Function<void (const String&)>&& testingCallback, bool isEphemeral, UpdatePrevalentDomainsToPartitionOrBlockCookiesHandler&& updatePrevalentDomainsToPartitionOrBlockCookiesHandler = [](const WTF::Vector<String>&, const WTF::Vector<String>&, const WTF::Vector<String>&, ShouldClearFirst) { }, HasStorageAccessForFrameHandler&& hasStorageAccessForFrameHandler = [](const String&, const String&, uint64_t, uint64_t, WTF::Function<void(bool)>&&) { }, GrantStorageAccessHandler&& grantStorageAccessHandler = [](const String&, const String&, std::optional<uint64_t>, uint64_t, WTF::Function<void(bool)>&&) { }, RemoveAllStorageAccessHandler&& removeAllStorageAccessHandler = []() { }, RemovePrevalentDomainsHandler&& removeDomainsHandler = [] (const WTF::Vector<String>&) { })
{
return adoptRef(*new WebResourceLoadStatisticsStore(resourceLoadStatisticsDirectory, WTFMove(testingCallback), isEphemeral, WTFMove(updatePrevalentDomainsToPartitionOrBlockCookiesHandler), WTFMove(hasStorageAccessForFrameHandler), WTFMove(grantStorageAccessHandler), WTFMove(removeAllStorageAccessHandler), WTFMove(removeDomainsHandler)));
}
~WebResourceLoadStatisticsStore();
static const OptionSet<WebsiteDataType>& monitoredDataTypes();
bool isEmpty() const { return m_resourceStatisticsMap.isEmpty(); }
WorkQueue& statisticsQueue() { return m_statisticsQueue.get(); }
void setNotifyPagesWhenDataRecordsWereScanned(bool value) { m_parameters.shouldNotifyPagesWhenDataRecordsWereScanned = value; }
void setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value) { m_parameters.shouldClassifyResourcesBeforeDataRecordsRemoval = value; }
void setShouldSubmitTelemetry(bool value) { m_parameters.shouldSubmitTelemetry = value; }
void resourceLoadStatisticsUpdated(Vector<WebCore::ResourceLoadStatistics>&& origins);
void hasStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void (bool)>&& callback);
void requestStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void (bool)>&& callback);
void requestStorageAccessUnderOpener(String&& domainInNeedOfStorageAccess, uint64_t openerPageID, String&& openerDomain, bool isTriggeredByUserGesture);
void requestStorageAccessCallback(bool wasGranted, uint64_t contextId);
void processWillOpenConnection(WebProcessProxy&, IPC::Connection&);
void processDidCloseConnection(WebProcessProxy&, IPC::Connection&);
void applicationWillTerminate();
void logUserInteraction(const WebCore::URL&);
void logNonRecentUserInteraction(const WebCore::URL&);
void clearUserInteraction(const WebCore::URL&);
void hasHadUserInteraction(const WebCore::URL&, WTF::Function<void (bool)>&&);
void setLastSeen(const WebCore::URL&, Seconds);
void setPrevalentResource(const WebCore::URL&);
void setVeryPrevalentResource(const WebCore::URL&);
void isPrevalentResource(const WebCore::URL&, WTF::Function<void (bool)>&&);
void isVeryPrevalentResource(const WebCore::URL&, WTF::Function<void(bool)>&&);
void isRegisteredAsSubFrameUnder(const WebCore::URL& subFrame, const WebCore::URL& topFrame, WTF::Function<void (bool)>&&);
void isRegisteredAsRedirectingTo(const WebCore::URL& hostRedirectedFrom, const WebCore::URL& hostRedirectedTo, WTF::Function<void (bool)>&&);
void clearPrevalentResource(const WebCore::URL&);
void setGrandfathered(const WebCore::URL&, bool);
void isGrandfathered(const WebCore::URL&, WTF::Function<void (bool)>&&);
void setSubframeUnderTopFrameOrigin(const WebCore::URL& subframe, const WebCore::URL& topFrame);
void setSubresourceUnderTopFrameOrigin(const WebCore::URL& subresource, const WebCore::URL& topFrame);
void setSubresourceUniqueRedirectTo(const WebCore::URL& subresource, const WebCore::URL& hostNameRedirectedTo);
void setSubresourceUniqueRedirectFrom(const WebCore::URL& subresource, const WebCore::URL& hostNameRedirectedFrom);
void setTopFrameUniqueRedirectTo(const WebCore::URL& topFrameHostName, const WebCore::URL& hostNameRedirectedTo);
void setTopFrameUniqueRedirectFrom(const WebCore::URL& topFrameHostName, const WebCore::URL& hostNameRedirectedFrom);
void scheduleCookiePartitioningUpdate(CompletionHandler<void()>&&);
void scheduleCookiePartitioningUpdateForDomains(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst, CompletionHandler<void()>&&);
void scheduleClearPartitioningStateForDomains(const Vector<String>& domains, CompletionHandler<void()>&&);
void scheduleStatisticsAndDataRecordsProcessing();
void submitTelemetry();
void scheduleCookiePartitioningStateReset();
void scheduleClearInMemory();
enum class ShouldGrandfather {
No,
Yes,
};
void scheduleClearInMemoryAndPersistent(ShouldGrandfather, CompletionHandler<void()>&&);
void scheduleClearInMemoryAndPersistent(WallTime modifiedSince, ShouldGrandfather, CompletionHandler<void()>&&);
void setTimeToLiveUserInteraction(Seconds);
void setTimeToLiveCookiePartitionFree(Seconds);
void setMinimumTimeBetweenDataRecordsRemoval(Seconds);
void setGrandfatheringTime(Seconds);
void setMaxStatisticsEntries(size_t);
void setPruneEntriesDownTo(size_t);
void processStatistics(const WTF::Function<void (const WebCore::ResourceLoadStatistics&)>&) const;
void pruneStatisticsIfNeeded();
void resetParametersToDefaultValues();
std::unique_ptr<WebCore::KeyedEncoder> createEncoderFromData() const;
void mergeWithDataFromDecoder(WebCore::KeyedDecoder&);
void clearInMemory();
void grandfatherExistingWebsiteData(CompletionHandler<void()>&&);
void setResourceLoadStatisticsDebugMode(bool);
void setStatisticsTestingCallback(Function<void (const String&)>&& callback) { m_statisticsTestingCallback = WTFMove(callback); }
void logTestingEvent(const String&);
private:
WebResourceLoadStatisticsStore(const String&, Function<void(const String&)>&& testingCallback, bool isEphemeral, UpdatePrevalentDomainsToPartitionOrBlockCookiesHandler&&, HasStorageAccessForFrameHandler&&, GrantStorageAccessHandler&&, RemoveAllStorageAccessHandler&&, RemovePrevalentDomainsHandler&&);
void removeDataRecords(CompletionHandler<void()>&&);
// IPC::MessageReceiver
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
void performDailyTasks();
bool shouldRemoveDataRecords() const;
void setDataRecordsBeingRemoved(bool);
bool shouldPartitionCookies(const WebCore::ResourceLoadStatistics&) const;
bool shouldBlockCookies(const WebCore::ResourceLoadStatistics&) const;
bool hasStatisticsExpired(const WebCore::ResourceLoadStatistics&) const;
bool hasHadUnexpiredRecentUserInteraction(WebCore::ResourceLoadStatistics&) const;
void includeTodayAsOperatingDateIfNecessary();
Vector<String> topPrivatelyControlledDomainsToRemoveWebsiteDataFor();
void updateCookiePartitioning(CompletionHandler<void()>&&);
void updateCookiePartitioningForDomains(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst, CompletionHandler<void()>&&);
void clearPartitioningStateForDomains(const Vector<String>& domains, CompletionHandler<void()>&&);
void mergeStatistics(Vector<WebCore::ResourceLoadStatistics>&&);
WebCore::ResourceLoadStatistics& ensureResourceStatisticsForPrimaryDomain(const String&);
unsigned recursivelyGetAllDomainsThatHaveRedirectedToThisDomain(const WebCore::ResourceLoadStatistics&, HashSet<String>& domainsThatHaveRedirectedTo, unsigned numberOfRecursiveCalls);
void setPrevalentResource(WebCore::ResourceLoadStatistics&, ResourceLoadPrevalence);
void processStatisticsAndDataRecords();
void resetCookiePartitioningState();
void removeAllStorageAccess();
void setDebugLogggingEnabled(bool enabled) { m_debugLoggingEnabled = enabled; }
#if PLATFORM(COCOA)
void registerUserDefaultsIfNeeded();
#endif
bool wasAccessedAsFirstPartyDueToUserInteraction(const WebCore::ResourceLoadStatistics& current, const WebCore::ResourceLoadStatistics& updated);
struct Parameters {
size_t pruneEntriesDownTo { 800 };
size_t maxStatisticsEntries { 1000 };
std::optional<Seconds> timeToLiveUserInteraction;
Seconds timeToLiveCookiePartitionFree { 24_h };
Seconds minimumTimeBetweenDataRecordsRemoval { 1_h };
Seconds grandfatheringTime { 24_h * 7 };
bool shouldNotifyPagesWhenDataRecordsWereScanned { false };
bool shouldClassifyResourcesBeforeDataRecordsRemoval { true };
bool shouldSubmitTelemetry { true };
};
HashMap<String, WebCore::ResourceLoadStatistics> m_resourceStatisticsMap;
#if HAVE(CORE_PREDICTION)
ResourceLoadStatisticsClassifierCocoa m_resourceLoadStatisticsClassifier;
#else
ResourceLoadStatisticsClassifier m_resourceLoadStatisticsClassifier;
#endif
Ref<WTF::WorkQueue> m_statisticsQueue;
ResourceLoadStatisticsPersistentStorage m_persistentStorage;
Vector<OperatingDate> m_operatingDates;
UpdatePrevalentDomainsToPartitionOrBlockCookiesHandler m_updatePrevalentDomainsToPartitionOrBlockCookiesHandler;
HasStorageAccessForFrameHandler m_hasStorageAccessForFrameHandler;
GrantStorageAccessHandler m_grantStorageAccessHandler;
RemoveAllStorageAccessHandler m_removeAllStorageAccessHandler;
RemovePrevalentDomainsHandler m_removeDomainsHandler;
WallTime m_endOfGrandfatheringTimestamp;
RunLoop::Timer<WebResourceLoadStatisticsStore> m_dailyTasksTimer;
MonotonicTime m_lastTimeDataRecordsWereRemoved;
Parameters m_parameters;
#if ENABLE(NETSCAPE_PLUGIN_API)
HashSet<uint64_t> m_activePluginTokens;
#endif
bool m_dataRecordsBeingRemoved { false };
bool m_debugModeEnabled { false };
bool m_debugLoggingEnabled { false };
Function<void (const String&)> m_statisticsTestingCallback;
};
} // namespace WebKit