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