Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cd3a142

Browse files
Zirakcodebytere
authored andcommittedJun 27, 2020
events: Handle a range of this values for dispatchEvent
On the web, dispatchEvent is finicky about its `this` value. An exception is thrown for `this` values which are not an EventTarget. PR-URL: #34015 Reviewed-By: Denys Otrishko <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent aa1cb3f commit cd3a142

File tree

2 files changed

+47
-1
lines changed

2 files changed

+47
-1
lines changed
 

‎lib/internal/event_target.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,25 @@ const {
99
Object,
1010
Set,
1111
Symbol,
12+
SymbolFor,
1213
SymbolToStringTag,
1314
} = primordials;
1415

1516
const {
1617
codes: {
1718
ERR_INVALID_ARG_TYPE,
1819
ERR_EVENT_RECURSION,
19-
ERR_MISSING_ARGS
20+
ERR_MISSING_ARGS,
21+
ERR_INVALID_THIS,
2022
}
2123
} = require('internal/errors');
2224
const { validateInteger, validateObject } = require('internal/validators');
2325

2426
const { customInspectSymbol } = require('internal/util');
2527
const { inspect } = require('util');
2628

29+
const kIsEventTarget = SymbolFor('nodejs.event_target');
30+
2731
const kEvents = Symbol('kEvents');
2832
const kStop = Symbol('kStop');
2933
const kTarget = Symbol('kTarget');
@@ -185,6 +189,10 @@ class Listener {
185189
}
186190

187191
class EventTarget {
192+
// Used in checking whether an object is an EventTarget. This is a well-known
193+
// symbol as EventTarget may be used cross-realm. See discussion in #33661.
194+
static [kIsEventTarget] = true;
195+
188196
[kEvents] = new Map();
189197
#emitting = new Set();
190198

@@ -257,6 +265,10 @@ class EventTarget {
257265
throw new ERR_INVALID_ARG_TYPE('event', 'Event', event);
258266
}
259267

268+
if (!isEventTarget(this)) {
269+
throw new ERR_INVALID_THIS('EventTarget');
270+
}
271+
260272
if (this.#emitting.has(event.type) ||
261273
event[kTarget] !== null) {
262274
throw new ERR_EVENT_RECURSION(event.type);
@@ -438,6 +450,15 @@ function validateEventListenerOptions(options) {
438450
};
439451
}
440452

453+
// Test whether the argument is an event object. This is far from a fool-proof
454+
// test, for example this input will result in a false positive:
455+
// > isEventTarget({ constructor: EventTarget })
456+
// It stands in its current implementation as a compromise. For the relevant
457+
// discussion, see #33661.
458+
function isEventTarget(obj) {
459+
return obj && obj.constructor && obj.constructor[kIsEventTarget];
460+
}
461+
441462
function addCatch(that, promise, event) {
442463
const then = promise.then;
443464
if (typeof then === 'function') {

‎test/parallel/test-eventtarget.js

+25
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,28 @@ ok(EventTarget);
439439
const event = new Event('');
440440
strictEqual(event.toString(), '[object Event]');
441441
}
442+
443+
{
444+
// `this` value of dispatchEvent
445+
const target = new EventTarget();
446+
const target2 = new EventTarget();
447+
const event = new Event('foo');
448+
449+
ok(target.dispatchEvent.call(target2, event));
450+
451+
[
452+
'foo',
453+
{},
454+
[],
455+
1,
456+
null,
457+
undefined,
458+
false,
459+
Symbol(),
460+
/a/
461+
].forEach((i) => {
462+
throws(() => target.dispatchEvent.call(i, event), {
463+
code: 'ERR_INVALID_THIS'
464+
});
465+
});
466+
}

0 commit comments

Comments
 (0)
Please sign in to comment.