Skip to content

Commit

Permalink
Storage Access API: Allow configurable storage access scope
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=212114
<rdar://problem/63423063>

Reviewed by Alex Christensen.

The scope of storage access as per-frame or per-page was discussed in the
standards process here: privacycg/storage-access#3

The decision was to have per-page storage access by default. Recent feedback
from Google and conversation with Mozilla suggest that we might want to
support the caller choosing the scope.

This patch adds support for different scope configurations while keeping the
existing default as per-frame. A later patch will switch the default and add
test cases for per-page scope.

Source/WebCore:

A new struct is added WebCore::RequestStorageAccessResult which carries full
information about the storage access request result.

A new enum is added WebCore::StorageAccessScope to encode per-frame and
per-page access.

No new tests. No changed functionality. Tests already exist.

* dom/DocumentStorageAccess.cpp:
(WebCore::DocumentStorageAccess::requestStorageAccess):
* dom/DocumentStorageAccess.h:
(WebCore::RequestStorageAccessResult::encode const):
(WebCore::RequestStorageAccessResult::decode):
* page/ChromeClient.h:
(WebCore::ChromeClient::requestStorageAccess):

Source/WebKit:

Most of the changes is piping through the new enum
WebCore::StorageAccessScope from the call side to encode per-frame and
per-page access, and piping through the new struct
WebCore::RequestStorageAccessResult on the return side which carries full
information about the storage access request result.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::CompletionHandler<void):
* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp:
(WebKit::ResourceLoadStatisticsMemoryStore::requestStorageAccess):
(WebKit::ResourceLoadStatisticsMemoryStore::requestStorageAccessUnderOpener):
(WebKit::ResourceLoadStatisticsMemoryStore::grantStorageAccess):
(WebKit::ResourceLoadStatisticsMemoryStore::grantStorageAccessInternal):
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsStore.h:
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::requestStorageAccess):
(WebKit::WebResourceLoadStatisticsStore::requestStorageAccessEphemeral):
(WebKit::WebResourceLoadStatisticsStore::grantStorageAccess):
(WebKit::WebResourceLoadStatisticsStore::grantStorageAccessEphemeral):
(WebKit::WebResourceLoadStatisticsStore::grantStorageAccessInStorageSession):
    Renamed from WebResourceLoadStatisticsStore::grantStorageAccess()
    to reduce confusion since we already have another function called
    WebResourceLoadStatisticsStore::grantStorageAccess().
(WebKit::WebResourceLoadStatisticsStore::callGrantStorageAccessHandler):
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h:
* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::requestStorageAccess):
* NetworkProcess/NetworkConnectionToWebProcess.h:
* NetworkProcess/NetworkConnectionToWebProcess.messages.in:
* Scripts/webkit/messages.py:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::requestStorageAccess):
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::requestStorageAccess):
* WebProcess/WebPage/WebPage.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@262024 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
wilander@apple.com committed May 21, 2020
1 parent 5c78a47 commit 3fe9ed1
Show file tree
Hide file tree
Showing 20 changed files with 246 additions and 88 deletions.
35 changes: 35 additions & 0 deletions Source/WebCore/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
2020-05-21 John Wilander <wilander@apple.com>

Storage Access API: Allow configurable storage access scope
https://bugs.webkit.org/show_bug.cgi?id=212114
<rdar://problem/63423063>

Reviewed by Alex Christensen.

The scope of storage access as per-frame or per-page was discussed in the
standards process here: https://github.com/privacycg/storage-access/issues/3

The decision was to have per-page storage access by default. Recent feedback
from Google and conversation with Mozilla suggest that we might want to
support the caller choosing the scope.

This patch adds support for different scope configurations while keeping the
existing default as per-frame. A later patch will switch the default and add
test cases for per-page scope.

A new struct is added WebCore::RequestStorageAccessResult which carries full
information about the storage access request result.

A new enum is added WebCore::StorageAccessScope to encode per-frame and
per-page access.

No new tests. No changed functionality. Tests already exist.

* dom/DocumentStorageAccess.cpp:
(WebCore::DocumentStorageAccess::requestStorageAccess):
* dom/DocumentStorageAccess.h:
(WebCore::RequestStorageAccessResult::encode const):
(WebCore::RequestStorageAccessResult::decode):
* page/ChromeClient.h:
(WebCore::ChromeClient::requestStorageAccess):

2020-05-21 Yoshiaki Jitsukawa <yoshiaki.jitsukawa@sony.com>

[PlayStation] Add minimal WKView API to enable TestWebKitAPI
Expand Down
8 changes: 4 additions & 4 deletions Source/WebCore/dom/DocumentStorageAccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,12 @@ void DocumentStorageAccess::requestStorageAccess(Ref<DeferredPromise>&& promise)
auto subFrameDomain = RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host());
auto topFrameDomain = RegistrableDomain::uncheckedCreateFromHost(topSecurityOrigin.host());

page->chrome().client().requestStorageAccess(WTFMove(subFrameDomain), WTFMove(topFrameDomain), *frame, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (StorageAccessWasGranted wasGranted, StorageAccessPromptWasShown promptWasShown) mutable {
page->chrome().client().requestStorageAccess(WTFMove(subFrameDomain), WTFMove(topFrameDomain), *frame, m_storageAccessScope, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (RequestStorageAccessResult result) mutable {
if (!weakThis)
return;

// Consume the user gesture only if the user explicitly denied access.
bool shouldPreserveUserGesture = wasGranted == StorageAccessWasGranted::Yes || promptWasShown == StorageAccessPromptWasShown::No;
bool shouldPreserveUserGesture = result.wasGranted == StorageAccessWasGranted::Yes || result.promptWasShown == StorageAccessPromptWasShown::No;

if (shouldPreserveUserGesture) {
m_document.eventLoop().queueMicrotask([this, weakThis] {
Expand All @@ -188,10 +188,10 @@ void DocumentStorageAccess::requestStorageAccess(Ref<DeferredPromise>&& promise)
});
}

if (wasGranted == StorageAccessWasGranted::Yes)
if (result.wasGranted == StorageAccessWasGranted::Yes)
promise->resolve();
else {
if (promptWasShown == StorageAccessPromptWasShown::Yes)
if (result.promptWasShown == StorageAccessPromptWasShown::Yes)
setWasExplicitlyDeniedFrameSpecificStorageAccess();
promise->reject();
}
Expand Down
56 changes: 56 additions & 0 deletions Source/WebCore/dom/DocumentStorageAccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#if ENABLE(RESOURCE_LOAD_STATISTICS)

#include "RegistrableDomain.h"
#include "Supplementable.h"
#include <wtf/WeakPtr.h>

Expand All @@ -46,6 +47,22 @@ enum class StorageAccessPromptWasShown : bool {
Yes
};

enum class StorageAccessScope : bool {
PerFrame,
PerPage
};

struct RequestStorageAccessResult {
StorageAccessWasGranted wasGranted;
StorageAccessPromptWasShown promptWasShown;
StorageAccessScope scope;
RegistrableDomain topFrameDomain;
RegistrableDomain subFrameDomain;

template<class Encoder> void encode(Encoder&) const;
template<class Decoder> static Optional<RequestStorageAccessResult> decode(Decoder&);
};

const unsigned maxNumberOfTimesExplicitlyDeniedFrameSpecificStorageAccess = 2;

class DocumentStorageAccess final : public Supplement<Document>, public CanMakeWeakPtr<DocumentStorageAccess> {
Expand Down Expand Up @@ -73,8 +90,47 @@ class DocumentStorageAccess final : public Supplement<Document>, public CanMakeW
Document& m_document;

uint8_t m_numberOfTimesExplicitlyDeniedFrameSpecificStorageAccess = 0;

StorageAccessScope m_storageAccessScope = StorageAccessScope::PerFrame;
};

template<class Encoder>
void RequestStorageAccessResult::encode(Encoder& encoder) const
{
encoder << wasGranted << promptWasShown << scope << topFrameDomain << subFrameDomain;
}

template<class Decoder>
Optional<RequestStorageAccessResult> RequestStorageAccessResult::decode(Decoder& decoder)
{
Optional<StorageAccessWasGranted> wasGranted;
decoder >> wasGranted;
if (!wasGranted)
return WTF::nullopt;

Optional<StorageAccessPromptWasShown> promptWasShown;
decoder >> promptWasShown;
if (!promptWasShown)
return WTF::nullopt;

Optional<StorageAccessScope> scope;
decoder >> scope;
if (!scope)
return WTF::nullopt;

Optional<RegistrableDomain> topFrameDomain;
decoder >> topFrameDomain;
if (!topFrameDomain)
return WTF::nullopt;

Optional<RegistrableDomain> subFrameDomain;
decoder >> subFrameDomain;
if (!subFrameDomain)
return WTF::nullopt;

return { { WTFMove(*wasGranted), WTFMove(*promptWasShown), WTFMove(*scope), WTFMove(*topFrameDomain), WTFMove(*subFrameDomain) } };
}

} // namespace WebCore

#endif // ENABLE(RESOURCE_LOAD_STATISTICS)
2 changes: 1 addition & 1 deletion Source/WebCore/page/ChromeClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ class ChromeClient {

#if ENABLE(RESOURCE_LOAD_STATISTICS)
virtual void hasStorageAccess(RegistrableDomain&& /*subFrameDomain*/, RegistrableDomain&& /*topFrameDomain*/, Frame&, WTF::CompletionHandler<void(bool)>&& completionHandler) { completionHandler(false); }
virtual void requestStorageAccess(RegistrableDomain&& /*subFrameDomain*/, RegistrableDomain&& /*topFrameDomain*/, Frame&, WTF::CompletionHandler<void(StorageAccessWasGranted, StorageAccessPromptWasShown)>&& completionHandler) { completionHandler(StorageAccessWasGranted::No, StorageAccessPromptWasShown::No); }
virtual void requestStorageAccess(RegistrableDomain&& subFrameDomain, RegistrableDomain&& topFrameDomain, Frame&, StorageAccessScope scope, WTF::CompletionHandler<void(RequestStorageAccessResult)>&& completionHandler) { completionHandler({ StorageAccessWasGranted::No, StorageAccessPromptWasShown::No, scope, WTFMove(topFrameDomain), WTFMove(subFrameDomain) }); }
#endif

#if ENABLE(DEVICE_ORIENTATION)
Expand Down
58 changes: 58 additions & 0 deletions Source/WebKit/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,61 @@
2020-05-21 John Wilander <wilander@apple.com>

Storage Access API: Allow configurable storage access scope
https://bugs.webkit.org/show_bug.cgi?id=212114
<rdar://problem/63423063>

Reviewed by Alex Christensen.

The scope of storage access as per-frame or per-page was discussed in the
standards process here: https://github.com/privacycg/storage-access/issues/3

The decision was to have per-page storage access by default. Recent feedback
from Google and conversation with Mozilla suggest that we might want to
support the caller choosing the scope.

This patch adds support for different scope configurations while keeping the
existing default as per-frame. A later patch will switch the default and add
test cases for per-page scope.

Most of the changes is piping through the new enum
WebCore::StorageAccessScope from the call side to encode per-frame and
per-page access, and piping through the new struct
WebCore::RequestStorageAccessResult on the return side which carries full
information about the storage access request result.

* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.cpp:
(WebKit::CompletionHandler<void):
* NetworkProcess/Classifier/ResourceLoadStatisticsDatabaseStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.cpp:
(WebKit::ResourceLoadStatisticsMemoryStore::requestStorageAccess):
(WebKit::ResourceLoadStatisticsMemoryStore::requestStorageAccessUnderOpener):
(WebKit::ResourceLoadStatisticsMemoryStore::grantStorageAccess):
(WebKit::ResourceLoadStatisticsMemoryStore::grantStorageAccessInternal):
* NetworkProcess/Classifier/ResourceLoadStatisticsMemoryStore.h:
* NetworkProcess/Classifier/ResourceLoadStatisticsStore.h:
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.cpp:
(WebKit::WebResourceLoadStatisticsStore::requestStorageAccess):
(WebKit::WebResourceLoadStatisticsStore::requestStorageAccessEphemeral):
(WebKit::WebResourceLoadStatisticsStore::grantStorageAccess):
(WebKit::WebResourceLoadStatisticsStore::grantStorageAccessEphemeral):
(WebKit::WebResourceLoadStatisticsStore::grantStorageAccessInStorageSession):
Renamed from WebResourceLoadStatisticsStore::grantStorageAccess()
to reduce confusion since we already have another function called
WebResourceLoadStatisticsStore::grantStorageAccess().
(WebKit::WebResourceLoadStatisticsStore::callGrantStorageAccessHandler):
* NetworkProcess/Classifier/WebResourceLoadStatisticsStore.h:
* NetworkProcess/NetworkConnectionToWebProcess.cpp:
(WebKit::NetworkConnectionToWebProcess::requestStorageAccess):
* NetworkProcess/NetworkConnectionToWebProcess.h:
* NetworkProcess/NetworkConnectionToWebProcess.messages.in:
* Scripts/webkit/messages.py:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::requestStorageAccess):
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::requestStorageAccess):
* WebProcess/WebPage/WebPage.h:

2020-05-21 Yoshiaki Jitsukawa <yoshiaki.jitsukawa@sony.com>

[PlayStation] Add minimal WKView API to enable TestWebKitAPI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1510,7 +1510,7 @@ void ResourceLoadStatisticsDatabaseStore::hasStorageAccess(const SubFrameDomain&
});
}

void ResourceLoadStatisticsDatabaseStore::requestStorageAccess(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, FrameIdentifier frameID, PageIdentifier pageID, CompletionHandler<void(StorageAccessStatus)>&& completionHandler)
void ResourceLoadStatisticsDatabaseStore::requestStorageAccess(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, FrameIdentifier frameID, PageIdentifier pageID, StorageAccessScope scope, CompletionHandler<void(StorageAccessStatus)>&& completionHandler)
{
ASSERT(!RunLoop::isMain());

Expand Down Expand Up @@ -1566,7 +1566,7 @@ void ResourceLoadStatisticsDatabaseStore::requestStorageAccess(SubFrameDomain&&
return;
}

grantStorageAccessInternal(WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, userWasPromptedEarlier, [completionHandler = WTFMove(completionHandler)] (StorageAccessWasGranted wasGranted) mutable {
grantStorageAccessInternal(WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, userWasPromptedEarlier, scope, [completionHandler = WTFMove(completionHandler)] (StorageAccessWasGranted wasGranted) mutable {
completionHandler(wasGranted == StorageAccessWasGranted::Yes ? StorageAccessStatus::HasAccess : StorageAccessStatus::CannotRequestAccess);
});
}
Expand All @@ -1584,10 +1584,10 @@ void ResourceLoadStatisticsDatabaseStore::requestStorageAccessUnderOpener(Domain
debugBroadcastConsoleMessage(MessageSource::ITPDebug, MessageLevel::Info, makeString("[ITP] Storage access was granted for '"_s, domainInNeedOfStorageAccess.string(), "' under opener page from '"_s, openerDomain.string(), "', with user interaction in the opened window."_s));
}

grantStorageAccessInternal(WTFMove(domainInNeedOfStorageAccess), WTFMove(openerDomain), WTF::nullopt, openerPageID, StorageAccessPromptWasShown::No, [](StorageAccessWasGranted) { });
grantStorageAccessInternal(WTFMove(domainInNeedOfStorageAccess), WTFMove(openerDomain), WTF::nullopt, openerPageID, StorageAccessPromptWasShown::No, StorageAccessScope::PerPage, [](StorageAccessWasGranted) { });
}

void ResourceLoadStatisticsDatabaseStore::grantStorageAccess(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, FrameIdentifier frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShown, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
void ResourceLoadStatisticsDatabaseStore::grantStorageAccess(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, FrameIdentifier frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShown, StorageAccessScope scope, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
{
ASSERT(!RunLoop::isMain());

Expand All @@ -1602,10 +1602,10 @@ void ResourceLoadStatisticsDatabaseStore::grantStorageAccess(SubFrameDomain&& su
insertDomainRelationshipList(storageAccessUnderTopFrameDomainsQuery, HashSet<RegistrableDomain>({ topFrameDomain }), *subFrameStatus.second);
}

grantStorageAccessInternal(WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, promptWasShown, WTFMove(completionHandler));
grantStorageAccessInternal(WTFMove(subFrameDomain), WTFMove(topFrameDomain), frameID, pageID, promptWasShown, scope, WTFMove(completionHandler));
}

void ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, Optional<FrameIdentifier> frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShownNowOrEarlier, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
void ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal(SubFrameDomain&& subFrameDomain, TopFrameDomain&& topFrameDomain, Optional<FrameIdentifier> frameID, PageIdentifier pageID, StorageAccessPromptWasShown promptWasShownNowOrEarlier, StorageAccessScope scope, CompletionHandler<void(StorageAccessWasGranted)>&& completionHandler)
{
ASSERT(!RunLoop::isMain());

Expand All @@ -1628,8 +1628,8 @@ void ResourceLoadStatisticsDatabaseStore::grantStorageAccessInternal(SubFrameDom
setUserInteraction(subFrameDomain, true, WallTime::now());
}

RunLoop::main().dispatch([subFrameDomain = subFrameDomain.isolatedCopy(), topFrameDomain = topFrameDomain.isolatedCopy(), frameID, pageID, store = makeRef(store()), completionHandler = WTFMove(completionHandler)]() mutable {
store->callGrantStorageAccessHandler(subFrameDomain, topFrameDomain, frameID, pageID, [completionHandler = WTFMove(completionHandler), store = store.copyRef()](StorageAccessWasGranted wasGranted) mutable {
RunLoop::main().dispatch([subFrameDomain = subFrameDomain.isolatedCopy(), topFrameDomain = topFrameDomain.isolatedCopy(), frameID, pageID, store = makeRef(store()), scope, completionHandler = WTFMove(completionHandler)]() mutable {
store->callGrantStorageAccessHandler(subFrameDomain, topFrameDomain, frameID, pageID, scope, [completionHandler = WTFMove(completionHandler), store = store.copyRef()](StorageAccessWasGranted wasGranted) mutable {
store->statisticsQueue().dispatch([wasGranted, completionHandler = WTFMove(completionHandler)] () mutable {
completionHandler(wasGranted);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@ class ResourceLoadStatisticsDatabaseStore final : public ResourceLoadStatisticsS
void calculateAndSubmitTelemetry() const override;

void hasStorageAccess(const SubFrameDomain&, const TopFrameDomain&, Optional<WebCore::FrameIdentifier>, WebCore::PageIdentifier, CompletionHandler<void(bool)>&&) override;
void requestStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, CompletionHandler<void(StorageAccessStatus)>&&) override;
void grantStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&) override;
void requestStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::StorageAccessScope, CompletionHandler<void(StorageAccessStatus)>&&) override;
void grantStorageAccess(SubFrameDomain&&, TopFrameDomain&&, WebCore::FrameIdentifier, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, WebCore::StorageAccessScope, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&) override;

void logFrameNavigation(const NavigatedToDomain&, const TopFrameDomain&, const NavigatedFromDomain&, bool isRedirect, bool isMainFrame, Seconds delayAfterMainFrameDocumentLoad, bool wasPotentiallyInitiatedByUser) override;
void logCrossSiteLoadWithLinkDecoration(const NavigatedFromDomain&, const NavigatedToDomain&) override;
Expand Down Expand Up @@ -225,7 +225,7 @@ class ResourceLoadStatisticsDatabaseStore final : public ResourceLoadStatisticsS
void setPrevalentResource(const RegistrableDomain&, ResourceLoadPrevalence);
unsigned recursivelyFindNonPrevalentDomainsThatRedirectedToThisDomain(unsigned primaryDomainID, StdSet<unsigned>& nonPrevalentRedirectionSources, unsigned numberOfRecursiveCalls);
void setDomainsAsPrevalent(StdSet<unsigned>&&);
void grantStorageAccessInternal(SubFrameDomain&&, TopFrameDomain&&, Optional<WebCore::FrameIdentifier>, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&);
void grantStorageAccessInternal(SubFrameDomain&&, TopFrameDomain&&, Optional<WebCore::FrameIdentifier>, WebCore::PageIdentifier, WebCore::StorageAccessPromptWasShown, WebCore::StorageAccessScope, CompletionHandler<void(WebCore::StorageAccessWasGranted)>&&);
void markAsPrevalentIfHasRedirectedToPrevalent();
Vector<RegistrableDomain> ensurePrevalentResourcesForDebugMode() override;
void removeDataRecords(CompletionHandler<void()>&&);
Expand Down
Loading

0 comments on commit 3fe9ed1

Please sign in to comment.