c7b18d570ebc5b6f625d7006e9770bb06aaf470f
[WebKit-https.git] / Source / WebKit / UIProcess / WebResourceLoadStatisticsStore.cpp
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 #include "config.h"
27 #include "WebResourceLoadStatisticsStore.h"
28
29 #include "Logging.h"
30 #include "ResourceLoadStatisticsMemoryStore.h"
31 #include "ResourceLoadStatisticsPersistentStorage.h"
32 #include "WebFrameProxy.h"
33 #include "WebPageProxy.h"
34 #include "WebProcessMessages.h"
35 #include "WebProcessProxy.h"
36 #include "WebResourceLoadStatisticsStoreMessages.h"
37 #include "WebResourceLoadStatisticsTelemetry.h"
38 #include "WebsiteDataFetchOption.h"
39 #include "WebsiteDataStore.h"
40 #include <WebCore/ResourceLoadStatistics.h>
41 #include <wtf/CrossThreadCopier.h>
42 #include <wtf/NeverDestroyed.h>
43 #include <wtf/threads/BinarySemaphore.h>
44
45 namespace WebKit {
46 using namespace WebCore;
47
48 template<typename T> static inline String isolatedPrimaryDomain(const T& value)
49 {
50     return ResourceLoadStatistics::primaryDomain(value).isolatedCopy();
51 }
52
53 static bool areDomainsAssociated(WebPageProxy* page, const String& firstDomain, const String& secondDomain)
54 {
55     bool needsSiteSpecificQuirks = page && page->preferences().needsSiteSpecificQuirks();
56     return ResourceLoadStatistics::areDomainsAssociated(needsSiteSpecificQuirks, firstDomain, secondDomain);
57 }
58
59 const OptionSet<WebsiteDataType>& WebResourceLoadStatisticsStore::monitoredDataTypes()
60 {
61     static NeverDestroyed<OptionSet<WebsiteDataType>> dataTypes(std::initializer_list<WebsiteDataType>({
62         WebsiteDataType::Cookies,
63         WebsiteDataType::DOMCache,
64         WebsiteDataType::IndexedDBDatabases,
65         WebsiteDataType::LocalStorage,
66         WebsiteDataType::MediaKeys,
67         WebsiteDataType::OfflineWebApplicationCache,
68 #if ENABLE(NETSCAPE_PLUGIN_API)
69         WebsiteDataType::PlugInData,
70 #endif
71         WebsiteDataType::SearchFieldRecentSearches,
72         WebsiteDataType::SessionStorage,
73 #if ENABLE(SERVICE_WORKER)
74         WebsiteDataType::ServiceWorkerRegistrations,
75 #endif
76         WebsiteDataType::WebSQLDatabases,
77     }));
78
79     ASSERT(RunLoop::isMain());
80
81     return dataTypes;
82 }
83
84 void WebResourceLoadStatisticsStore::setNotifyPagesWhenDataRecordsWereScanned(bool value)
85 {
86     ASSERT(RunLoop::isMain());
87
88     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), value] {
89         if (m_memoryStore)
90             m_memoryStore->setNotifyPagesWhenDataRecordsWereScanned(value);
91     });
92 }
93
94 void WebResourceLoadStatisticsStore::setShouldClassifyResourcesBeforeDataRecordsRemoval(bool value)
95 {
96     ASSERT(RunLoop::isMain());
97
98     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), value] {
99         if (m_memoryStore)
100             m_memoryStore->setShouldClassifyResourcesBeforeDataRecordsRemoval(value);
101     });
102 }
103
104 void WebResourceLoadStatisticsStore::setShouldSubmitTelemetry(bool value)
105 {
106     ASSERT(RunLoop::isMain());
107
108     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), value] {
109         if (m_memoryStore)
110             m_memoryStore->setShouldSubmitTelemetry(value);
111     });
112 }
113
114 WebResourceLoadStatisticsStore::WebResourceLoadStatisticsStore(WebsiteDataStore& websiteDataStore)
115     : m_websiteDataStore(makeWeakPtr(websiteDataStore))
116     , m_statisticsQueue(WorkQueue::create("WebResourceLoadStatisticsStore Process Data Queue", WorkQueue::Type::Serial, WorkQueue::QOS::Utility))
117     , m_dailyTasksTimer(RunLoop::main(), this, &WebResourceLoadStatisticsStore::performDailyTasks)
118 {
119     ASSERT(RunLoop::isMain());
120
121     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), isPersistent = websiteDataStore.isPersistent(), resourceLoadStatisticsDirectory = websiteDataStore.resolvedResourceLoadStatisticsDirectory().isolatedCopy()] {
122         m_memoryStore = std::make_unique<ResourceLoadStatisticsMemoryStore>(*this, m_statisticsQueue);
123         m_persistentStorage = std::make_unique<ResourceLoadStatisticsPersistentStorage>(*m_memoryStore, m_statisticsQueue, resourceLoadStatisticsDirectory, isPersistent ? ResourceLoadStatisticsPersistentStorage::IsReadOnly::No : ResourceLoadStatisticsPersistentStorage::IsReadOnly::Yes);
124     });
125
126     m_statisticsQueue->dispatchAfter(5_s, [this, protectedThis = makeRef(*this)] {
127         if (m_memoryStore)
128             m_memoryStore->calculateAndSubmitTelemetry();
129     });
130
131     m_dailyTasksTimer.startRepeating(24_h);
132 }
133
134 WebResourceLoadStatisticsStore::~WebResourceLoadStatisticsStore()
135 {
136     ASSERT(RunLoop::isMain());
137
138     flushAndDestroyPersistentStore();
139 }
140
141 void WebResourceLoadStatisticsStore::flushAndDestroyPersistentStore()
142 {
143     ASSERT(RunLoop::isMain());
144
145     if (!m_persistentStorage && !m_memoryStore)
146         return;
147
148     // Make sure we destroy the persistent store on the background queue and wait for it to die
149     // synchronously since it has a C++ reference to us.
150     BinarySemaphore semaphore;
151     m_statisticsQueue->dispatch([&semaphore, this] {
152         m_persistentStorage = nullptr;
153         m_memoryStore = nullptr;
154         semaphore.signal();
155     });
156     semaphore.wait(WallTime::infinity());
157 }
158
159 void WebResourceLoadStatisticsStore::setResourceLoadStatisticsDebugMode(bool value)
160 {
161     ASSERT(RunLoop::isMain());
162
163     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), value] {
164         if (m_memoryStore)
165             m_memoryStore->setResourceLoadStatisticsDebugMode(value);
166     });
167 }
168
169 void WebResourceLoadStatisticsStore::scheduleStatisticsAndDataRecordsProcessing()
170 {
171     ASSERT(RunLoop::isMain());
172
173     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this)] {
174         if (m_memoryStore)
175             m_memoryStore->processStatisticsAndDataRecords();
176     });
177 }
178
179 void WebResourceLoadStatisticsStore::resourceLoadStatisticsUpdated(Vector<WebCore::ResourceLoadStatistics>&& origins)
180 {
181     ASSERT(RunLoop::isMain());
182
183     // It is safe to move the origins to the background queue without isolated copy here because this is an r-value
184     // coming from IPC. ResourceLoadStatistics only contains strings which are safe to move to other threads as long
185     // as nobody on this thread holds a reference to those strings.
186     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), origins = WTFMove(origins)]() mutable {
187         if (!m_memoryStore)
188             return;
189
190         m_memoryStore->mergeStatistics(WTFMove(origins));
191
192         // We can cancel any pending request to process statistics since we're doing it synchronously below.
193         m_memoryStore->cancelPendingStatisticsProcessingRequest();
194
195         // Fire before processing statistics to propagate user interaction as fast as possible to the network process.
196         m_memoryStore->updateCookiePartitioning([]() { });
197         m_memoryStore->processStatisticsAndDataRecords();
198     });
199 }
200
201 void WebResourceLoadStatisticsStore::hasStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, CompletionHandler<void (bool)>&& completionHandler)
202 {
203     ASSERT(subFrameHost != topFrameHost);
204     ASSERT(RunLoop::isMain());
205
206     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), subFramePrimaryDomain = isolatedPrimaryDomain(subFrameHost), topFramePrimaryDomain = isolatedPrimaryDomain(topFrameHost), frameID, pageID, completionHandler = WTFMove(completionHandler)] () mutable {
207         if (!m_memoryStore) {
208             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] {
209                 completionHandler(false);
210             });
211             return;
212         }
213         m_memoryStore->hasStorageAccess(subFramePrimaryDomain, topFramePrimaryDomain, frameID, pageID, [completionHandler = WTFMove(completionHandler)](bool hasStorageAccess) mutable {
214             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), hasStorageAccess] {
215                 completionHandler(hasStorageAccess);
216             });
217         });
218     });
219 }
220
221 void WebResourceLoadStatisticsStore::callHasStorageAccessForFrameHandler(const String& resourceDomain, const String& firstPartyDomain, uint64_t frameID, uint64_t pageID, Function<void(bool hasAccess)>&& callback)
222 {
223     ASSERT(RunLoop::isMain());
224
225 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
226     if (m_websiteDataStore) {
227         m_websiteDataStore->hasStorageAccessForFrameHandler(resourceDomain, firstPartyDomain, frameID, pageID, WTFMove(callback));
228         return;
229     }
230 #endif
231     callback(false);
232 }
233
234 void WebResourceLoadStatisticsStore::requestStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool promptEnabled, CompletionHandler<void(StorageAccessStatus)>&& completionHandler)
235 {
236     ASSERT(subFrameHost != topFrameHost);
237     ASSERT(RunLoop::isMain());
238
239     auto subFramePrimaryDomain = isolatedPrimaryDomain(subFrameHost);
240     auto topFramePrimaryDomain = isolatedPrimaryDomain(topFrameHost);
241     if (subFramePrimaryDomain == topFramePrimaryDomain) {
242         completionHandler(StorageAccessStatus::HasAccess);
243         return;
244     }
245
246     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), subFramePrimaryDomain = crossThreadCopy(subFramePrimaryDomain), topFramePrimaryDomain = crossThreadCopy(topFramePrimaryDomain), frameID, pageID, promptEnabled, completionHandler = WTFMove(completionHandler)] () mutable {
247         if (!m_memoryStore) {
248             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] {
249                 completionHandler(StorageAccessStatus::CannotRequestAccess);
250             });
251             return;
252         }
253
254         m_memoryStore->requestStorageAccess(WTFMove(subFramePrimaryDomain), WTFMove(topFramePrimaryDomain), frameID, pageID, promptEnabled, [completionHandler = WTFMove(completionHandler)](StorageAccessStatus status) mutable {
255             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), status] {
256                 completionHandler(status);
257             });
258         });
259     });
260 }
261
262 void WebResourceLoadStatisticsStore::requestStorageAccessUnderOpener(String&& primaryDomainInNeedOfStorageAccess, uint64_t openerPageID, String&& openerPrimaryDomain, bool isTriggeredByUserGesture)
263 {
264     ASSERT(RunLoop::isMain());
265
266     // It is safe to move the strings to the background queue without isolated copy here because they are r-value references
267     // coming from IPC. Strings which are safe to move to other threads as long as nobody on this thread holds a reference
268     // to those strings.
269     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomainInNeedOfStorageAccess = WTFMove(primaryDomainInNeedOfStorageAccess), openerPageID, openerPrimaryDomain = WTFMove(openerPrimaryDomain), isTriggeredByUserGesture]() mutable {
270         if (m_memoryStore)
271             m_memoryStore->requestStorageAccessUnderOpener(WTFMove(primaryDomainInNeedOfStorageAccess), openerPageID, WTFMove(openerPrimaryDomain), isTriggeredByUserGesture);
272     });
273 }
274
275 void WebResourceLoadStatisticsStore::grantStorageAccess(String&& subFrameHost, String&& topFrameHost, uint64_t frameID, uint64_t pageID, bool userWasPromptedNow, CompletionHandler<void(bool)>&& completionHandler)
276 {
277     ASSERT(RunLoop::isMain());
278     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), subFrameHost = crossThreadCopy(subFrameHost), topFrameHost = crossThreadCopy(topFrameHost), frameID, pageID, userWasPromptedNow, completionHandler = WTFMove(completionHandler)] () mutable {
279         if (!m_memoryStore) {
280             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] {
281                 completionHandler(false);
282             });
283             return;
284         }
285
286         m_memoryStore->grantStorageAccess(WTFMove(subFrameHost), WTFMove(topFrameHost), frameID, pageID, userWasPromptedNow, [completionHandler = WTFMove(completionHandler)](bool wasGrantedAccess) mutable {
287             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), wasGrantedAccess] {
288                 completionHandler(wasGrantedAccess);
289             });
290         });
291     });
292 }
293
294 void WebResourceLoadStatisticsStore::callGrantStorageAccessHandler(const String& subFramePrimaryDomain, const String& topFramePrimaryDomain, std::optional<uint64_t> frameID, uint64_t pageID, CompletionHandler<void(bool)>&& callback)
295 {
296     ASSERT(RunLoop::isMain());
297
298 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
299     if (m_websiteDataStore) {
300         m_websiteDataStore->grantStorageAccessHandler(subFramePrimaryDomain, topFramePrimaryDomain, frameID, pageID, WTFMove(callback));
301         return;
302     }
303 #endif
304     callback(false);
305 }
306
307 void WebResourceLoadStatisticsStore::removeAllStorageAccess()
308 {
309     ASSERT(RunLoop::isMain());
310
311 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
312     if (m_websiteDataStore)
313         m_websiteDataStore->removeAllStorageAccessHandler();
314 #endif
315 }
316
317
318 void WebResourceLoadStatisticsStore::processWillOpenConnection(WebProcessProxy& process, IPC::Connection&)
319 {
320     process.addMessageReceiver(Messages::WebResourceLoadStatisticsStore::messageReceiverName(), *this);
321 }
322
323 void WebResourceLoadStatisticsStore::processDidCloseConnection(WebProcessProxy& process, IPC::Connection&)
324 {
325     process.removeMessageReceiver(Messages::WebResourceLoadStatisticsStore::messageReceiverName());
326 }
327
328 void WebResourceLoadStatisticsStore::applicationWillTerminate()
329 {
330     flushAndDestroyPersistentStore();
331 }
332
333 void WebResourceLoadStatisticsStore::performDailyTasks()
334 {
335     ASSERT(RunLoop::isMain());
336
337     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this)] {
338         if (!m_memoryStore)
339             return;
340
341         m_memoryStore->includeTodayAsOperatingDateIfNecessary();
342         m_memoryStore->calculateAndSubmitTelemetry();
343     });
344 }
345
346 void WebResourceLoadStatisticsStore::submitTelemetry()
347 {
348     ASSERT(RunLoop::isMain());
349
350     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this)] {
351         if (m_memoryStore)
352             WebResourceLoadStatisticsTelemetry::calculateAndSubmit(*m_memoryStore);
353     });
354 }
355
356 void WebResourceLoadStatisticsStore::logFrameNavigation(const WebFrameProxy& frame, const URL& pageURL, const WebCore::ResourceRequest& request, const WebCore::URL& redirectURL)
357 {
358     ASSERT(RunLoop::isMain());
359
360     auto sourceURL = redirectURL;
361     bool isRedirect = !redirectURL.isNull();
362     if (!isRedirect) {
363         sourceURL = frame.url();
364         if (sourceURL.isNull())
365             sourceURL = pageURL;
366     }
367
368     auto& targetURL = request.url();
369
370     if (!targetURL.isValid() || !pageURL.isValid())
371         return;
372
373     auto targetHost = targetURL.host();
374     auto mainFrameHost = pageURL.host();
375
376     if (targetHost.isEmpty() || mainFrameHost.isEmpty() || targetHost == sourceURL.host())
377         return;
378
379     auto* page = frame.page();
380     auto targetPrimaryDomain = ResourceLoadStatistics::primaryDomain(targetURL);
381     auto mainFramePrimaryDomain = ResourceLoadStatistics::primaryDomain(pageURL);
382     auto sourcePrimaryDomain = ResourceLoadStatistics::primaryDomain(sourceURL);
383
384     bool areTargetAndMainFrameDomainsAssociated = areDomainsAssociated(page, targetPrimaryDomain, mainFramePrimaryDomain);
385     bool areTargetAndSourceDomainsAssociated = areDomainsAssociated(page, targetPrimaryDomain, sourcePrimaryDomain);
386
387     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), targetPrimaryDomain = targetPrimaryDomain.isolatedCopy(), mainFramePrimaryDomain = mainFramePrimaryDomain.isolatedCopy(), sourcePrimaryDomain = sourcePrimaryDomain.isolatedCopy(), targetHost = targetHost.toString().isolatedCopy(), mainFrameHost = mainFrameHost.toString().isolatedCopy(), areTargetAndMainFrameDomainsAssociated, areTargetAndSourceDomainsAssociated, isRedirect, isMainFrame = frame.isMainFrame()] {
388         if (m_memoryStore)
389             m_memoryStore->logFrameNavigation(targetPrimaryDomain, mainFramePrimaryDomain, sourcePrimaryDomain, targetHost, mainFrameHost, areTargetAndMainFrameDomainsAssociated, areTargetAndSourceDomainsAssociated, isRedirect, isMainFrame);
390     });
391 }
392
393 void WebResourceLoadStatisticsStore::logUserInteraction(const URL& url)
394 {
395     ASSERT(RunLoop::isMain());
396
397     if (url.isBlankURL() || url.isEmpty())
398         return;
399
400     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url)] {
401         if (m_memoryStore)
402             m_memoryStore->logUserInteraction(primaryDomain);
403     });
404 }
405
406 void WebResourceLoadStatisticsStore::logNonRecentUserInteraction(const URL& url)
407 {
408     ASSERT(RunLoop::isMain());
409
410     if (url.isBlankURL() || url.isEmpty())
411         return;
412     
413     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url)] {
414         if (m_memoryStore)
415             m_memoryStore->logNonRecentUserInteraction(primaryDomain);
416     });
417 }
418
419 void WebResourceLoadStatisticsStore::clearUserInteraction(const URL& url)
420 {
421     ASSERT(RunLoop::isMain());
422
423     if (url.isBlankURL() || url.isEmpty())
424         return;
425
426     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url)] {
427         if (m_memoryStore)
428             m_memoryStore->clearUserInteraction(primaryDomain);
429     });
430 }
431
432 void WebResourceLoadStatisticsStore::hasHadUserInteraction(const URL& url, CompletionHandler<void (bool)>&& completionHandler)
433 {
434     ASSERT(RunLoop::isMain());
435
436     if (url.isBlankURL() || url.isEmpty()) {
437         completionHandler(false);
438         return;
439     }
440
441     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)] () mutable {
442         bool hadUserInteraction = m_memoryStore ? m_memoryStore->hasHadUserInteraction(primaryDomain) : false;
443         RunLoop::main().dispatch([hadUserInteraction, completionHandler = WTFMove(completionHandler)] {
444             completionHandler(hadUserInteraction);
445         });
446     });
447 }
448
449 void WebResourceLoadStatisticsStore::setLastSeen(const URL& url, Seconds seconds)
450 {
451     ASSERT(RunLoop::isMain());
452
453     if (url.isBlankURL() || url.isEmpty())
454         return;
455     
456     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url), seconds] {
457         if (m_memoryStore)
458             m_memoryStore->setLastSeen(primaryDomain, seconds);
459     });
460 }
461     
462 void WebResourceLoadStatisticsStore::setPrevalentResource(const URL& url)
463 {
464     ASSERT(RunLoop::isMain());
465
466     if (url.isBlankURL() || url.isEmpty())
467         return;
468
469     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url)] {
470         if (m_memoryStore)
471             m_memoryStore->setPrevalentResource(primaryDomain);
472     });
473 }
474
475 void WebResourceLoadStatisticsStore::setVeryPrevalentResource(const URL& url)
476 {
477     ASSERT(RunLoop::isMain());
478
479     if (url.isBlankURL() || url.isEmpty())
480         return;
481     
482     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url)] {
483         if (m_memoryStore)
484             m_memoryStore->setVeryPrevalentResource(primaryDomain);
485     });
486 }
487
488 void WebResourceLoadStatisticsStore::isPrevalentResource(const URL& url, CompletionHandler<void (bool)>&& completionHandler)
489 {
490     ASSERT(RunLoop::isMain());
491
492     if (url.isBlankURL() || url.isEmpty()) {
493         completionHandler(false);
494         return;
495     }
496
497     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)] () mutable {
498         bool isPrevalentResource = m_memoryStore ? m_memoryStore->isPrevalentResource(primaryDomain) : false;
499         RunLoop::main().dispatch([isPrevalentResource, completionHandler = WTFMove(completionHandler)] {
500             completionHandler(isPrevalentResource);
501         });
502     });
503 }
504
505 void WebResourceLoadStatisticsStore::isVeryPrevalentResource(const URL& url, CompletionHandler<void(bool)>&& completionHandler)
506 {
507     ASSERT(RunLoop::isMain());
508
509     if (url.isBlankURL() || url.isEmpty()) {
510         completionHandler(false);
511         return;
512     }
513     
514     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url), completionHandler = WTFMove(completionHandler)] () mutable {
515         bool isVeryPrevalentResource = m_memoryStore ? m_memoryStore->isVeryPrevalentResource(primaryDomain) : false;
516         RunLoop::main().dispatch([isVeryPrevalentResource, completionHandler = WTFMove(completionHandler)] {
517             completionHandler(isVeryPrevalentResource);
518         });
519     });
520 }
521
522 void WebResourceLoadStatisticsStore::isRegisteredAsSubFrameUnder(const URL& subFrame, const URL& topFrame, CompletionHandler<void (bool)>&& completionHandler)
523 {
524     ASSERT(RunLoop::isMain());
525
526     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), subFramePrimaryDomain = isolatedPrimaryDomain(subFrame), topFramePrimaryDomain = isolatedPrimaryDomain(topFrame), completionHandler = WTFMove(completionHandler)] () mutable {
527         bool isRegisteredAsSubFrameUnder = m_memoryStore ? m_memoryStore->isRegisteredAsSubFrameUnder(subFramePrimaryDomain, topFramePrimaryDomain) : false;
528         RunLoop::main().dispatch([isRegisteredAsSubFrameUnder, completionHandler = WTFMove(completionHandler)] {
529             completionHandler(isRegisteredAsSubFrameUnder);
530         });
531     });
532 }
533
534 void WebResourceLoadStatisticsStore::isRegisteredAsRedirectingTo(const URL& hostRedirectedFrom, const URL& hostRedirectedTo, CompletionHandler<void (bool)>&& completionHandler)
535 {
536     ASSERT(RunLoop::isMain());
537
538     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), hostRedirectedFromPrimaryDomain = isolatedPrimaryDomain(hostRedirectedFrom), hostRedirectedToPrimaryDomain = isolatedPrimaryDomain(hostRedirectedTo), completionHandler = WTFMove(completionHandler)] () mutable {
539         bool isRegisteredAsRedirectingTo = m_memoryStore ? m_memoryStore->isRegisteredAsRedirectingTo(hostRedirectedFromPrimaryDomain, hostRedirectedToPrimaryDomain) : false;
540         RunLoop::main().dispatch([isRegisteredAsRedirectingTo, completionHandler = WTFMove(completionHandler)] {
541             completionHandler(isRegisteredAsRedirectingTo);
542         });
543     });
544 }
545
546 void WebResourceLoadStatisticsStore::clearPrevalentResource(const URL& url)
547 {
548     ASSERT(RunLoop::isMain());
549
550     if (url.isBlankURL() || url.isEmpty())
551         return;
552
553     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url)] {
554         if (m_memoryStore)
555             m_memoryStore->clearPrevalentResource(primaryDomain);
556     });
557 }
558
559 void WebResourceLoadStatisticsStore::setGrandfathered(const URL& url, bool value)
560 {
561     ASSERT(RunLoop::isMain());
562
563     if (url.isBlankURL() || url.isEmpty())
564         return;
565
566     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryDomain = isolatedPrimaryDomain(url), value] {
567         if (m_memoryStore)
568             m_memoryStore->setGrandfathered(primaryDomain, value);
569     });
570 }
571
572 void WebResourceLoadStatisticsStore::isGrandfathered(const URL& url, CompletionHandler<void (bool)>&& completionHandler)
573 {
574     ASSERT(RunLoop::isMain());
575
576     if (url.isBlankURL() || url.isEmpty()) {
577         completionHandler(false);
578         return;
579     }
580
581     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler), primaryDomain = isolatedPrimaryDomain(url)] () mutable {
582         bool isGrandFathered = m_memoryStore ? m_memoryStore->isGrandfathered(primaryDomain) : false;
583         RunLoop::main().dispatch([isGrandFathered, completionHandler = WTFMove(completionHandler)] {
584             completionHandler(isGrandFathered);
585         });
586     });
587 }
588
589 void WebResourceLoadStatisticsStore::setSubframeUnderTopFrameOrigin(const URL& subframe, const URL& topFrame)
590 {
591     ASSERT(RunLoop::isMain());
592
593     if (subframe.isBlankURL() || subframe.isEmpty() || topFrame.isBlankURL() || topFrame.isEmpty())
594         return;
595
596     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryTopFrameDomain = isolatedPrimaryDomain(topFrame), primarySubFrameDomain = isolatedPrimaryDomain(subframe)] {
597         if (m_memoryStore)
598             m_memoryStore->setSubframeUnderTopFrameOrigin(primarySubFrameDomain, primaryTopFrameDomain);
599     });
600 }
601
602 void WebResourceLoadStatisticsStore::setSubresourceUnderTopFrameOrigin(const URL& subresource, const URL& topFrame)
603 {
604     ASSERT(RunLoop::isMain());
605
606     if (subresource.isBlankURL() || subresource.isEmpty() || topFrame.isBlankURL() || topFrame.isEmpty())
607         return;
608
609     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryTopFrameDomain = isolatedPrimaryDomain(topFrame), primarySubresourceDomain = isolatedPrimaryDomain(subresource)] {
610         if (m_memoryStore)
611             m_memoryStore->setSubresourceUnderTopFrameOrigin(primarySubresourceDomain, primaryTopFrameDomain);
612     });
613 }
614
615 void WebResourceLoadStatisticsStore::setSubresourceUniqueRedirectTo(const URL& subresource, const URL& hostNameRedirectedTo)
616 {
617     ASSERT(RunLoop::isMain());
618
619     if (subresource.isBlankURL() || subresource.isEmpty() || hostNameRedirectedTo.isBlankURL() || hostNameRedirectedTo.isEmpty())
620         return;
621
622     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryRedirectDomain = isolatedPrimaryDomain(hostNameRedirectedTo), primarySubresourceDomain = isolatedPrimaryDomain(subresource)] {
623         if (m_memoryStore)
624             m_memoryStore->setSubresourceUniqueRedirectTo(primarySubresourceDomain, primaryRedirectDomain);
625     });
626 }
627
628 void WebResourceLoadStatisticsStore::setSubresourceUniqueRedirectFrom(const URL& subresource, const URL& hostNameRedirectedFrom)
629 {
630     ASSERT(RunLoop::isMain());
631
632     if (subresource.isBlankURL() || subresource.isEmpty() || hostNameRedirectedFrom.isBlankURL() || hostNameRedirectedFrom.isEmpty())
633         return;
634     
635     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryRedirectDomain = isolatedPrimaryDomain(hostNameRedirectedFrom), primarySubresourceDomain = isolatedPrimaryDomain(subresource)] {
636         if (m_memoryStore)
637             m_memoryStore->setSubresourceUniqueRedirectFrom(primarySubresourceDomain, primaryRedirectDomain);
638     });
639 }
640
641 void WebResourceLoadStatisticsStore::setTopFrameUniqueRedirectTo(const URL& topFrameHostName, const URL& hostNameRedirectedTo)
642 {
643     ASSERT(RunLoop::isMain());
644
645     if (topFrameHostName.isBlankURL() || topFrameHostName.isEmpty() || hostNameRedirectedTo.isBlankURL() || hostNameRedirectedTo.isEmpty())
646         return;
647     
648     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryRedirectDomain = isolatedPrimaryDomain(hostNameRedirectedTo), topFramePrimaryDomain = isolatedPrimaryDomain(topFrameHostName)] {
649         if (m_memoryStore)
650             m_memoryStore->setTopFrameUniqueRedirectTo(topFramePrimaryDomain, primaryRedirectDomain);
651     });
652 }
653
654 void WebResourceLoadStatisticsStore::setTopFrameUniqueRedirectFrom(const URL& topFrameHostName, const URL& hostNameRedirectedFrom)
655 {
656     ASSERT(RunLoop::isMain());
657
658     if (topFrameHostName.isBlankURL() || topFrameHostName.isEmpty() || hostNameRedirectedFrom.isBlankURL() || hostNameRedirectedFrom.isEmpty())
659         return;
660     
661     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), primaryRedirectDomain = isolatedPrimaryDomain(hostNameRedirectedFrom), topFramePrimaryDomain = isolatedPrimaryDomain(topFrameHostName)] {
662         if (m_memoryStore)
663             m_memoryStore->setTopFrameUniqueRedirectFrom(topFramePrimaryDomain, primaryRedirectDomain);
664     });
665 }
666
667 void WebResourceLoadStatisticsStore::scheduleCookiePartitioningUpdate(CompletionHandler<void()>&& completionHandler)
668 {
669     // Helper function used by testing system. Should only be called from the main thread.
670     ASSERT(RunLoop::isMain());
671
672     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] () mutable {
673         if (!m_memoryStore) {
674             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
675                 completionHandler();
676             });
677             return;
678         }
679         m_memoryStore->updateCookiePartitioning([completionHandler = WTFMove(completionHandler)]() mutable {
680             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
681                 completionHandler();
682             });
683         });
684     });
685 }
686
687 void WebResourceLoadStatisticsStore::scheduleCookiePartitioningUpdateForDomains(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst shouldClearFirst, CompletionHandler<void()>&& completionHandler)
688 {
689     // Helper function used by testing system. Should only be called from the main thread.
690     ASSERT(RunLoop::isMain());
691     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), domainsToPartition = crossThreadCopy(domainsToPartition), domainsToBlock = crossThreadCopy(domainsToBlock), domainsToNeitherPartitionNorBlock = crossThreadCopy(domainsToNeitherPartitionNorBlock), shouldClearFirst, completionHandler = WTFMove(completionHandler)] () mutable {
692         if (!m_memoryStore) {
693             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
694                 completionHandler();
695             });
696             return;
697         }
698
699         m_memoryStore->updateCookiePartitioningForDomains(domainsToPartition, domainsToBlock, domainsToNeitherPartitionNorBlock, shouldClearFirst, [completionHandler = WTFMove(completionHandler)]() mutable {
700             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
701                 completionHandler();
702             });
703         });
704     });
705 }
706
707 void WebResourceLoadStatisticsStore::scheduleClearPartitioningStateForDomains(const Vector<String>& domains, CompletionHandler<void()>&& completionHandler)
708 {
709     // Helper function used by testing system. Should only be called from the main thread.
710     ASSERT(RunLoop::isMain());
711     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), domains = crossThreadCopy(domains), completionHandler = WTFMove(completionHandler)] () mutable {
712         if (!m_memoryStore) {
713             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
714                 completionHandler();
715             });
716             return;
717         }
718
719         m_memoryStore->clearPartitioningStateForDomains(domains, [completionHandler = WTFMove(completionHandler)]() mutable {
720             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)]() {
721                 completionHandler();
722             });
723         });
724     });
725 }
726
727 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
728 void WebResourceLoadStatisticsStore::scheduleCookiePartitioningStateReset()
729 {
730     ASSERT(RunLoop::isMain());
731     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this)] {
732         if (m_memoryStore)
733             m_memoryStore->resetCookiePartitioningState();
734     });
735 }
736 #endif
737
738 void WebResourceLoadStatisticsStore::scheduleClearInMemory()
739 {
740     ASSERT(RunLoop::isMain());
741     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this)] {
742         if (m_memoryStore)
743             m_memoryStore->clear();
744     });
745 }
746
747 void WebResourceLoadStatisticsStore::scheduleClearInMemoryAndPersistent(ShouldGrandfather shouldGrandfather, CompletionHandler<void()>&& completionHandler)
748 {
749     ASSERT(RunLoop::isMain());
750     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), shouldGrandfather, completionHandler = WTFMove(completionHandler)] () mutable {
751         if (m_memoryStore)
752             m_memoryStore->clear();
753         if (m_persistentStorage)
754             m_persistentStorage->clear();
755         
756         CompletionHandler<void()> callCompletionHandlerOnMainThread = [completionHandler = WTFMove(completionHandler)]() mutable {
757             RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler)] {
758                 completionHandler();
759             });
760         };
761
762         if (shouldGrandfather == ShouldGrandfather::Yes && m_memoryStore)
763             m_memoryStore->grandfatherExistingWebsiteData(WTFMove(callCompletionHandlerOnMainThread));
764         else
765             callCompletionHandlerOnMainThread();
766     });
767 }
768
769 void WebResourceLoadStatisticsStore::scheduleClearInMemoryAndPersistent(WallTime modifiedSince, ShouldGrandfather shouldGrandfather, CompletionHandler<void()>&& callback)
770 {
771     ASSERT(RunLoop::isMain());
772
773     // For now, be conservative and clear everything regardless of modifiedSince.
774     UNUSED_PARAM(modifiedSince);
775     scheduleClearInMemoryAndPersistent(shouldGrandfather, WTFMove(callback));
776 }
777
778 void WebResourceLoadStatisticsStore::setTimeToLiveUserInteraction(Seconds seconds)
779 {
780     ASSERT(RunLoop::isMain());
781     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), seconds] {
782         if (m_memoryStore)
783             m_memoryStore->setTimeToLiveUserInteraction(seconds);
784     });
785 }
786
787 void WebResourceLoadStatisticsStore::setTimeToLiveCookiePartitionFree(Seconds seconds)
788 {
789     ASSERT(RunLoop::isMain());
790     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), seconds] {
791         if (m_memoryStore)
792             m_memoryStore->setTimeToLiveCookiePartitionFree(seconds);
793     });
794 }
795
796 void WebResourceLoadStatisticsStore::setMinimumTimeBetweenDataRecordsRemoval(Seconds seconds)
797 {
798     ASSERT(RunLoop::isMain());
799     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), seconds] {
800         if (m_memoryStore)
801             m_memoryStore->setMinimumTimeBetweenDataRecordsRemoval(seconds);
802     });
803 }
804
805 void WebResourceLoadStatisticsStore::setGrandfatheringTime(Seconds seconds)
806 {
807     ASSERT(RunLoop::isMain());
808     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), seconds] {
809         if (m_memoryStore)
810             m_memoryStore->setGrandfatheringTime(seconds);
811     });
812 }
813
814 void WebResourceLoadStatisticsStore::callUpdatePrevalentDomainsToPartitionOrBlockCookiesHandler(const Vector<String>& domainsToPartition, const Vector<String>& domainsToBlock, const Vector<String>& domainsToNeitherPartitionNorBlock, ShouldClearFirst shouldClearFirst, CompletionHandler<void()>&& completionHandler)
815 {
816     ASSERT(RunLoop::isMain());
817
818 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
819     if (m_websiteDataStore) {
820         m_websiteDataStore->updatePrevalentDomainsToPartitionOrBlockCookies(domainsToPartition, domainsToBlock, domainsToNeitherPartitionNorBlock, shouldClearFirst, WTFMove(completionHandler));
821         return;
822     }
823 #endif
824     completionHandler();
825 }
826
827 void WebResourceLoadStatisticsStore::callRemoveDomainsHandler(const Vector<String>& domains)
828 {
829     ASSERT(RunLoop::isMain());
830
831 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
832     if (m_websiteDataStore)
833         m_websiteDataStore->removePrevalentDomains(domains);
834 #endif
835 }
836     
837 void WebResourceLoadStatisticsStore::setMaxStatisticsEntries(size_t maximumEntryCount)
838 {
839     ASSERT(RunLoop::isMain());
840     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), maximumEntryCount] {
841         if (m_memoryStore)
842             m_memoryStore->setMaxStatisticsEntries(maximumEntryCount);
843     });
844 }
845     
846 void WebResourceLoadStatisticsStore::setPruneEntriesDownTo(size_t pruneTargetCount)
847 {
848     ASSERT(RunLoop::isMain());
849
850     m_statisticsQueue->dispatch([this, protectedThis = makeRef(*this), pruneTargetCount] {
851         if (m_memoryStore)
852             m_memoryStore->setPruneEntriesDownTo(pruneTargetCount);
853     });
854 }
855
856 void WebResourceLoadStatisticsStore::resetParametersToDefaultValues()
857 {
858     ASSERT(RunLoop::isMain());
859
860     m_statisticsQueue->dispatch([this, protectedThis(makeRef(*this))] {
861         if (m_memoryStore)
862             m_memoryStore->resetParametersToDefaultValues();
863     });
864 }
865
866 void WebResourceLoadStatisticsStore::logTestingEvent(const String& event)
867 {
868     ASSERT(RunLoop::isMain());
869
870     if (m_statisticsTestingCallback)
871         m_statisticsTestingCallback(event);
872 }
873
874 } // namespace WebKit