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