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 "ResourceLoadStatisticsStore.h"
31#include "WebResourceLoadStatisticsStore.h"
32#include <WebCore/SQLiteDatabase.h>
33#include <WebCore/SQLiteStatement.h>
34#include <wtf/CompletionHandler.h>
35#include <wtf/StdSet.h>
36#include <wtf/Vector.h>
37#include <wtf/WorkQueue.h>
38
39namespace WebCore {
40class SQLiteDatabase;
41class SQLiteStatement;
42enum class StorageAccessPromptWasShown : bool;
43enum class StorageAccessWasGranted : bool;
44struct ResourceLoadStatistics;
45}
46
47namespace WebKit {
48
49class ResourceLoadStatisticsMemoryStore;
50
51// This is always constructed / used / destroyed on the WebResourceLoadStatisticsStore's statistics queue.
52class ResourceLoadStatisticsDatabaseStore final : public ResourceLoadStatisticsStore {
53public:
54 ResourceLoadStatisticsDatabaseStore(WebResourceLoadStatisticsStore&, WorkQueue&, ShouldIncludeLocalhost, const String& storageDirectoryPath);
55
56 void populateFromMemoryStore(const ResourceLoadStatisticsMemoryStore&);
57
58 void clear(CompletionHandler<void()>&&) override;
59 bool isEmpty() const override;
60
61 void updateCookieBlocking(CompletionHandler<void()>&&) override;
62
63 void classifyPrevalentResources() override;
64 void syncStorageIfNeeded() override;
65 void syncStorageImmediately() override;
66
67 void requestStorageAccessUnderOpener(DomainInNeedOfStorageAccess&&, WebCore::PageIdentifier openerID, OpenerDomain&&) override;
68
69 void grandfatherDataForDomains(const HashSet<RegistrableDomain>&) override;
70
71 bool isRegisteredAsSubresourceUnder(const SubResourceDomain&, const TopFrameDomain&) const override;
72 bool isRegisteredAsSubFrameUnder(const SubFrameDomain&, const TopFrameDomain&) const override;
73 bool isRegisteredAsRedirectingTo(const RedirectedFromDomain&, const RedirectedToDomain&) const override;
74
75 void clearPrevalentResource(const RegistrableDomain&) override;
76 String dumpResourceLoadStatistics() const override;
77 bool isPrevalentResource(const RegistrableDomain&) const override;
78 bool isVeryPrevalentResource(const RegistrableDomain&) const override;
79 void setPrevalentResource(const RegistrableDomain&) override;
80 void setVeryPrevalentResource(const RegistrableDomain&) override;
81
82 void setGrandfathered(const RegistrableDomain&, bool value) override;
83 bool isGrandfathered(const RegistrableDomain&) const override;
84
85 void setSubframeUnderTopFrameDomain(const SubFrameDomain&, const TopFrameDomain&) override;
86 void setSubresourceUnderTopFrameDomain(const SubResourceDomain&, const TopFrameDomain&) override;
87 void setSubresourceUniqueRedirectTo(const SubResourceDomain&, const RedirectDomain&) override;
88 void setSubresourceUniqueRedirectFrom(const SubResourceDomain&, const RedirectDomain&) override;
89 void setTopFrameUniqueRedirectTo(const TopFrameDomain&, const RedirectDomain&) override;
90 void setTopFrameUniqueRedirectFrom(const TopFrameDomain&, const RedirectDomain&) override;
91
92 void calculateAndSubmitTelemetry() const override;
93
94 void hasStorageAccess(const SubFrameDomain&, const TopFrameDomain&, Optional<FrameID>, WebCore::PageIdentifier, CompletionHandler<void(bool)>&&) override;
95 void requestStorageAccess(SubFrameDomain&&, TopFrameDomain&&, FrameID, WebCore::PageIdentifier, CompletionHandler<void(StorageAccessStatus)>&&) override;
96 void grantStorageAccess(SubFrameDomain&&, TopFrameDomain&&, FrameID, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&) override;
97
98 void logFrameNavigation(const NavigatedToDomain&, const TopFrameDomain&, const NavigatedFromDomain&, bool isRedirect, bool isMainFrame) override;
99 void logUserInteraction(const TopFrameDomain&) override;
100 void logSubresourceLoading(const SubResourceDomain&, const TopFrameDomain&, WallTime lastSeen) override;
101 void logSubresourceRedirect(const RedirectedFromDomain&, const RedirectedToDomain&) override;
102 void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) override;
103
104 void clearUserInteraction(const RegistrableDomain&) override;
105 bool hasHadUserInteraction(const RegistrableDomain&, OperatingDatesWindow) override;
106
107 void setLastSeen(const RegistrableDomain&, Seconds) override;
108
109private:
110 bool insertObservedDomain(const ResourceLoadStatistics&);
111 void insertDomainRelationships(const ResourceLoadStatistics&);
112 bool insertDomainRelationship(WebCore::SQLiteStatement&, unsigned domainID, const RegistrableDomain& topFrameDomain);
113 bool relationshipExists(WebCore::SQLiteStatement&, unsigned firstDomainID, const RegistrableDomain& secondDomain) const;
114 unsigned domainID(const RegistrableDomain&) const;
115#ifndef NDEBUG
116 bool confirmDomainDoesNotExist(const RegistrableDomain&) const;
117#endif
118 void updateLastSeen(const RegistrableDomain&, WallTime);
119 void setUserInteraction(const RegistrableDomain&, bool hadUserInteraction, WallTime);
120 Vector<RegistrableDomain> domainsToBlock() const;
121
122 struct PrevalentDomainData {
123 unsigned domainID;
124 RegistrableDomain registerableDomain;
125 WallTime mostRecentUserInteractionTime;
126 bool hadUserInteraction;
127 bool grandfathered;
128 };
129 Vector<PrevalentDomainData> prevalentDomains() const;
130 Vector<unsigned> findExpiredUserInteractions() const;
131 void clearExpiredUserInteractions();
132 void clearGrandfathering(Vector<unsigned>&&);
133 WebCore::StorageAccessPromptWasShown hasUserGrantedStorageAccessThroughPrompt(unsigned domainID, const RegistrableDomain&) const;
134 void incrementRecordsDeletedCountForDomains(HashSet<RegistrableDomain>&&) override;
135
136 void reclassifyResources();
137 struct NotVeryPrevalentResources {
138 RegistrableDomain registerableDomain;
139 ResourceLoadPrevalence prevalence;
140 unsigned subresourceUnderTopFrameDomainsCount;
141 unsigned subresourceUniqueRedirectsToCount;
142 unsigned subframeUnderTopFrameDomainsCount;
143 unsigned topFrameUniqueRedirectsToCount;
144 };
145 HashMap<unsigned, NotVeryPrevalentResources> findNotVeryPrevalentResources();
146
147 bool predicateValueForDomain(WebCore::SQLiteStatement&, const RegistrableDomain&) const;
148
149 enum class CookieTreatmentResult { Allow, BlockAndKeep, BlockAndPurge };
150 CookieTreatmentResult cookieTreatmentForOrigin(const RegistrableDomain&) const;
151
152 void setPrevalentResource(const RegistrableDomain&, ResourceLoadPrevalence);
153 unsigned recursivelyFindNonPrevalentDomainsThatRedirectedToThisDomain(unsigned primaryDomainID, StdSet<unsigned>& nonPrevalentRedirectionSources, unsigned numberOfRecursiveCalls);
154 void setDomainsAsPrevalent(StdSet<unsigned>&&);
155 void grantStorageAccessInternal(SubFrameDomain&&, TopFrameDomain&&, Optional<FrameID>, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&);
156 void markAsPrevalentIfHasRedirectedToPrevalent();
157 Vector<RegistrableDomain> ensurePrevalentResourcesForDebugMode() override;
158 void removeDataRecords(CompletionHandler<void()>&&);
159 void pruneStatisticsIfNeeded() override;
160 enum class AddedRecord { No, Yes };
161 std::pair<AddedRecord, unsigned> ensureResourceStatisticsForRegistrableDomain(const RegistrableDomain&);
162 bool shouldRemoveAllWebsiteDataFor(const PrevalentDomainData&, bool shouldCheckForGrandfathering) const;
163 bool shouldRemoveAllButCookiesFor(const PrevalentDomainData&, bool shouldCheckForGrandfathering) const;
164 HashMap<RegistrableDomain, WebsiteDataToRemove> registrableDomainsToRemoveWebsiteDataFor() override;
165 bool isDatabaseStore() const final { return true; }
166
167 bool createSchema();
168 bool prepareStatements();
169
170 const String m_storageDirectoryPath;
171 mutable WebCore::SQLiteDatabase m_database;
172 mutable WebCore::SQLiteStatement m_observedDomainCount;
173 WebCore::SQLiteStatement m_insertObservedDomainStatement;
174 WebCore::SQLiteStatement m_insertTopLevelDomainStatement;
175 mutable WebCore::SQLiteStatement m_domainIDFromStringStatement;
176 WebCore::SQLiteStatement m_storageAccessUnderTopFrameDomainsStatement;
177 WebCore::SQLiteStatement m_topFrameUniqueRedirectsTo;
178 mutable WebCore::SQLiteStatement m_topFrameUniqueRedirectsToExists;
179 WebCore::SQLiteStatement m_topFrameUniqueRedirectsFrom;
180 mutable WebCore::SQLiteStatement m_topFrameUniqueRedirectsFromExists;
181 WebCore::SQLiteStatement m_topFrameLinkDecorationsFrom;
182 mutable WebCore::SQLiteStatement m_topFrameLinkDecorationsFromExists;
183 WebCore::SQLiteStatement m_subframeUnderTopFrameDomains;
184 mutable WebCore::SQLiteStatement m_subframeUnderTopFrameDomainExists;
185 WebCore::SQLiteStatement m_subresourceUnderTopFrameDomains;
186 mutable WebCore::SQLiteStatement m_subresourceUnderTopFrameDomainExists;
187 WebCore::SQLiteStatement m_subresourceUniqueRedirectsTo;
188 mutable WebCore::SQLiteStatement m_subresourceUniqueRedirectsToExists;
189 WebCore::SQLiteStatement m_subresourceUniqueRedirectsFrom;
190 mutable WebCore::SQLiteStatement m_subresourceUniqueRedirectsFromExists;
191 WebCore::SQLiteStatement m_mostRecentUserInteractionStatement;
192 WebCore::SQLiteStatement m_updateLastSeenStatement;
193 WebCore::SQLiteStatement m_updatePrevalentResourceStatement;
194 mutable WebCore::SQLiteStatement m_isPrevalentResourceStatement;
195 WebCore::SQLiteStatement m_updateVeryPrevalentResourceStatement;
196 mutable WebCore::SQLiteStatement m_isVeryPrevalentResourceStatement;
197 WebCore::SQLiteStatement m_clearPrevalentResourceStatement;
198 mutable WebCore::SQLiteStatement m_hadUserInteractionStatement;
199 WebCore::SQLiteStatement m_updateGrandfatheredStatement;
200 mutable WebCore::SQLiteStatement m_isGrandfatheredStatement;
201 mutable WebCore::SQLiteStatement m_findExpiredUserInteractionStatement;
202};
203
204} // namespace WebKit
205
206SPECIALIZE_TYPE_TRAITS_BEGIN(WebKit::ResourceLoadStatisticsDatabaseStore)
207 static bool isType(const WebKit::ResourceLoadStatisticsStore& store) { return store.isDatabaseStore(); }
208SPECIALIZE_TYPE_TRAITS_END()
209
210#endif
211