worker: add brand checks for detached properties/methods

Add proper brand-checking for detached property and method
accesses. Also adds a note about non-standard APIs and
makes the standard accessors enumerable.

Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: https://github.com/nodejs/node/pull/39763
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
This commit is contained in:
James M Snell
2021-08-13 15:12:07 -07:00
parent e087d78472
commit 966060df0e
2 changed files with 56 additions and 1 deletions

View File

@@ -53,6 +53,7 @@ const { inspect } = require('internal/util/inspect');
const {
codes: {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_THIS,
ERR_MISSING_ARGS,
}
} = require('internal/errors');
@@ -74,6 +75,7 @@ const kStartedReading = Symbol('kStartedReading');
const kStdioWantsMoreDataCallback = Symbol('kStdioWantsMoreDataCallback');
const kCurrentlyReceivingPorts =
SymbolFor('nodejs.internal.kCurrentlyReceivingPorts');
const kType = Symbol('kType');
const messageTypes = {
UP_AND_RUNNING: 'upAndRunning',
@@ -349,11 +351,16 @@ function onMessageEvent(type, data) {
this.dispatchEvent(new MessageEvent(type, { data }));
}
function isBroadcastChannel(value) {
return value?.[kType] === 'BroadcastChannel';
}
class BroadcastChannel extends EventTarget {
constructor(name) {
if (arguments.length === 0)
throw new ERR_MISSING_ARGS('name');
super();
this[kType] = 'BroadcastChannel';
this[kName] = `${name}`;
this[kHandle] = broadcastChannel(this[kName]);
this[kOnMessage] = FunctionPrototypeBind(onMessageEvent, this, 'message');
@@ -364,6 +371,8 @@ class BroadcastChannel extends EventTarget {
}
[inspect.custom](depth, options) {
if (!isBroadcastChannel(this))
throw new ERR_INVALID_THIS('BroadcastChannel');
if (depth < 0)
return 'BroadcastChannel';
@@ -378,9 +387,15 @@ class BroadcastChannel extends EventTarget {
}, opts)}`;
}
get name() { return this[kName]; }
get name() {
if (!isBroadcastChannel(this))
throw new ERR_INVALID_THIS('BroadcastChannel');
return this[kName];
}
close() {
if (!isBroadcastChannel(this))
throw new ERR_INVALID_THIS('BroadcastChannel');
if (this[kHandle] === undefined)
return;
this[kHandle].off('message', this[kOnMessage]);
@@ -392,6 +407,8 @@ class BroadcastChannel extends EventTarget {
}
postMessage(message) {
if (!isBroadcastChannel(this))
throw new ERR_INVALID_THIS('BroadcastChannel');
if (arguments.length === 0)
throw new ERR_MISSING_ARGS('message');
if (this[kHandle] === undefined)
@@ -400,19 +417,40 @@ class BroadcastChannel extends EventTarget {
throw new DOMException('Message could not be posted.');
}
// The ref() method is Node.js specific and not part of the standard
// BroadcastChannel API definition. Typically we shouldn't extend Web
// Platform APIs with Node.js specific methods but ref and unref
// are a bit special.
ref() {
if (!isBroadcastChannel(this))
throw new ERR_INVALID_THIS('BroadcastChannel');
if (this[kHandle])
this[kHandle].ref();
return this;
}
// The unref() method is Node.js specific and not part of the standard
// BroadcastChannel API definition. Typically we shouldn't extend Web
// Platform APIs with Node.js specific methods but ref and unref
// are a bit special.
unref() {
if (!isBroadcastChannel(this))
throw new ERR_INVALID_THIS('BroadcastChannel');
if (this[kHandle])
this[kHandle].unref();
return this;
}
}
const kEnumerableProperty = ObjectCreate(null);
kEnumerableProperty.enumerable = true;
ObjectDefineProperties(BroadcastChannel.prototype, {
name: kEnumerableProperty,
close: kEnumerableProperty,
postMessage: kEnumerableProperty,
});
defineEventHandler(BroadcastChannel.prototype, 'message');
defineEventHandler(BroadcastChannel.prototype, 'messageerror');