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