Updated resource load statistics are never merged into the SQLite Database backend...
[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 <WebCore/FrameIdentifier.h>
33 #include <wtf/CompletionHandler.h>
34 #include <wtf/Vector.h>
35 #include <wtf/WeakPtr.h>
36 #include <wtf/WorkQueue.h>
37
38 #if HAVE(CORE_PREDICTION)
39 #include "ResourceLoadStatisticsClassifierCocoa.h"
40 #endif
41
42 namespace WebCore {
43 class KeyedDecoder;
44 class KeyedEncoder;
45 enum class StorageAccessPromptWasShown : bool;
46 enum class StorageAccessWasGranted : bool;
47 struct ResourceLoadStatistics;
48 }
49
50 namespace WebKit {
51
52 class ResourceLoadStatisticsPersistentStorage;
53
54 class OperatingDate {
55 public:
56     OperatingDate() = default;
57     
58     static OperatingDate fromWallTime(WallTime);
59     static OperatingDate today();
60     Seconds secondsSinceEpoch() const;
61     bool operator==(const OperatingDate& other) const;
62     bool operator<(const OperatingDate& other) const;
63     bool operator<=(const OperatingDate& other) const;
64     
65 private:
66     OperatingDate(int year, int month, int monthDay)
67         : m_year(year)
68         , m_month(month)
69         , m_monthDay(monthDay)
70     { }
71
72     int m_year { 0 };
73     int m_month { 0 }; // [0, 11].
74     int m_monthDay { 0 }; // [1, 31].
75 };
76
77 enum class OperatingDatesWindow : bool { Long, Short };
78
79 // This is always constructed / used / destroyed on the WebResourceLoadStatisticsStore's statistics queue.
80 class ResourceLoadStatisticsStore : public CanMakeWeakPtr<ResourceLoadStatisticsStore> {
81     WTF_MAKE_FAST_ALLOCATED;
82 public:
83     using ResourceLoadStatistics = WebCore::ResourceLoadStatistics;
84     using RegistrableDomain = WebCore::RegistrableDomain;
85     using TopFrameDomain = WebCore::RegistrableDomain;
86     using SubFrameDomain = WebCore::RegistrableDomain;
87     using SubResourceDomain = WebCore::RegistrableDomain;
88     using RedirectDomain = WebCore::RegistrableDomain;
89     using RedirectedFromDomain = WebCore::RegistrableDomain;
90     using RedirectedToDomain = WebCore::RegistrableDomain;
91     using NavigatedFromDomain = WebCore::RegistrableDomain;
92     using NavigatedToDomain = WebCore::RegistrableDomain;
93     using DomainInNeedOfStorageAccess = WebCore::RegistrableDomain;
94     using OpenerDomain = WebCore::RegistrableDomain;
95     
96     virtual ~ResourceLoadStatisticsStore();
97
98     virtual void clear(CompletionHandler<void()>&&) = 0;
99     virtual bool isEmpty() const = 0;
100
101     virtual void updateCookieBlocking(CompletionHandler<void()>&&) = 0;
102     void updateCookieBlockingForDomains(const RegistrableDomainsToBlockCookiesFor&, CompletionHandler<void()>&&);
103     void clearBlockingStateForDomains(const Vector<RegistrableDomain>& domains, CompletionHandler<void()>&&);
104
105     void includeTodayAsOperatingDateIfNecessary();
106     void processStatisticsAndDataRecords();
107
108     virtual void classifyPrevalentResources() = 0;
109     virtual void syncStorageIfNeeded() = 0;
110     virtual void syncStorageImmediately() = 0;
111     virtual void mergeStatistics(Vector<ResourceLoadStatistics>&&) = 0;
112
113     virtual void requestStorageAccessUnderOpener(DomainInNeedOfStorageAccess&&, WebCore::PageIdentifier openerID, OpenerDomain&&) = 0;
114     void removeAllStorageAccess(CompletionHandler<void()>&&);
115
116     void grandfatherExistingWebsiteData(CompletionHandler<void()>&&);
117     void cancelPendingStatisticsProcessingRequest();
118
119     virtual bool isRegisteredAsSubresourceUnder(const SubResourceDomain&, const TopFrameDomain&) const = 0;
120     virtual bool isRegisteredAsSubFrameUnder(const SubFrameDomain&, const TopFrameDomain&) const = 0;
121     virtual bool isRegisteredAsRedirectingTo(const RedirectedFromDomain&, const RedirectedToDomain&) const = 0;
122
123     virtual void clearPrevalentResource(const RegistrableDomain&) = 0;
124     virtual void dumpResourceLoadStatistics(CompletionHandler<void(const String&)>&&) = 0;
125     virtual bool isPrevalentResource(const RegistrableDomain&) const = 0;
126     virtual bool isVeryPrevalentResource(const RegistrableDomain&) const = 0;
127     virtual void setPrevalentResource(const RegistrableDomain&) = 0;
128     virtual void setVeryPrevalentResource(const RegistrableDomain&) = 0;
129
130     virtual void setGrandfathered(const RegistrableDomain&, bool value) = 0;
131     virtual bool isGrandfathered(const RegistrableDomain&) const = 0;
132
133     virtual void incrementRecordsDeletedCountForDomains(HashSet<RegistrableDomain>&&) = 0;
134     virtual void grandfatherDataForDomains(const HashSet<RegistrableDomain>&) = 0;
135
136     virtual void setSubframeUnderTopFrameDomain(const SubFrameDomain&, const TopFrameDomain&) = 0;
137     virtual void setSubresourceUnderTopFrameDomain(const SubResourceDomain&, const TopFrameDomain&) = 0;
138     virtual void setSubresourceUniqueRedirectTo(const SubResourceDomain&, const RedirectDomain&) = 0;
139     virtual void setSubresourceUniqueRedirectFrom(const SubResourceDomain&, const RedirectDomain&) = 0;
140     virtual void setTopFrameUniqueRedirectTo(const TopFrameDomain&, const RedirectDomain&) = 0;
141     virtual void setTopFrameUniqueRedirectFrom(const TopFrameDomain&, const RedirectDomain&) = 0;
142
143     void logTestingEvent(const String&);
144
145     void setMaxStatisticsEntries(size_t maximumEntryCount);
146     void setPruneEntriesDownTo(size_t pruneTargetCount);
147     void resetParametersToDefaultValues();
148     Optional<Seconds> statisticsEpirationTime() const;
149
150     virtual void calculateAndSubmitTelemetry() const = 0;
151
152     void setNotifyPagesWhenDataRecordsWereScanned(bool);
153     void setIsRunningTest(bool);
154     bool shouldSkip(const RegistrableDomain&) const;
155     void setShouldClassifyResourcesBeforeDataRecordsRemoval(bool);
156     void setShouldSubmitTelemetry(bool);
157     void setTimeToLiveUserInteraction(Seconds);
158     void setMinimumTimeBetweenDataRecordsRemoval(Seconds);
159     void setGrandfatheringTime(Seconds);
160     void setResourceLoadStatisticsDebugMode(bool);
161     bool isDebugModeEnabled() const { return m_debugModeEnabled; };
162     void setPrevalentResourceForDebugMode(const RegistrableDomain&);
163
164     virtual void hasStorageAccess(const SubFrameDomain&, const TopFrameDomain&, Optional<WebCore::FrameIdentifier>, WebCore::PageIdentifier, CompletionHandler<void(bool)>&&) = 0;
165     virtual void requestStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, CompletionHandler<void(StorageAccessStatus)>&&) = 0;
166     virtual void grantStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&) = 0;
167
168     virtual void logFrameNavigation(const NavigatedToDomain&, const TopFrameDomain&, const NavigatedFromDomain&, bool isRedirect, bool isMainFrame) = 0;
169     virtual void logUserInteraction(const TopFrameDomain&) = 0;
170     virtual void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) = 0;
171
172     virtual void clearUserInteraction(const RegistrableDomain&) = 0;
173     virtual bool hasHadUserInteraction(const RegistrableDomain&, OperatingDatesWindow) = 0;
174
175     virtual void setLastSeen(const RegistrableDomain& primaryDomain, Seconds) = 0;
176
177     void didCreateNetworkProcess();
178
179     const WebResourceLoadStatisticsStore& store() const { return m_store; }
180
181     static constexpr unsigned maxImportance { 3 };
182
183     virtual bool isMemoryStore() const { return false; }
184     virtual bool isDatabaseStore()const { return false; }
185
186 protected:
187     static unsigned computeImportance(const WebCore::ResourceLoadStatistics&);
188     static Vector<OperatingDate> mergeOperatingDates(const Vector<OperatingDate>& existingDates, Vector<OperatingDate>&& newDates);
189     static void debugLogDomainsInBatches(const char* action, const RegistrableDomainsToBlockCookiesFor&);
190
191     ResourceLoadStatisticsStore(WebResourceLoadStatisticsStore&, WorkQueue&, ShouldIncludeLocalhost);
192     
193     bool dataRecordsBeingRemoved() const { return m_dataRecordsBeingRemoved; }
194
195     bool hasStatisticsExpired(const ResourceLoadStatistics&, OperatingDatesWindow) const;
196     bool hasStatisticsExpired(WallTime mostRecentUserInteractionTime, OperatingDatesWindow) const;
197     void scheduleStatisticsProcessingRequestIfNecessary();
198     void mergeOperatingDates(Vector<OperatingDate>&&);
199     virtual Vector<RegistrableDomain> ensurePrevalentResourcesForDebugMode() = 0;
200     virtual Vector<std::pair<RegistrableDomain, WebsiteDataToRemove>> registrableDomainsToRemoveWebsiteDataFor() = 0;
201     virtual void pruneStatisticsIfNeeded() = 0;
202
203     WebResourceLoadStatisticsStore& store() { return m_store; }
204     Ref<WorkQueue>& workQueue() { return m_workQueue; }
205 #if HAVE(CORE_PREDICTION)
206     ResourceLoadStatisticsClassifierCocoa& classifier() { return m_resourceLoadStatisticsClassifier; }
207 #else
208     ResourceLoadStatisticsClassifier& classifier() { return m_resourceLoadStatisticsClassifier; }
209 #endif
210
211     struct Parameters {
212         size_t pruneEntriesDownTo { 800 };
213         size_t maxStatisticsEntries { 1000 };
214         Optional<Seconds> timeToLiveUserInteraction;
215         Seconds minimumTimeBetweenDataRecordsRemoval { 1_h };
216         Seconds grandfatheringTime { 24_h * 7 };
217         Seconds cacheMaxAgeCapTime { 24_h * 7 };
218         Seconds clientSideCookiesAgeCapTime { 24_h * 7 };
219         bool shouldNotifyPagesWhenDataRecordsWereScanned { false };
220         bool shouldClassifyResourcesBeforeDataRecordsRemoval { true };
221         bool shouldSubmitTelemetry { true };
222         bool isRunningTest { false };
223     };
224     const Parameters& parameters() const { return m_parameters; }
225     const Vector<OperatingDate>& operatingDates() const { return m_operatingDates; }
226     void clearOperatingDates() { m_operatingDates.clear(); }
227     WallTime& endOfGrandfatheringTimestamp() { return m_endOfGrandfatheringTimestamp; }
228     const WallTime& endOfGrandfatheringTimestamp() const { return m_endOfGrandfatheringTimestamp; }
229     void setEndOfGrandfatheringTimestamp(const WallTime& grandfatheringTime) { m_endOfGrandfatheringTimestamp = grandfatheringTime; }
230     void clearEndOfGrandfatheringTimeStamp() { m_endOfGrandfatheringTimestamp = { }; }
231     const RegistrableDomain& debugManualPrevalentResource() const { return m_debugManualPrevalentResource; }
232     const RegistrableDomain& debugStaticPrevalentResource() const { return m_debugStaticPrevalentResource; }
233     bool debugLoggingEnabled() const { return m_debugLoggingEnabled; };
234     bool debugModeEnabled() const { return m_debugModeEnabled; }
235
236     static constexpr unsigned maxNumberOfRecursiveCallsInRedirectTraceBack { 50 };
237     
238     Vector<CompletionHandler<void()>> m_dataRecordRemovalCompletionHandlers;
239
240 private:
241     bool shouldRemoveDataRecords() const;
242     void setDebugLogggingEnabled(bool enabled) { m_debugLoggingEnabled  = enabled; }
243     void setDataRecordsBeingRemoved(bool);
244     void removeDataRecords(CompletionHandler<void()>&&);
245     void setCacheMaxAgeCap(Seconds);
246     void updateCacheMaxAgeCap();
247     void setAgeCapForClientSideCookies(Seconds);
248     void updateClientSideCookiesAgeCap();
249
250     WebResourceLoadStatisticsStore& m_store;
251     Ref<WorkQueue> m_workQueue;
252 #if HAVE(CORE_PREDICTION)
253     ResourceLoadStatisticsClassifierCocoa m_resourceLoadStatisticsClassifier;
254 #else
255     ResourceLoadStatisticsClassifier m_resourceLoadStatisticsClassifier;
256 #endif
257 #if ENABLE(NETSCAPE_PLUGIN_API)
258     HashSet<uint64_t> m_activePluginTokens;
259 #endif
260     Parameters m_parameters;
261     Vector<OperatingDate> m_operatingDates;
262     WallTime m_endOfGrandfatheringTimestamp;
263     RegistrableDomain m_debugManualPrevalentResource;
264     MonotonicTime m_lastTimeDataRecordsWereRemoved;
265     uint64_t m_lastStatisticsProcessingRequestIdentifier { 0 };
266     Optional<uint64_t> m_pendingStatisticsProcessingRequestIdentifier;
267     const RegistrableDomain m_debugStaticPrevalentResource { URL { URL(), "https://3rdpartytestwebkit.org"_s } };
268     bool m_debugLoggingEnabled { false };
269     bool m_debugModeEnabled { false };
270     bool m_dataRecordsBeingRemoved { false };
271     ShouldIncludeLocalhost m_shouldIncludeLocalhost { ShouldIncludeLocalhost::Yes };
272 };
273
274 } // namespace WebKit
275
276 #endif