Diff
Modified: trunk/LayoutTests/ChangeLog (282365 => 282366)
--- trunk/LayoutTests/ChangeLog 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/LayoutTests/ChangeLog 2021-09-13 22:18:26 UTC (rev 282366)
@@ -1,3 +1,17 @@
+2021-09-13 Chris Dumez <cdu...@apple.com>
+
+ Relax BroadcastChannel origin partitioning if iframe has storage access
+ https://bugs.webkit.org/show_bug.cgi?id=230164
+
+ Reviewed by Alex Christensen.
+
+ Add layout test coverage.
+
+ * http/tests/messaging/broadcastchannel-partitioning-with-storage-access-expected.txt: Added.
+ * http/tests/messaging/broadcastchannel-partitioning-with-storage-access.html: Added.
+ * http/tests/messaging/resources/broadcastchannel-partitioning-with-storage-access-iframe.html: Added.
+ * http/tests/messaging/resources/broadcastchannel-partitioning-with-storage-access-popup.html: Added.
+
2021-09-13 Arcady Goldmints-Orlov <agoldmi...@igalia.com>
[GLIB] Update test baselines after r282306
Added: trunk/LayoutTests/http/tests/messaging/broadcastchannel-partitioning-with-storage-access-expected.txt (0 => 282366)
--- trunk/LayoutTests/http/tests/messaging/broadcastchannel-partitioning-with-storage-access-expected.txt (rev 0)
+++ trunk/LayoutTests/http/tests/messaging/broadcastchannel-partitioning-with-storage-access-expected.txt 2021-09-13 22:18:26 UTC (rev 282366)
@@ -0,0 +1,11 @@
+Tests that BroadcastChannel's origin partitioning can be relaxed via requestStorageAccess()
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS Received message from same-origin iframe with storage access under cross-origin popup
+PASS gotMessageFromSameOriginIframeUnderCrossOriginPopup is false
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/http/tests/messaging/broadcastchannel-partitioning-with-storage-access.html (0 => 282366)
--- trunk/LayoutTests/http/tests/messaging/broadcastchannel-partitioning-with-storage-access.html (rev 0)
+++ trunk/LayoutTests/http/tests/messaging/broadcastchannel-partitioning-with-storage-access.html 2021-09-13 22:18:26 UTC (rev 282366)
@@ -0,0 +1,30 @@
+<!DOCTYPE html><!-- webkit-test-runner [ BroadcastChannelOriginPartitioningEnabled=true ] -->
+<html>
+<body>
+<script src=""
+<script>
+description("Tests that BroadcastChannel's origin partitioning can be relaxed via requestStorageAccess()");
+jsTestIsAsync = true;
+
+let bc = new BroadcastChannel("broadcastchannel-partitioning-with-storage-access");
+
+let gotMessageFromSameOriginIframeUnderCrossOriginPopup = false;
+bc._onmessage_ = (message) => {
+ if (message.data == "same-origin-iframe-under-cross-origin-popup-with-storage-access") {
+ testPassed("Received message from same-origin iframe with storage access under cross-origin popup");
+ shouldBeFalse("gotMessageFromSameOriginIframeUnderCrossOriginPopup");
+ gotMessageFromSameOriginIframeUnderCrossOriginPopup = true;
+ } else {
+ testFailed("Received unexpected message: " + message.data);
+ }
+
+ if (gotMessageFromSameOriginIframeUnderCrossOriginPopup)
+ setTimeout(finishJSTest, 1000);
+};
+
+_onload_ = () => {
+ open("http://localhost:8000/messaging/resources/broadcastchannel-partitioning-with-storage-access-popup.html");
+};
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/http/tests/messaging/resources/broadcastchannel-partitioning-with-storage-access-iframe.html (0 => 282366)
--- trunk/LayoutTests/http/tests/messaging/resources/broadcastchannel-partitioning-with-storage-access-iframe.html (rev 0)
+++ trunk/LayoutTests/http/tests/messaging/resources/broadcastchannel-partitioning-with-storage-access-iframe.html 2021-09-13 22:18:26 UTC (rev 282366)
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script>
+partitionedChannel = new BroadcastChannel("broadcastchannel-partitioning-with-storage-access");
+partitionedChannel.postMessage("same-origin-iframe-under-cross-origin-popup-without-storage-access-1");
+
+internals.withUserGesture(() => {
+ document.requestStorageAccess().then(() => {
+ unpartitionedChannel = new BroadcastChannel("broadcastchannel-partitioning-with-storage-access");
+ unpartitionedChannel.postMessage("same-origin-iframe-under-cross-origin-popup-with-storage-access");
+
+ partitionedChannel.postMessage("same-origin-iframe-under-cross-origin-popup-without-storage-access-2");
+ });
+});
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/http/tests/messaging/resources/broadcastchannel-partitioning-with-storage-access-popup.html (0 => 282366)
--- trunk/LayoutTests/http/tests/messaging/resources/broadcastchannel-partitioning-with-storage-access-popup.html (rev 0)
+++ trunk/LayoutTests/http/tests/messaging/resources/broadcastchannel-partitioning-with-storage-access-popup.html 2021-09-13 22:18:26 UTC (rev 282366)
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<iframe src=""
+</body>
+</html>
Modified: trunk/LayoutTests/platform/mac-wk1/TestExpectations (282365 => 282366)
--- trunk/LayoutTests/platform/mac-wk1/TestExpectations 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/LayoutTests/platform/mac-wk1/TestExpectations 2021-09-13 22:18:26 UTC (rev 282366)
@@ -79,6 +79,9 @@
editing/async-clipboard/clipboard-read-text-same-origin.html [ Skip ]
editing/async-clipboard/sanitize-when-reading-markup.html [ Skip ]
+# No requestStorageAccess() support for WK1.
+http/tests/messaging/broadcastchannel-partitioning-with-storage-access.html [ Skip ]
+
imported/w3c/web-platform-tests/websockets/Close-1000-reason.any.html [ Pass Failure ]
imported/w3c/web-platform-tests/websockets/Close-1000-reason.any.worker.html [ Pass Failure ]
imported/w3c/web-platform-tests/websockets/binary/001.html [ Pass Failure ]
Modified: trunk/LayoutTests/platform/win/TestExpectations (282365 => 282366)
--- trunk/LayoutTests/platform/win/TestExpectations 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/LayoutTests/platform/win/TestExpectations 2021-09-13 22:18:26 UTC (rev 282366)
@@ -4636,6 +4636,7 @@
# No BroadcastChannel support on Windows.
fast/html/broadcast-channel-between-different-sessions.html [ Skip ]
http/tests/messaging/broadcastchannel-partitioning.html [ Skip ]
+http/tests/messaging/broadcastchannel-partitioning-with-storage-access.html [ Skip ]
# This test is skipped because the necessary feature flag functionality specific to the Windows WebKit legacy port is
# not implemented. The feature flags in question are CSSCounterStyleAtRulesEnabled and CSSCounterStyleAtRuleImageSymbolsEnabled.
Modified: trunk/Source/WebCore/ChangeLog (282365 => 282366)
--- trunk/Source/WebCore/ChangeLog 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/Source/WebCore/ChangeLog 2021-09-13 22:18:26 UTC (rev 282366)
@@ -1,3 +1,39 @@
+2021-09-13 Chris Dumez <cdu...@apple.com>
+
+ Relax BroadcastChannel origin partitioning if iframe has storage access
+ https://bugs.webkit.org/show_bug.cgi?id=230164
+
+ Reviewed by Alex Christensen.
+
+ In r282105, we started partitioning origins for BroadcastChannel using topOrigin/frameOrigin.
+ This prevents a topFrame of origin A to message a subframe of origin A if that subframe if under
+ another domain B. However, the `document.requestStorageAccess()` API exists to relax storage
+ partitioning and Gecko relies on this to relax BroadcastChannel origin partitioning as well.
+ This patch aligns WebKit's behavior with Gecko.
+
+ Test: http/tests/messaging/broadcastchannel-partitioning-with-storage-access.html
+
+ * dom/BroadcastChannel.cpp:
+ (WebCore::shouldPartitionOrigin):
+ (WebCore::BroadcastChannel::MainThreadBridge::create):
+ (WebCore::BroadcastChannel::MainThreadBridge::name const):
+ (WebCore::BroadcastChannel::MainThreadBridge::identifier const):
+ (WebCore::BroadcastChannel::MainThreadBridge::MainThreadBridge):
+ (WebCore::BroadcastChannel::MainThreadBridge::ensureOnMainThread):
+ (WebCore::BroadcastChannel::MainThreadBridge::registerChannel):
+ (WebCore::BroadcastChannel::MainThreadBridge::unregisterChannel):
+ (WebCore::BroadcastChannel::MainThreadBridge::postMessage):
+ (WebCore::BroadcastChannel::BroadcastChannel):
+ (WebCore::BroadcastChannel::~BroadcastChannel):
+ (WebCore::BroadcastChannel::identifier const):
+ (WebCore::BroadcastChannel::name const):
+ (WebCore::BroadcastChannel::postMessage):
+ (WebCore::BroadcastChannel::close):
+ (WebCore::BroadcastChannel::dispatchMessage):
+ * dom/BroadcastChannel.h:
+ * page/ChromeClient.h:
+ (WebCore::ChromeClient::hasPageLevelStorageAccess const):
+
2021-09-13 Youenn Fablet <you...@apple.com>
Fire RTCPeerConnection.signalstatechange as per spec
Modified: trunk/Source/WebCore/dom/BroadcastChannel.cpp (282365 => 282366)
--- trunk/Source/WebCore/dom/BroadcastChannel.cpp 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/Source/WebCore/dom/BroadcastChannel.cpp 2021-09-13 22:18:26 UTC (rev 282366)
@@ -27,6 +27,8 @@
#include "BroadcastChannel.h"
#include "BroadcastChannelRegistry.h"
+#include "Chrome.h"
+#include "ChromeClient.h"
#include "EventNames.h"
#include "MessageEvent.h"
#include "Page.h"
@@ -57,33 +59,141 @@
return map;
}
-BroadcastChannel::BroadcastChannel(ScriptExecutionContext& context, const String& name)
- : ActiveDOMObject(&context)
- , m_name(name)
- , m_origin { context.settingsValues().broadcastChannelOriginPartitioningEnabled ? context.topOrigin().data() : context.securityOrigin()->data(), context.securityOrigin()->data() }
- , m_identifier(BroadcastChannelIdentifier::generateThreadSafe())
+static bool shouldPartitionOrigin(Document& document)
{
+ if (!document.settings().broadcastChannelOriginPartitioningEnabled())
+ return false;
+
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+ if (!document.settings().storageAccessAPIEnabled())
+ return true;
+
+ auto* page = document.page();
+ if (!page)
+ return true;
+
+ return !page->chrome().client().hasPageLevelStorageAccess(RegistrableDomain::uncheckedCreateFromHost(document.topDocument().securityOrigin().host()), RegistrableDomain::uncheckedCreateFromHost(document.securityOrigin().host()));
+#else
+ return true;
+#endif
+}
+
+class BroadcastChannel::MainThreadBridge : public ThreadSafeRefCounted<MainThreadBridge, WTF::DestructionThread::Main> {
+public:
+ static Ref<MainThreadBridge> create(BroadcastChannel& channel, const String& name)
{
- Locker locker { allBroadcastChannelsLock };
- allBroadcastChannels().add(m_identifier, this);
+ return adoptRef(*new MainThreadBridge(channel, name));
}
- ensureOnMainThread([origin = crossThreadCopy(m_origin), name = crossThreadCopy(m_name), contextIdentifier = context.contextIdentifier(), channelIdentifier = m_identifier](auto& document) {
+ void registerChannel();
+ void unregisterChannel();
+ void postMessage(Ref<SerializedScriptValue>&&);
+
+ String name() const { return m_name.isolatedCopy(); }
+ BroadcastChannelIdentifier identifier() const { return m_identifier; }
+
+private:
+ MainThreadBridge(BroadcastChannel&, const String& name);
+
+ void ensureOnMainThread(Function<void(Document&)>&&);
+
+ WeakPtr<BroadcastChannel> m_broadcastChannel;
+ const BroadcastChannelIdentifier m_identifier;
+ const String m_name; // Main thread only.
+ ClientOrigin m_origin; // Main thread only.
+};
+
+BroadcastChannel::MainThreadBridge::MainThreadBridge(BroadcastChannel& channel, const String& name)
+ : m_broadcastChannel(makeWeakPtr(channel))
+ , m_identifier(BroadcastChannelIdentifier::generateThreadSafe())
+ , m_name(name.isolatedCopy())
+{
+}
+
+void BroadcastChannel::MainThreadBridge::ensureOnMainThread(Function<void(Document&)>&& task)
+{
+ ASSERT(m_broadcastChannel);
+ if (!m_broadcastChannel)
+ return;
+
+ auto* context = m_broadcastChannel->scriptExecutionContext();
+ if (!context)
+ return;
+ ASSERT(context->isContextThread());
+
+ Ref protectedThis { *this };
+ if (is<Document>(*context))
+ task(downcast<Document>(*context));
+ else {
+ downcast<WorkerGlobalScope>(*context).thread().workerLoaderProxy().postTaskToLoader([protectedThis = WTFMove(protectedThis), task = WTFMove(task)](auto& context) {
+ task(downcast<Document>(context));
+ });
+ }
+}
+
+void BroadcastChannel::MainThreadBridge::registerChannel()
+{
+ ensureOnMainThread([this, contextIdentifier = m_broadcastChannel->scriptExecutionContext()->contextIdentifier()](auto& document) {
+ m_origin = { shouldPartitionOrigin(document) ? document.topOrigin().data() : document.securityOrigin().data(), document.securityOrigin().data() };
if (auto* page = document.page())
- page->broadcastChannelRegistry().registerChannel(origin, name, channelIdentifier);
- channelToContextIdentifier().add(channelIdentifier, contextIdentifier);
+ page->broadcastChannelRegistry().registerChannel(m_origin, m_name, m_identifier);
+ channelToContextIdentifier().add(m_identifier, contextIdentifier);
});
}
+void BroadcastChannel::MainThreadBridge::unregisterChannel()
+{
+ ensureOnMainThread([this](auto& document) {
+ if (auto* page = document.page())
+ page->broadcastChannelRegistry().unregisterChannel(m_origin, m_name, m_identifier);
+ channelToContextIdentifier().remove(m_identifier);
+ });
+}
+
+void BroadcastChannel::MainThreadBridge::postMessage(Ref<SerializedScriptValue>&& message)
+{
+ ensureOnMainThread([this, message = WTFMove(message)](auto& document) mutable {
+ auto* page = document.page();
+ if (!page)
+ return;
+
+ auto blobHandles = message->blobHandles();
+ page->broadcastChannelRegistry().postMessage(m_origin, m_name, m_identifier, WTFMove(message), [blobHandles = WTFMove(blobHandles)] {
+ // Keeps Blob data inside messageData alive until the message has been delivered.
+ });
+ });
+}
+
+BroadcastChannel::BroadcastChannel(ScriptExecutionContext& context, const String& name)
+ : ActiveDOMObject(&context)
+ , m_mainThreadBridge(MainThreadBridge::create(*this, name))
+{
+ {
+ Locker locker { allBroadcastChannelsLock };
+ allBroadcastChannels().add(m_mainThreadBridge->identifier(), this);
+ }
+ m_mainThreadBridge->registerChannel();
+}
+
BroadcastChannel::~BroadcastChannel()
{
close();
{
Locker locker { allBroadcastChannelsLock };
- allBroadcastChannels().remove(m_identifier);
+ allBroadcastChannels().remove(m_mainThreadBridge->identifier());
}
}
+BroadcastChannelIdentifier BroadcastChannel::identifier() const
+{
+ return m_mainThreadBridge->identifier();
+}
+
+String BroadcastChannel::name() const
+{
+ return m_mainThreadBridge->name();
+}
+
ExceptionOr<void> BroadcastChannel::postMessage(JSC::JSGlobalObject& globalObject, JSC::JSValue message)
{
if (m_isClosed)
@@ -95,17 +205,7 @@
return messageData.releaseException();
ASSERT(ports.isEmpty());
- ensureOnMainThread([origin = crossThreadCopy(m_origin), name = crossThreadCopy(m_name), identifier = m_identifier, messageData = messageData.releaseReturnValue()](auto& document) mutable {
- auto* page = document.page();
- if (!page)
- return;
-
- auto blobHandles = messageData->blobHandles();
- page->broadcastChannelRegistry().postMessage(origin, name, identifier, WTFMove(messageData), [blobHandles = WTFMove(blobHandles)] {
- // Keeps Blob data inside messageData alive until the message has been delivered.
- });
- });
-
+ m_mainThreadBridge->postMessage(messageData.releaseReturnValue());
return { };
}
@@ -115,11 +215,7 @@
return;
m_isClosed = true;
- ensureOnMainThread([origin = crossThreadCopy(m_origin), name = crossThreadCopy(m_name), channelIdentifier = m_identifier](auto& document) {
- if (auto* page = document.page())
- page->broadcastChannelRegistry().unregisterChannel(origin, name, channelIdentifier);
- channelToContextIdentifier().remove(channelIdentifier);
- });
+ m_mainThreadBridge->unregisterChannel();
}
void BroadcastChannel::dispatchMessageTo(BroadcastChannelIdentifier channelIdentifier, Ref<SerializedScriptValue>&& message, CompletionHandler<void()>&& completionHandler)
@@ -149,26 +245,11 @@
return;
queueTaskKeepingObjectAlive(*this, TaskSource::PostedMessageQueue, [this, message = WTFMove(message)]() mutable {
- if (!m_isClosed)
- dispatchEvent(MessageEvent::create({ }, WTFMove(message), m_origin.clientOrigin.toString()));
+ if (!m_isClosed && scriptExecutionContext())
+ dispatchEvent(MessageEvent::create({ }, WTFMove(message), scriptExecutionContext()->securityOrigin()->toString()));
});
}
-void BroadcastChannel::ensureOnMainThread(Function<void(Document&)>&& task)
-{
- auto* context = scriptExecutionContext();
- if (!context)
- return;
-
- if (is<Document>(*context))
- task(downcast<Document>(*context));
- else {
- downcast<WorkerGlobalScope>(*context).thread().workerLoaderProxy().postTaskToLoader([task = WTFMove(task)](auto& context) {
- task(downcast<Document>(context));
- });
- }
-}
-
const char* BroadcastChannel::activeDOMObjectName() const
{
return "BroadcastChannel";
Modified: trunk/Source/WebCore/dom/BroadcastChannel.h (282365 => 282366)
--- trunk/Source/WebCore/dom/BroadcastChannel.h 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/Source/WebCore/dom/BroadcastChannel.h 2021-09-13 22:18:26 UTC (rev 282366)
@@ -56,8 +56,8 @@
using RefCounted<BroadcastChannel>::ref;
using RefCounted<BroadcastChannel>::deref;
- BroadcastChannelIdentifier identifier() const { return m_identifier; }
- const String& name() const { return m_name; }
+ BroadcastChannelIdentifier identifier() const;
+ String name() const;
ExceptionOr<void> postMessage(JSC::JSGlobalObject&, JSC::JSValue message);
void close();
@@ -82,9 +82,8 @@
bool virtualHasPendingActivity() const final;
void stop() final { close(); }
- const String m_name;
- const ClientOrigin m_origin;
- const BroadcastChannelIdentifier m_identifier;
+ class MainThreadBridge;
+ Ref<MainThreadBridge> m_mainThreadBridge;
bool m_isClosed { false };
bool m_hasRelevantEventListener { false };
};
Modified: trunk/Source/WebCore/page/ChromeClient.h (282365 => 282366)
--- trunk/Source/WebCore/page/ChromeClient.h 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/Source/WebCore/page/ChromeClient.h 2021-09-13 22:18:26 UTC (rev 282366)
@@ -554,6 +554,7 @@
#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&, StorageAccessScope scope, WTF::CompletionHandler<void(RequestStorageAccessResult)>&& completionHandler) { completionHandler({ StorageAccessWasGranted::No, StorageAccessPromptWasShown::No, scope, WTFMove(topFrameDomain), WTFMove(subFrameDomain) }); }
+ virtual bool hasPageLevelStorageAccess(const RegistrableDomain& /*topLevelDomain*/, const RegistrableDomain& /*resourceDomain*/) const { return false; }
#endif
#if ENABLE(DEVICE_ORIENTATION)
Modified: trunk/Source/WebKit/ChangeLog (282365 => 282366)
--- trunk/Source/WebKit/ChangeLog 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/Source/WebKit/ChangeLog 2021-09-13 22:18:26 UTC (rev 282366)
@@ -1,5 +1,16 @@
2021-09-13 Chris Dumez <cdu...@apple.com>
+ Relax BroadcastChannel origin partitioning if iframe has storage access
+ https://bugs.webkit.org/show_bug.cgi?id=230164
+
+ Reviewed by Alex Christensen.
+
+ * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+ (WebKit::WebChromeClient::hasPageLevelStorageAccess const):
+ * WebProcess/WebCoreSupport/WebChromeClient.h:
+
+2021-09-13 Chris Dumez <cdu...@apple.com>
+
Crash under WebPage::runJavaScript()
https://bugs.webkit.org/show_bug.cgi?id=230223
<rdar://80172436>
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp (282365 => 282366)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp 2021-09-13 22:18:26 UTC (rev 282366)
@@ -1441,6 +1441,11 @@
ASSERT(webFrame);
m_page.requestStorageAccess(WTFMove(subFrameDomain), WTFMove(topFrameDomain), *webFrame, scope, WTFMove(completionHandler));
}
+
+bool WebChromeClient::hasPageLevelStorageAccess(const WebCore::RegistrableDomain& topLevelDomain, const WebCore::RegistrableDomain& resourceDomain) const
+{
+ return m_page.hasPageLevelStorageAccess(topLevelDomain, resourceDomain);
+}
#endif
#if ENABLE(DEVICE_ORIENTATION)
Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h (282365 => 282366)
--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h 2021-09-13 22:06:45 UTC (rev 282365)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h 2021-09-13 22:18:26 UTC (rev 282366)
@@ -410,6 +410,7 @@
#if ENABLE(RESOURCE_LOAD_STATISTICS)
void hasStorageAccess(WebCore::RegistrableDomain&& subFrameDomain, WebCore::RegistrableDomain&& topFrameDomain, WebCore::Frame&, WTF::CompletionHandler<void(bool)>&&) final;
void requestStorageAccess(WebCore::RegistrableDomain&& subFrameDomain, WebCore::RegistrableDomain&& topFrameDomain, WebCore::Frame&, WebCore::StorageAccessScope, WTF::CompletionHandler<void(WebCore::RequestStorageAccessResult)>&&) final;
+ bool hasPageLevelStorageAccess(const WebCore::RegistrableDomain& topLevelDomain, const WebCore::RegistrableDomain& resourceDomain) const final;
#endif
#if ENABLE(DEVICE_ORIENTATION)