Skip to content
Permalink
Browse files
Add support to the Permissions API for dedicated workers
https://bugs.webkit.org/show_bug.cgi?id=243805

Reviewed by Chris Dumez and Sihui Liu.

Permissions::query() should be exposed for both window and workers. Currently,
it is only exposed for window. This patch is the first step in exposing it for
all of the workers.

* LayoutTests/http/tests/notifications/permission/worker-permission-query-expected.txt: Added.
* LayoutTests/http/tests/notifications/permission/worker-permission-query.html: Added.
* LayoutTests/http/tests/notifications/permission/worker-permission-query.js: Added.
(onmessage):
* LayoutTests/imported/w3c/web-platform-tests/permissions/all-permissions-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/permissions/idlharness.any.worker-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/storage/permission-query.https.any.worker-expected.txt:
* Source/WebCore/CMakeLists.txt:
* Source/WebCore/DerivedSources-input.xcfilelist:
* Source/WebCore/DerivedSources-output.xcfilelist:
* Source/WebCore/DerivedSources.make:
* Source/WebCore/Headers.cmake:
* Source/WebCore/Modules/permissions/NavigatorPermissions.cpp:
(WebCore::NavigatorPermissions::permissions):
* Source/WebCore/Modules/permissions/NavigatorPermissions.h:
* Source/WebCore/Modules/permissions/PermissionController.h:
* Source/WebCore/Modules/permissions/PermissionStatus.cpp:
(WebCore::PermissionStatus::PermissionStatus):
(WebCore::PermissionStatus::~PermissionStatus):
(WebCore::PermissionStatus::stateChanged):
* Source/WebCore/Modules/permissions/PermissionStatus.h:
* Source/WebCore/Modules/permissions/PermissionStatus.idl:
* Source/WebCore/Modules/permissions/PermissionStatusIdentifier.h: Added.
* Source/WebCore/Modules/permissions/Permissions.cpp:
(WebCore::Permissions::create):
(WebCore::Permissions::Permissions):
(WebCore::Permissions::navigator):
(WebCore::Permissions::query):
* Source/WebCore/Modules/permissions/Permissions.h:
* Source/WebCore/Modules/permissions/Permissions.idl:
* Source/WebCore/Modules/permissions/WorkerNavigator+Permissions.idl: Copied from Source/WebCore/Modules/permissions/Permissions.idl.
* Source/WebCore/Modules/permissions/WorkerNavigatorPermissions.cpp: Copied from Source/WebCore/Modules/permissions/NavigatorPermissions.cpp.
(WebCore::WorkerNavigatorPermissions::WorkerNavigatorPermissions):
(WebCore::WorkerNavigatorPermissions::permissions):
(WebCore::WorkerNavigatorPermissions::from):
(WebCore::WorkerNavigatorPermissions::supplementName):
* Source/WebCore/Modules/permissions/WorkerNavigatorPermissions.h: Copied from Source/WebCore/Modules/permissions/NavigatorPermissions.h.
* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebKit/WebProcess/WebCoreSupport/WebPermissionController.cpp:
(WebKit::WebPermissionController::addObserver):
(WebKit::WebPermissionController::removeObserver):
(WebKit::WebPermissionController::permissionChanged):
* Source/WebKit/WebProcess/WebCoreSupport/WebPermissionController.h:

Canonical link: https://commits.webkit.org/253447@main
  • Loading branch information
RupinMittal authored and cdumez committed Aug 16, 2022
1 parent d95feca commit fd42e2c17767290e383a082d15593c4b74f79717
Show file tree
Hide file tree
Showing 24 changed files with 378 additions and 98 deletions.
@@ -0,0 +1,17 @@
This test checks that Permissions::query() works for dedicated workers

On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


PASS message.data is "prompt"
PASS receivedPostMessageResponse became true
PASS requestPermissionResult is "granted"
PASS message.data is "granted"
PASS receivedPostMessageResponse became true
PASS requestPermissionResult is "denied"
PASS message.data is "denied"
PASS receivedPostMessageResponse became true
PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<head>
<script src="/resources/js-test-pre.js"></script>
<script src="/resources/notifications-test-pre.js"></script>
</head>
<body>
<script>

description("This test checks that Permissions::query() works for dedicated workers")

jsTestIsAsync = true;

var expectedData = null;
var receivedPostMessageResponse = true;

var worker = new Worker('worker-permission-query.js');
worker.onmessage = function(message) {
window.message = message;
shouldBeEqualToString("message.data", expectedData);
receivedPostMessageResponse = true;
}

async function defaultTest()
{
receivedPostMessageResponse = false;
expectedData = "prompt";
worker.postMessage(1);
await shouldBecomeEqual("receivedPostMessageResponse", "true");
}

async function grantTest()
{
receivedPostMessageResponse = false;
expectedData = "granted";
internals.withUserGesture(() => {
// Permission is granted by default when requestPermission() is called.
window.Notification.requestPermission().then((result)=> {
requestPermissionResult = result;
shouldBeEqualToString("requestPermissionResult", "granted");
worker.postMessage(2);
});
});
await shouldBecomeEqual("receivedPostMessageResponse", "true");
}

async function denyTest()
{
receivedPostMessageResponse = false;
expectedData = "denied";
internals.withUserGesture(() => {
testRunner.denyWebNotificationPermissionOnPrompt(testURL);
window.Notification.requestPermission().then((result)=> {
requestPermissionResult = result;
shouldBeEqualToString("requestPermissionResult", "denied");
worker.postMessage(3);
});
});
await shouldBecomeEqual("receivedPostMessageResponse", "true");
}

(async function () {
await defaultTest();
await grantTest();
await denyTest();
finishJSTest();
})();

</script>
<script src="/resources/js-test-post.js"></script>
</body>
</html>
@@ -0,0 +1,5 @@
onmessage = function(e) {
navigator.permissions.query({ name: "notifications" }).then((status) => {
postMessage(status.state);
});
}
@@ -3,19 +3,19 @@ PASS Query "geolocation" permission
PASS Query "notifications" permission
FAIL Query "persistent-storage" permission promise_test: Unhandled rejection with value: object "TypeError: Type error"
FAIL Query "push" permission promise_test: Unhandled rejection with value: object "TypeError: Type error"
FAIL Query "accelerometer" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "accelerometer" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
FAIL Query "ambient-light-sensor" permission promise_test: Unhandled rejection with value: object "TypeError: Type error"
FAIL Query "background-fetch" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "background-fetch" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
FAIL Query "background-sync" permission promise_test: Unhandled rejection with value: object "TypeError: Type error"
FAIL Query "bluetooth" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "gyroscope" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "magnetometer" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "midi" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "nfc" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "bluetooth" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
FAIL Query "gyroscope" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
FAIL Query "magnetometer" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
FAIL Query "midi" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
FAIL Query "nfc" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
FAIL Query "screen-wake-lock" permission promise_test: Unhandled rejection with value: object "TypeError: Type error"
PASS Query "camera" permission
FAIL Query "display-capture" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "display-capture" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
PASS Query "microphone" permission
FAIL Query "speaker-selection" permission promise_test: Unhandled rejection with value: object "NotSupportedError: The operation is not supported."
FAIL Query "speaker-selection" permission promise_test: Unhandled rejection with value: object "NotSupportedError: Permissions::query does not support this API"
FAIL Query "xr-spatial-tracking" permission promise_test: Unhandled rejection with value: object "TypeError: Type error"

@@ -19,29 +19,29 @@ PASS WorkerNavigator includes NavigatorID: member names are unique
PASS WorkerNavigator includes NavigatorLanguage: member names are unique
PASS WorkerNavigator includes NavigatorOnLine: member names are unique
PASS WorkerNavigator includes NavigatorConcurrentHardware: member names are unique
FAIL PermissionStatus interface: existence and properties of interface object assert_own_property: self does not have own property "PermissionStatus" expected property "PermissionStatus" missing
FAIL PermissionStatus interface object length assert_own_property: self does not have own property "PermissionStatus" expected property "PermissionStatus" missing
FAIL PermissionStatus interface object name assert_own_property: self does not have own property "PermissionStatus" expected property "PermissionStatus" missing
FAIL PermissionStatus interface: existence and properties of interface prototype object assert_own_property: self does not have own property "PermissionStatus" expected property "PermissionStatus" missing
FAIL PermissionStatus interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "PermissionStatus" expected property "PermissionStatus" missing
FAIL PermissionStatus interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "PermissionStatus" expected property "PermissionStatus" missing
FAIL PermissionStatus interface: attribute state assert_own_property: self does not have own property "PermissionStatus" expected property "PermissionStatus" missing
FAIL PermissionStatus interface: attribute onchange assert_own_property: self does not have own property "PermissionStatus" expected property "PermissionStatus" missing
FAIL PermissionStatus must be primary interface of permissionStatus assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Can't find variable: permissionStatus"
FAIL Stringification of permissionStatus assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Can't find variable: permissionStatus"
FAIL PermissionStatus interface: permissionStatus must inherit property "state" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Can't find variable: permissionStatus"
FAIL PermissionStatus interface: permissionStatus must inherit property "onchange" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Can't find variable: permissionStatus"
FAIL Permissions interface: existence and properties of interface object assert_own_property: self does not have own property "Permissions" expected property "Permissions" missing
FAIL Permissions interface object length assert_own_property: self does not have own property "Permissions" expected property "Permissions" missing
FAIL Permissions interface object name assert_own_property: self does not have own property "Permissions" expected property "Permissions" missing
FAIL Permissions interface: existence and properties of interface prototype object assert_own_property: self does not have own property "Permissions" expected property "Permissions" missing
FAIL Permissions interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "Permissions" expected property "Permissions" missing
FAIL Permissions interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "Permissions" expected property "Permissions" missing
FAIL Permissions interface: operation query(object) assert_own_property: self does not have own property "Permissions" expected property "Permissions" missing
FAIL Permissions must be primary interface of navigator.permissions assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL Stringification of navigator.permissions assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL Permissions interface: navigator.permissions must inherit property "query(object)" with the proper type assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL Permissions interface: calling query(object) on navigator.permissions with too few arguments must throw TypeError assert_equals: wrong typeof object expected "object" but got "undefined"
FAIL WorkerNavigator interface: attribute permissions assert_true: The prototype object must have a property "permissions" expected true got false
FAIL WorkerNavigator interface: navigator must inherit property "permissions" with the proper type assert_inherits: property "permissions" not found in prototype chain
PASS PermissionStatus interface: existence and properties of interface object
PASS PermissionStatus interface object length
PASS PermissionStatus interface object name
PASS PermissionStatus interface: existence and properties of interface prototype object
PASS PermissionStatus interface: existence and properties of interface prototype object's "constructor" property
PASS PermissionStatus interface: existence and properties of interface prototype object's @@unscopables property
PASS PermissionStatus interface: attribute state
FAIL PermissionStatus interface: attribute onchange assert_true: The prototype object must have a property "onchange" expected true got false
PASS PermissionStatus must be primary interface of permissionStatus
PASS Stringification of permissionStatus
PASS PermissionStatus interface: permissionStatus must inherit property "state" with the proper type
FAIL PermissionStatus interface: permissionStatus must inherit property "onchange" with the proper type assert_inherits: property "onchange" not found in prototype chain
PASS Permissions interface: existence and properties of interface object
PASS Permissions interface object length
PASS Permissions interface object name
PASS Permissions interface: existence and properties of interface prototype object
PASS Permissions interface: existence and properties of interface prototype object's "constructor" property
PASS Permissions interface: existence and properties of interface prototype object's @@unscopables property
PASS Permissions interface: operation query(object)
PASS Permissions must be primary interface of navigator.permissions
PASS Stringification of navigator.permissions
PASS Permissions interface: navigator.permissions must inherit property "query(object)" with the proper type
PASS Permissions interface: calling query(object) on navigator.permissions with too few arguments must throw TypeError
PASS WorkerNavigator interface: attribute permissions
PASS WorkerNavigator interface: navigator must inherit property "permissions" with the proper type

@@ -1,3 +1,3 @@

FAIL The "persistent-storage" permission is recognized promise_test: Unhandled rejection with value: object "TypeError: undefined is not an object (evaluating 'navigator.permissions.query')"
FAIL The "persistent-storage" permission is recognized promise_test: Unhandled rejection with value: object "TypeError: Type error"

@@ -524,6 +524,7 @@ set(WebCore_NON_SVG_IDL_FILES
Modules/permissions/PermissionState.idl
Modules/permissions/PermissionStatus.idl
Modules/permissions/Permissions.idl
Modules/permissions/WorkerNavigator+Permissions.idl

Modules/pictureinpicture/Document+PictureInPicture.idl
Modules/pictureinpicture/DocumentOrShadowRoot+PictureInPicture.idl
@@ -584,6 +584,7 @@ $(PROJECT_DIR)/Modules/permissions/PermissionName.idl
$(PROJECT_DIR)/Modules/permissions/PermissionState.idl
$(PROJECT_DIR)/Modules/permissions/PermissionStatus.idl
$(PROJECT_DIR)/Modules/permissions/Permissions.idl
$(PROJECT_DIR)/Modules/permissions/WorkerNavigator+Permissions.idl
$(PROJECT_DIR)/Modules/pictureinpicture/Document+PictureInPicture.idl
$(PROJECT_DIR)/Modules/pictureinpicture/DocumentOrShadowRoot+PictureInPicture.idl
$(PROJECT_DIR)/Modules/pictureinpicture/HTMLVideoElement+PictureInPicture.idl
@@ -2926,6 +2926,8 @@ $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerLocation.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerLocation.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerNavigator+MediaCapabilities.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerNavigator+MediaCapabilities.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerNavigator+Permissions.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerNavigator+Permissions.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerNavigator.cpp
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerNavigator.h
$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSWorkerOptions.cpp
@@ -506,6 +506,7 @@ JS_BINDING_IDLS := \
$(WebCore)/Modules/permissions/PermissionState.idl \
$(WebCore)/Modules/permissions/PermissionStatus.idl \
$(WebCore)/Modules/permissions/Permissions.idl \
$(WebCore)/Modules/permissions/WorkerNavigator+Permissions.idl \
$(WebCore)/Modules/pictureinpicture/DocumentOrShadowRoot+PictureInPicture.idl \
$(WebCore)/Modules/pictureinpicture/Document+PictureInPicture.idl \
$(WebCore)/Modules/pictureinpicture/HTMLVideoElement+PictureInPicture.idl \
@@ -36,20 +36,20 @@ NavigatorPermissions::NavigatorPermissions(Navigator& navigator)
{
}

RefPtr<Permissions> NavigatorPermissions::permissions(Navigator& navigator)
Permissions& NavigatorPermissions::permissions(Navigator& navigator)
{
return NavigatorPermissions::from(navigator)->permissions();
return NavigatorPermissions::from(navigator).permissions();
}

RefPtr<Permissions> NavigatorPermissions::permissions()
Permissions& NavigatorPermissions::permissions()
{
if (!m_permissions)
m_permissions = Permissions::create(m_navigator);

return m_permissions;
return *m_permissions;
}

NavigatorPermissions* NavigatorPermissions::from(Navigator& navigator)
NavigatorPermissions& NavigatorPermissions::from(Navigator& navigator)
{
auto* supplement = static_cast<NavigatorPermissions*>(Supplement<Navigator>::from(&navigator, supplementName()));
if (!supplement) {
@@ -58,7 +58,7 @@ NavigatorPermissions* NavigatorPermissions::from(Navigator& navigator)
provideTo(&navigator, supplementName(), WTFMove(newSupplement));
}

return supplement;
return *supplement;
}

const char* NavigatorPermissions::supplementName()
@@ -37,11 +37,11 @@ class NavigatorPermissions final : public Supplement<Navigator> {
public:
explicit NavigatorPermissions(Navigator&);

static RefPtr<Permissions> permissions(Navigator&);
RefPtr<Permissions> permissions();
static Permissions& permissions(Navigator&);
Permissions& permissions();

private:
static NavigatorPermissions* from(Navigator&);
static NavigatorPermissions& from(Navigator&);
static const char* supplementName();

RefPtr<Permissions> m_permissions;
@@ -25,13 +25,13 @@

#pragma once

#include "PermissionState.h"
#include <wtf/CompletionHandler.h>
#include <wtf/RefPtr.h>
#include <wtf/ThreadSafeRefCounted.h>

namespace WebCore {

enum class PermissionState : uint8_t;
class Page;
class PermissionObserver;
struct ClientOrigin;
@@ -33,6 +33,7 @@
#include "PermissionController.h"
#include "SecurityOrigin.h"
#include <wtf/IsoMallocInlines.h>
#include <wtf/MainThread.h>

namespace WebCore {

@@ -53,13 +54,17 @@ PermissionStatus::PermissionStatus(ScriptExecutionContext& context, PermissionSt
auto* origin = context.securityOrigin();
auto originData = origin ? origin->data() : SecurityOriginData { };
m_origin = ClientOrigin { context.topOrigin().data(), WTFMove(originData) };

PermissionController::shared().addObserver(*this);

// FIXME: Add support for workers. Currently, this only works for Window objects.
if (isMainThread())
PermissionController::shared().addObserver(*this);
}

PermissionStatus::~PermissionStatus()
{
PermissionController::shared().removeObserver(*this);
// FIXME: Add support for workers. Currently, this only works for Window objects.
if (isMainThread())
PermissionController::shared().removeObserver(*this);
}

void PermissionStatus::stateChanged(PermissionState newState)
@@ -28,7 +28,7 @@
[
ActiveDOMObject,
EnabledBySetting=PermissionsAPIEnabled,
Exposed=(Window)
Exposed=(Window,DedicatedWorker)
] interface PermissionStatus : EventTarget {
readonly attribute PermissionState state;
readonly attribute PermissionName name;

0 comments on commit fd42e2c

Please sign in to comment.