Rollout r231818, as it introduced regression on tickets.com.
[WebKit-https.git] / Source / WebKit / UIProcess / WebResourceLoadStatisticsStore.h
1 /*
2  * Copyright (C) 2016-2018 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 #include "Connection.h"
29 #include "ResourceLoadStatisticsClassifier.h"
30 #include "ResourceLoadStatisticsPersistentStorage.h"
31 #include "WebsiteDataType.h"
32 #include <wtf/CompletionHandler.h>
33 #include <wtf/HashSet.h>
34 #include <wtf/MonotonicTime.h>
35 #include <wtf/RunLoop.h>
36 #include <wtf/Vector.h>
37 #include <wtf/WallTime.h>
38 #include <wtf/text/WTFString.h>
39
40 #if HAVE(CORE_PREDICTION)
41 #include "ResourceLoadStatisticsClassifierCocoa.h"
42 #endif
43
44 namespace WTF {
45 class WorkQueue;
46 }
47
48 namespace WebCore {
49 class KeyedDecoder;
50 class KeyedEncoder;
51 class ResourceRequest;
52 class URL;
53 struct ResourceLoadStatistics;
54 }
55
56 namespace WebKit {
57
58 class OperatingDate;
59 class WebFrameProxy;
60 class WebProcessProxy;
61
62 enum class ShouldClearFirst;
63 enum class StorageAccessStatus {
64     CannotRequestAccess,
65     RequiresUserPrompt,
66     HasAccess
67 };
68
69 class WebResourceLoadStatisticsStore final : public IPC::Connection::WorkQueueMessageReceiver {
70 public:
71     using UpdatePrevalentDomainsToPartitionOrBlockCookiesHandler = WTF::Function<void(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst)>;
72     using HasStorageAccessForFrameHandler = WTF::Function<void(const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, WTF::Function<void(bool hasAccess)>&& callback)>;
73     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)>;
74     using RemoveAllStorageAccessHandler = WTF::Function<void()>;
75     using RemovePrevalentDomainsHandler = WTF::Function<void (const Vector<String>&)>;
76     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>&) { })
77     {
78         return adoptRef(*new WebResourceLoadStatisticsStore(resourceLoadStatisticsDirectory, WTFMove(testingCallback), isEphemeral, WTFMove(updatePrevalentDomainsToPartitionOrBlockCookiesHandler), WTFMove(hasStorageAccessForFrameHandler), WTFMove(grantStorageAccessHandler), WTFMove(removeAllStorageAccessHandler), WTFMove(removeDomainsHandler)));
79     }
80
81     ~WebResourceLoadStatisticsStore();
82
83     static const OptionSet<WebsiteDataType>& monitoredDataTypes();
84
85     bool isEmpty() const { return m_resourceStatisticsMap.isEmpty(); }
86     WorkQueue& statisticsQueue() { return m_statisticsQueue.get(); }
87
88     void setNotifyPagesWhenDataRecordsWereScanned(bool value) { m_parameters.shouldNotifyPagesWhenDataRecordsWereScanned = value; }
89     void setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value) { m_parameters.shouldClassifyResourcesBeforeDataRecordsRemoval = value; }
90     void setShouldSubmitTelemetry(bool value) { m_parameters.shouldSubmitTelemetry = value; }
91
92     void resourceLoadStatisticsUpdated(Vector<WebCore::ResourceLoadStatistics>&& origins);
93
94     void hasStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, WTF::CompletionHandler<void (bool)>&& callback);
95     void requestStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool promptEnabled, CompletionHandler<void(StorageAccessStatus)>&&);
96     void requestStorageAccessUnderOpener(String&& primaryDomainInNeedOfStorageAccess, uint64_t openerPageID, String&& openerPrimaryDomain, bool isTriggeredByUserGesture);
97     void grantStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool userWasPromptedNow, CompletionHandler<void(bool)>&&);
98     void requestStorageAccessCallback(bool wasGranted, uint64_t contextId);
99
100     void processWillOpenConnection(WebProcessProxy&, IPC::Connection&);
101     void processDidCloseConnection(WebProcessProxy&, IPC::Connection&);
102     void applicationWillTerminate();
103
104     void logFrameNavigation(const WebFrameProxy&, const WebCore::URL& pageURL, const WebCore::ResourceRequest&, const WebCore::URL& redirectURL);
105     void logUserInteraction(const WebCore::URL&);
106     void logNonRecentUserInteraction(const WebCore::URL&);
107     void clearUserInteraction(const WebCore::URL&);
108     void hasHadUserInteraction(const WebCore::URL&, WTF::Function<void (bool)>&&);
109     void setLastSeen(const WebCore::URL&, Seconds);
110     void setPrevalentResource(const WebCore::URL&);
111     void setVeryPrevalentResource(const WebCore::URL&);
112     void isPrevalentResource(const WebCore::URL&, WTF::Function<void (bool)>&&);
113     void isVeryPrevalentResource(const WebCore::URL&, WTF::Function<void(bool)>&&);
114     void isRegisteredAsSubFrameUnder(const WebCore::URL& subFrame, const WebCore::URL& topFrame, WTF::Function<void (bool)>&&);
115     void isRegisteredAsRedirectingTo(const WebCore::URL& hostRedirectedFrom, const WebCore::URL& hostRedirectedTo, WTF::Function<void (bool)>&&);
116     void clearPrevalentResource(const WebCore::URL&);
117     void setGrandfathered(const WebCore::URL&, bool);
118     void isGrandfathered(const WebCore::URL&, WTF::Function<void (bool)>&&);
119     void setSubframeUnderTopFrameOrigin(const WebCore::URL& subframe, const WebCore::URL& topFrame);
120     void setSubresourceUnderTopFrameOrigin(const WebCore::URL& subresource, const WebCore::URL& topFrame);
121     void setSubresourceUniqueRedirectTo(const WebCore::URL& subresource, const WebCore::URL& hostNameRedirectedTo);
122     void setSubresourceUniqueRedirectFrom(const WebCore::URL& subresource, const WebCore::URL& hostNameRedirectedFrom);
123     void setTopFrameUniqueRedirectTo(const WebCore::URL& topFrameHostName, const WebCore::URL& hostNameRedirectedTo);
124     void setTopFrameUniqueRedirectFrom(const WebCore::URL& topFrameHostName, const WebCore::URL& hostNameRedirectedFrom);
125     void scheduleCookiePartitioningUpdate(CompletionHandler<void()>&&);
126     void scheduleCookiePartitioningUpdateForDomains(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst, CompletionHandler<void()>&&);
127     void scheduleClearPartitioningStateForDomains(const Vector<String>& domains, CompletionHandler<void()>&&);
128     void scheduleStatisticsAndDataRecordsProcessing();
129     void submitTelemetry();
130     void scheduleCookiePartitioningStateReset();
131
132     void scheduleClearInMemory();
133     
134     enum class ShouldGrandfather {
135         No,
136         Yes,
137     };
138     void scheduleClearInMemoryAndPersistent(ShouldGrandfather, CompletionHandler<void()>&&);
139     void scheduleClearInMemoryAndPersistent(WallTime modifiedSince, ShouldGrandfather, CompletionHandler<void()>&&);
140
141     void setTimeToLiveUserInteraction(Seconds);
142     void setTimeToLiveCookiePartitionFree(Seconds);
143     void setMinimumTimeBetweenDataRecordsRemoval(Seconds);
144     void setGrandfatheringTime(Seconds);
145     void setMaxStatisticsEntries(size_t);
146     void setPruneEntriesDownTo(size_t);
147     
148     void processStatistics(const WTF::Function<void (const WebCore::ResourceLoadStatistics&)>&) const;
149     void pruneStatisticsIfNeeded();
150
151     void resetParametersToDefaultValues();
152
153     std::unique_ptr<WebCore::KeyedEncoder> createEncoderFromData() const;
154     void mergeWithDataFromDecoder(WebCore::KeyedDecoder&);
155     void clearInMemory();
156     void grandfatherExistingWebsiteData(CompletionHandler<void()>&&);
157
158     void setResourceLoadStatisticsDebugMode(bool);
159
160     void setStatisticsTestingCallback(Function<void (const String&)>&& callback) { m_statisticsTestingCallback = WTFMove(callback); }
161     void logTestingEvent(const String&);
162
163 private:
164     WebResourceLoadStatisticsStore(const String&, Function<void(const String&)>&& testingCallback, bool isEphemeral, UpdatePrevalentDomainsToPartitionOrBlockCookiesHandler&&, HasStorageAccessForFrameHandler&&, GrantStorageAccessHandler&&, RemoveAllStorageAccessHandler&&, RemovePrevalentDomainsHandler&&);
165
166     void removeDataRecords(CompletionHandler<void()>&&);
167
168     // IPC::MessageReceiver
169     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
170
171     void performDailyTasks();
172     bool shouldRemoveDataRecords() const;
173     void setDataRecordsBeingRemoved(bool);
174
175     bool shouldPartitionCookies(const WebCore::ResourceLoadStatistics&) const;
176     bool shouldBlockCookies(const WebCore::ResourceLoadStatistics&) const;
177     bool hasUserGrantedStorageAccessThroughPrompt(const WebCore::ResourceLoadStatistics&, const String& firstPartyPrimaryDomain) const;
178     bool hasStatisticsExpired(const WebCore::ResourceLoadStatistics&) const;
179     bool hasHadUnexpiredRecentUserInteraction(WebCore::ResourceLoadStatistics&) const;
180     void includeTodayAsOperatingDateIfNecessary();
181     Vector<String> topPrivatelyControlledDomainsToRemoveWebsiteDataFor();
182     void updateCookiePartitioning(CompletionHandler<void()>&&);
183     void updateCookiePartitioningForDomains(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst, CompletionHandler<void()>&&);
184     void clearPartitioningStateForDomains(const Vector<String>& domains, CompletionHandler<void()>&&);
185     void mergeStatistics(Vector<WebCore::ResourceLoadStatistics>&&);
186     WebCore::ResourceLoadStatistics& ensureResourceStatisticsForPrimaryDomain(const String&);
187     unsigned recursivelyGetAllDomainsThatHaveRedirectedToThisDomain(const WebCore::ResourceLoadStatistics&, HashSet<String>& domainsThatHaveRedirectedTo, unsigned numberOfRecursiveCalls);
188     void markAsPrevalentIfHasRedirectedToPrevalent(WebCore::ResourceLoadStatistics&);
189     void setPrevalentResource(WebCore::ResourceLoadStatistics&, ResourceLoadPrevalence);
190     void processStatisticsAndDataRecords();
191
192     void scheduleStatisticsProcessingRequestIfNecessary();
193     void cancelPendingStatisticsProcessingRequest();
194
195     void resetCookiePartitioningState();
196     StorageAccessStatus storageAccessStatus(const String& subFramePrimaryDomain, const String& topFramePrimaryDomain);
197     void grantStorageAccessInternal(String&& subFrameHost, String&& topFrameHost, std::optional<uint64_t> frameID, uint64_t pageID, bool userWasPromptedNowOrEarlier, CompletionHandler<void(bool)>&&);
198     void removeAllStorageAccess();
199
200     void setDebugLogggingEnabled(bool enabled) { m_debugLoggingEnabled  = enabled; }
201     void setStorageAccessPromptsEnabled(bool enabled) { m_storageAccessPromptsEnabled  = enabled; }
202
203 #if PLATFORM(COCOA)
204     void registerUserDefaultsIfNeeded();
205 #endif
206
207     bool wasAccessedAsFirstPartyDueToUserInteraction(const WebCore::ResourceLoadStatistics& current, const WebCore::ResourceLoadStatistics& updated);
208
209     struct Parameters {
210         size_t pruneEntriesDownTo { 800 };
211         size_t maxStatisticsEntries { 1000 };
212         std::optional<Seconds> timeToLiveUserInteraction;
213         Seconds timeToLiveCookiePartitionFree { 24_h };
214         Seconds minimumTimeBetweenDataRecordsRemoval { 1_h };
215         Seconds grandfatheringTime { 24_h * 7 };
216         bool shouldNotifyPagesWhenDataRecordsWereScanned { false };
217         bool shouldClassifyResourcesBeforeDataRecordsRemoval { true };
218         bool shouldSubmitTelemetry { true };
219     };
220
221     HashMap<String, WebCore::ResourceLoadStatistics> m_resourceStatisticsMap;
222 #if HAVE(CORE_PREDICTION)
223     ResourceLoadStatisticsClassifierCocoa m_resourceLoadStatisticsClassifier;
224 #else
225     ResourceLoadStatisticsClassifier m_resourceLoadStatisticsClassifier;
226 #endif
227     Ref<WTF::WorkQueue> m_statisticsQueue;
228     ResourceLoadStatisticsPersistentStorage m_persistentStorage;
229     Vector<OperatingDate> m_operatingDates;
230
231     UpdatePrevalentDomainsToPartitionOrBlockCookiesHandler m_updatePrevalentDomainsToPartitionOrBlockCookiesHandler;
232     HasStorageAccessForFrameHandler m_hasStorageAccessForFrameHandler;
233     GrantStorageAccessHandler m_grantStorageAccessHandler;
234     RemoveAllStorageAccessHandler m_removeAllStorageAccessHandler;
235     RemovePrevalentDomainsHandler m_removeDomainsHandler;
236
237     WallTime m_endOfGrandfatheringTimestamp;
238     RunLoop::Timer<WebResourceLoadStatisticsStore> m_dailyTasksTimer;
239     MonotonicTime m_lastTimeDataRecordsWereRemoved;
240
241     Parameters m_parameters;
242
243 #if ENABLE(NETSCAPE_PLUGIN_API)
244     HashSet<uint64_t> m_activePluginTokens;
245 #endif
246     bool m_dataRecordsBeingRemoved { false };
247
248     bool m_debugModeEnabled { false };
249     bool m_debugLoggingEnabled { false };
250     bool m_storageAccessPromptsEnabled { false };
251     bool m_hasScheduledProcessStats { false };
252
253     Function<void (const String&)> m_statisticsTestingCallback;
254
255     uint64_t m_lastStatisticsProcessingRequestIdentifier { 0 };
256     std::optional<uint64_t> m_pendingStatisticsProcessingRequestIdentifier;
257 };
258
259 } // namespace WebKit