Add SPI to configure WebsiteDataStores with a URL for standalone web applications...
[WebKit-https.git] / Source / WebKit / NetworkProcess / Classifier / ResourceLoadStatisticsStore.h
1 /*
2  * Copyright (C) 2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #if ENABLE(RESOURCE_LOAD_STATISTICS)
29
30 #include "ResourceLoadStatisticsClassifier.h"
31 #include "WebResourceLoadStatisticsStore.h"
32 #include <JavaScriptCore/ConsoleTypes.h>
33 #include <WebCore/FrameIdentifier.h>
34 #include <wtf/CompletionHandler.h>
35 #include <wtf/Vector.h>
36 #include <wtf/WeakPtr.h>
37 #include <wtf/WorkQueue.h>
38
39 #if HAVE(CORE_PREDICTION)
40 #include "ResourceLoadStatisticsClassifierCocoa.h"
41 #endif
42
43 namespace WebCore {
44 class KeyedDecoder;
45 class KeyedEncoder;
46 enum class StorageAccessPromptWasShown : bool;
47 enum class StorageAccessWasGranted : bool;
48 struct ResourceLoadStatistics;
49 }
50
51 namespace WebKit {
52
53 class ResourceLoadStatisticsPersistentStorage;
54
55 class OperatingDate {
56 public:
57     OperatingDate() = default;
58     
59     static OperatingDate fromWallTime(WallTime);
60     static OperatingDate today();
61     Seconds secondsSinceEpoch() const;
62     bool operator==(const OperatingDate& other) const;
63     bool operator<(const OperatingDate& other) const;
64     bool operator<=(const OperatingDate& other) const;
65     
66 private:
67     OperatingDate(int year, int month, int monthDay)
68         : m_year(year)
69         , m_month(month)
70         , m_monthDay(monthDay)
71     { }
72
73     int m_year { 0 };
74     int m_month { 0 }; // [0, 11].
75     int m_monthDay { 0 }; // [1, 31].
76 };
77
78 enum class OperatingDatesWindow : uint8_t { Long, Short, ForLiveOnTesting, ForReproTesting };
79 enum class CookieAccess : uint8_t { CannotRequest, BasedOnCookiePolicy, OnlyIfGranted };
80
81 // This is always constructed / used / destroyed on the WebResourceLoadStatisticsStore's statistics queue.
82 class ResourceLoadStatisticsStore : public CanMakeWeakPtr<ResourceLoadStatisticsStore> {
83     WTF_MAKE_FAST_ALLOCATED;
84 public:
85     using ResourceLoadStatistics = WebCore::ResourceLoadStatistics;
86     using RegistrableDomain = WebCore::RegistrableDomain;
87     using TopFrameDomain = WebCore::RegistrableDomain;
88     using SubFrameDomain = WebCore::RegistrableDomain;
89     using SubResourceDomain = WebCore::RegistrableDomain;
90     using RedirectDomain = WebCore::RegistrableDomain;
91     using RedirectedFromDomain = WebCore::RegistrableDomain;
92     using RedirectedToDomain = WebCore::RegistrableDomain;
93     using NavigatedFromDomain = WebCore::RegistrableDomain;
94     using NavigatedToDomain = WebCore::RegistrableDomain;
95     using DomainInNeedOfStorageAccess = WebCore::RegistrableDomain;
96     using OpenerDomain = WebCore::RegistrableDomain;
97     
98     virtual ~ResourceLoadStatisticsStore();
99
100     virtual void clear(CompletionHandler<void()>&&) = 0;
101     virtual bool isEmpty() const = 0;
102     virtual Vector<WebResourceLoadStatisticsStore::ThirdPartyData> aggregatedThirdPartyData() const = 0;
103
104     virtual void updateCookieBlocking(CompletionHandler<void()>&&) = 0;
105     void updateCookieBlockingForDomains(const RegistrableDomainsToBlockCookiesFor&, CompletionHandler<void()>&&);
106     void clearBlockingStateForDomains(const Vector<RegistrableDomain>& domains, CompletionHandler<void()>&&);
107
108     void includeTodayAsOperatingDateIfNecessary();
109     void processStatisticsAndDataRecords();
110
111     virtual void classifyPrevalentResources() = 0;
112     virtual void syncStorageIfNeeded() = 0;
113     virtual void syncStorageImmediately() = 0;
114     virtual void mergeStatistics(Vector<ResourceLoadStatistics>&&) = 0;
115
116     virtual void requestStorageAccessUnderOpener(DomainInNeedOfStorageAccess&&, WebCore::PageIdentifier openerID, OpenerDomain&&) = 0;
117     void removeAllStorageAccess(CompletionHandler<void()>&&);
118
119     void grandfatherExistingWebsiteData(CompletionHandler<void()>&&);
120     void cancelPendingStatisticsProcessingRequest();
121
122     virtual bool isRegisteredAsSubresourceUnder(const SubResourceDomain&, const TopFrameDomain&) const = 0;
123     virtual bool isRegisteredAsSubFrameUnder(const SubFrameDomain&, const TopFrameDomain&) const = 0;
124     virtual bool isRegisteredAsRedirectingTo(const RedirectedFromDomain&, const RedirectedToDomain&) const = 0;
125
126     virtual void clearPrevalentResource(const RegistrableDomain&) = 0;
127     virtual void dumpResourceLoadStatistics(CompletionHandler<void(const String&)>&&) = 0;
128     virtual bool isPrevalentResource(const RegistrableDomain&) const = 0;
129     virtual bool isVeryPrevalentResource(const RegistrableDomain&) const = 0;
130     virtual void setPrevalentResource(const RegistrableDomain&) = 0;
131     virtual void setVeryPrevalentResource(const RegistrableDomain&) = 0;
132
133     virtual void setGrandfathered(const RegistrableDomain&, bool value) = 0;
134     virtual bool isGrandfathered(const RegistrableDomain&) const = 0;
135
136     virtual void incrementRecordsDeletedCountForDomains(HashSet<RegistrableDomain>&&) = 0;
137     virtual void grandfatherDataForDomains(const HashSet<RegistrableDomain>&) = 0;
138
139     virtual void setSubframeUnderTopFrameDomain(const SubFrameDomain&, const TopFrameDomain&) = 0;
140     virtual void setSubresourceUnderTopFrameDomain(const SubResourceDomain&, const TopFrameDomain&) = 0;
141     virtual void setSubresourceUniqueRedirectTo(const SubResourceDomain&, const RedirectDomain&) = 0;
142     virtual void setSubresourceUniqueRedirectFrom(const SubResourceDomain&, const RedirectDomain&) = 0;
143     virtual void setTopFrameUniqueRedirectTo(const TopFrameDomain&, const RedirectDomain&) = 0;
144     virtual void setTopFrameUniqueRedirectFrom(const TopFrameDomain&, const RedirectDomain&) = 0;
145
146     void logTestingEvent(const String&);
147
148     void setMaxStatisticsEntries(size_t maximumEntryCount);
149     void setPruneEntriesDownTo(size_t pruneTargetCount);
150     void resetParametersToDefaultValues();
151     Optional<Seconds> statisticsEpirationTime() const;
152
153     virtual void calculateAndSubmitTelemetry() const = 0;
154
155     void setNotifyPagesWhenDataRecordsWereScanned(bool);
156     void setIsRunningTest(bool);
157     bool shouldSkip(const RegistrableDomain&) const;
158     void setShouldClassifyResourcesBeforeDataRecordsRemoval(bool);
159     void setShouldSubmitTelemetry(bool);
160     void setTimeToLiveUserInteraction(Seconds);
161     void setMinimumTimeBetweenDataRecordsRemoval(Seconds);
162     void setGrandfatheringTime(Seconds);
163     void setResourceLoadStatisticsDebugMode(bool);
164     bool isDebugModeEnabled() const { return m_debugModeEnabled; };
165     void setPrevalentResourceForDebugMode(const RegistrableDomain&);
166     void setThirdPartyCookieBlockingMode(WebCore::ThirdPartyCookieBlockingMode mode) { m_thirdPartyCookieBlockingMode = mode; };
167     WebCore::ThirdPartyCookieBlockingMode thirdPartyCookieBlockingMode() const { return m_thirdPartyCookieBlockingMode; };
168     void setSameSiteStrictEnforcementEnabled(WebCore::SameSiteStrictEnforcementEnabled enabled) { m_sameSiteStrictEnforcementEnabled = enabled; };
169     bool isSameSiteStrictEnforcementEnabled() const { return m_sameSiteStrictEnforcementEnabled == WebCore::SameSiteStrictEnforcementEnabled::Yes; };
170     void setFirstPartyWebsiteDataRemovalMode(WebCore::FirstPartyWebsiteDataRemovalMode mode) { m_firstPartyWebsiteDataRemovalMode = mode; }
171     void setStandaloneApplicationDomain(RegistrableDomain&& domain) { m_standaloneApplicationDomain = WTFMove(domain); }
172
173     virtual bool areAllThirdPartyCookiesBlockedUnder(const TopFrameDomain&) = 0;
174     virtual void hasStorageAccess(const SubFrameDomain&, const TopFrameDomain&, Optional<WebCore::FrameIdentifier>, WebCore::PageIdentifier, CompletionHandler<void(bool)>&&) = 0;
175     virtual void requestStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, CompletionHandler<void(StorageAccessStatus)>&&) = 0;
176     virtual void grantStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&) = 0;
177
178     virtual void logFrameNavigation(const NavigatedToDomain&, const TopFrameDomain&, const NavigatedFromDomain&, bool isRedirect, bool isMainFrame, Seconds delayAfterMainFrameDocumentLoad, bool wasPotentiallyInitiatedByUser) = 0;
179     virtual void logUserInteraction(const TopFrameDomain&, CompletionHandler<void()>&&) = 0;
180     virtual void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) = 0;
181
182     virtual void clearUserInteraction(const RegistrableDomain&, CompletionHandler<void()>&&) = 0;
183     virtual bool hasHadUserInteraction(const RegistrableDomain&, OperatingDatesWindow) = 0;
184
185     virtual void setLastSeen(const RegistrableDomain& primaryDomain, Seconds) = 0;
186
187     void didCreateNetworkProcess();
188
189     const WebResourceLoadStatisticsStore& store() const { return m_store; }
190
191     static constexpr unsigned maxImportance { 3 };
192
193     virtual bool isMemoryStore() const { return false; }
194     virtual bool isDatabaseStore()const { return false; }
195
196 protected:
197     static unsigned computeImportance(const WebCore::ResourceLoadStatistics&);
198     static Vector<OperatingDate> mergeOperatingDates(const Vector<OperatingDate>& existingDates, Vector<OperatingDate>&& newDates);
199
200     ResourceLoadStatisticsStore(WebResourceLoadStatisticsStore&, WorkQueue&, ShouldIncludeLocalhost);
201     
202     bool dataRecordsBeingRemoved() const { return m_dataRecordsBeingRemoved; }
203
204     bool hasStatisticsExpired(const ResourceLoadStatistics&, OperatingDatesWindow) const;
205     bool hasStatisticsExpired(WallTime mostRecentUserInteractionTime, OperatingDatesWindow) const;
206     void scheduleStatisticsProcessingRequestIfNecessary();
207     void mergeOperatingDates(Vector<OperatingDate>&&);
208     bool shouldEnforceSameSiteStrictForSpecificDomain(const RegistrableDomain&) const;
209     virtual Vector<RegistrableDomain> ensurePrevalentResourcesForDebugMode() = 0;
210     virtual RegistrableDomainsToDeleteOrRestrictWebsiteDataFor registrableDomainsToDeleteOrRestrictWebsiteDataFor() = 0;
211     virtual void pruneStatisticsIfNeeded() = 0;
212
213     WebResourceLoadStatisticsStore& store() { return m_store; }
214     Ref<WorkQueue>& workQueue() { return m_workQueue; }
215 #if HAVE(CORE_PREDICTION)
216     ResourceLoadStatisticsClassifierCocoa& classifier() { return m_resourceLoadStatisticsClassifier; }
217 #else
218     ResourceLoadStatisticsClassifier& classifier() { return m_resourceLoadStatisticsClassifier; }
219 #endif
220
221     struct Parameters {
222         size_t pruneEntriesDownTo { 800 };
223         size_t maxStatisticsEntries { 1000 };
224         Optional<Seconds> timeToLiveUserInteraction;
225         Seconds minimumTimeBetweenDataRecordsRemoval { 1_h };
226         Seconds grandfatheringTime { 24_h * 7 };
227         Seconds cacheMaxAgeCapTime { 24_h * 7 };
228         Seconds clientSideCookiesAgeCapTime { 24_h * 7 };
229         Seconds minDelayAfterMainFrameDocumentLoadToNotBeARedirect { 5_s };
230         bool shouldNotifyPagesWhenDataRecordsWereScanned { false };
231         bool shouldClassifyResourcesBeforeDataRecordsRemoval { true };
232         size_t minimumTopFrameRedirectsForSameSiteStrictEnforcement { 10 };
233         bool shouldSubmitTelemetry { true };
234         bool isRunningTest { false };
235     };
236     const Parameters& parameters() const { return m_parameters; }
237     const Vector<OperatingDate>& operatingDates() const { return m_operatingDates; }
238     void clearOperatingDates() { m_operatingDates.clear(); }
239     WallTime& endOfGrandfatheringTimestamp() { return m_endOfGrandfatheringTimestamp; }
240     const WallTime& endOfGrandfatheringTimestamp() const { return m_endOfGrandfatheringTimestamp; }
241     void setEndOfGrandfatheringTimestamp(const WallTime& grandfatheringTime) { m_endOfGrandfatheringTimestamp = grandfatheringTime; }
242     void clearEndOfGrandfatheringTimeStamp() { m_endOfGrandfatheringTimestamp = { }; }
243     const RegistrableDomain& debugManualPrevalentResource() const { return m_debugManualPrevalentResource; }
244     const RegistrableDomain& debugStaticPrevalentResource() const { return m_debugStaticPrevalentResource; }
245     void debugBroadcastConsoleMessage(MessageSource, MessageLevel, const String& message);
246     void debugLogDomainsInBatches(const char* action, const RegistrableDomainsToBlockCookiesFor&);
247     bool debugLoggingEnabled() const { return m_debugLoggingEnabled; };
248     bool debugModeEnabled() const { return m_debugModeEnabled; }
249     WebCore::FirstPartyWebsiteDataRemovalMode firstPartyWebsiteDataRemovalMode() const { return m_firstPartyWebsiteDataRemovalMode; }
250     RegistrableDomain standaloneApplicationDomain() const { return m_standaloneApplicationDomain; }
251
252     static constexpr unsigned maxNumberOfRecursiveCallsInRedirectTraceBack { 50 };
253     
254     Vector<CompletionHandler<void()>> m_dataRecordRemovalCompletionHandlers;
255
256 private:
257     bool shouldRemoveDataRecords() const;
258     void setDebugLogggingEnabled(bool enabled) { m_debugLoggingEnabled  = enabled; }
259     void setDataRecordsBeingRemoved(bool);
260     void removeDataRecords(CompletionHandler<void()>&&);
261     void setCacheMaxAgeCap(Seconds);
262     void updateCacheMaxAgeCap();
263     void setAgeCapForClientSideCookies(Seconds);
264     void updateClientSideCookiesAgeCap();
265
266     WebResourceLoadStatisticsStore& m_store;
267     Ref<WorkQueue> m_workQueue;
268 #if HAVE(CORE_PREDICTION)
269     ResourceLoadStatisticsClassifierCocoa m_resourceLoadStatisticsClassifier;
270 #else
271     ResourceLoadStatisticsClassifier m_resourceLoadStatisticsClassifier;
272 #endif
273 #if ENABLE(NETSCAPE_PLUGIN_API)
274     HashSet<uint64_t> m_activePluginTokens;
275 #endif
276     Parameters m_parameters;
277     Vector<OperatingDate> m_operatingDates;
278     WallTime m_endOfGrandfatheringTimestamp;
279     RegistrableDomain m_debugManualPrevalentResource;
280     MonotonicTime m_lastTimeDataRecordsWereRemoved;
281     uint64_t m_lastStatisticsProcessingRequestIdentifier { 0 };
282     Optional<uint64_t> m_pendingStatisticsProcessingRequestIdentifier;
283     const RegistrableDomain m_debugStaticPrevalentResource { URL { URL(), "https://3rdpartytestwebkit.org"_s } };
284     bool m_debugLoggingEnabled { false };
285     bool m_debugModeEnabled { false };
286     WebCore::ThirdPartyCookieBlockingMode m_thirdPartyCookieBlockingMode { WebCore::ThirdPartyCookieBlockingMode::All };
287     WebCore::SameSiteStrictEnforcementEnabled m_sameSiteStrictEnforcementEnabled { WebCore::SameSiteStrictEnforcementEnabled::No };
288     bool m_dataRecordsBeingRemoved { false };
289     ShouldIncludeLocalhost m_shouldIncludeLocalhost { ShouldIncludeLocalhost::Yes };
290     WebCore::FirstPartyWebsiteDataRemovalMode m_firstPartyWebsiteDataRemovalMode { WebCore::FirstPartyWebsiteDataRemovalMode::AllButCookies };
291     RegistrableDomain m_standaloneApplicationDomain;
292 };
293
294 } // namespace WebKit
295
296 #endif