Skip to content

Commit bf728b5

Browse files
benjamingrtargos
authored andcommitted
events: make abort_controller event trusted
The AbortController abort event is trusted, currently we fire all events with isTrusted: false. Allow dispatching events internally with `isTrusted: true` and add a test for it. Co-Authored-By: ExE Boss <[email protected]> Fixes: #35748 PR-URL: #35811 Backport-PR-URL: #38386 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Rich Trott <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent e93615c commit bf728b5

File tree

5 files changed

+59
-6
lines changed

5 files changed

+59
-6
lines changed

doc/api/events.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -1272,9 +1272,10 @@ This is not used in Node.js and is provided purely for completeness.
12721272
added: v14.5.0
12731273
-->
12741274

1275-
* Type: {boolean} Always returns `false`.
1275+
* Type: {boolean} True for Node.js internal events, false otherwise.
12761276

1277-
This is not used in Node.js and is provided purely for completeness.
1277+
Currently only `AbortSignal`s' `"abort"` event is fired with `isTrusted`
1278+
set to `true`.
12781279

12791280
#### `event.preventDefault()`
12801281
<!-- YAML

lib/internal/abort_controller.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ const {
1010

1111
const {
1212
EventTarget,
13-
Event
13+
Event,
14+
kTrustEvent
1415
} = require('internal/event_target');
1516
const {
1617
customInspectSymbol,
@@ -48,7 +49,9 @@ Object.defineProperties(AbortSignal.prototype, {
4849
function abortSignal(signal) {
4950
if (signal[kAborted]) return;
5051
signal[kAborted] = true;
51-
const event = new Event('abort');
52+
const event = new Event('abort', {
53+
[kTrustEvent]: true
54+
});
5255
if (typeof signal.onabort === 'function') {
5356
signal.onabort(event);
5457
}

lib/internal/event_target.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ const {
88
NumberIsInteger,
99
Object,
1010
ObjectDefineProperty,
11+
ObjectGetOwnPropertyDescriptor,
1112
String,
1213
Symbol,
1314
SymbolFor,
1415
SymbolToStringTag,
16+
SafeWeakSet,
1517
} = primordials;
1618

1719
const {
@@ -40,6 +42,7 @@ const kRemoveListener = Symbol('kRemoveListener');
4042
const kIsNodeStyleListener = Symbol('kIsNodeStyleListener');
4143
const kMaxListeners = Symbol('kMaxListeners');
4244
const kMaxListenersWarned = Symbol('kMaxListenersWarned');
45+
const kTrustEvent = Symbol('kTrustEvent');
4346

4447
// Lazy load perf_hooks to avoid the additional overhead on startup
4548
let perf_hooks;
@@ -60,7 +63,12 @@ const kBubbles = Symbol('bubbles');
6063
const kComposed = Symbol('composed');
6164
const kPropagationStopped = Symbol('propagationStopped');
6265

63-
const isTrusted = () => false;
66+
const isTrustedSet = new SafeWeakSet();
67+
const isTrusted = ObjectGetOwnPropertyDescriptor({
68+
get isTrusted() {
69+
return isTrustedSet.has(this);
70+
}
71+
}, 'isTrusted').get;
6472

6573
class Event {
6674
constructor(type, options) {
@@ -76,6 +84,10 @@ class Event {
7684
this[kDefaultPrevented] = false;
7785
this[kTimestamp] = lazyNow();
7886
this[kPropagationStopped] = false;
87+
if (options != null && options[kTrustEvent]) {
88+
isTrustedSet.add(this);
89+
}
90+
7991
// isTrusted is special (LegacyUnforgeable)
8092
ObjectDefineProperty(this, 'isTrusted', {
8193
get: isTrusted,
@@ -572,5 +584,6 @@ module.exports = {
572584
initNodeEventTarget,
573585
kCreateEvent,
574586
kNewListener,
587+
kTrustEvent,
575588
kRemoveListener,
576589
};

lib/internal/per_context/primordials.js

+4
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ primordials.SafeSet = makeSafe(
101101
Set,
102102
class SafeSet extends Set {}
103103
);
104+
primordials.SafeWeakSet = makeSafe(
105+
WeakSet,
106+
class SafeWeakSet extends WeakSet {}
107+
);
104108
primordials.SafePromise = makeSafe(
105109
Promise,
106110
class SafePromise extends Promise {}

test/parallel/test-abortcontroller.js

+33-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
// Flags: --no-warnings --experimental-abortcontroller
1+
// Flags: --no-warnings --expose-internals --experimental-abortcontroller
22
'use strict';
33

44
const common = require('../common');
55

66
const { ok, strictEqual } = require('assert');
7+
const { Event } = require('internal/event_target');
78

89
{
10+
// Tests that abort is fired with the correct event type on AbortControllers
911
const ac = new AbortController();
1012
ok(ac.signal);
1113
ac.signal.onabort = common.mustCall((event) => {
@@ -20,3 +22,33 @@ const { ok, strictEqual } = require('assert');
2022
ac.abort();
2123
ok(ac.signal.aborted);
2224
}
25+
26+
{
27+
// Tests that abort events are trusted
28+
const ac = new AbortController();
29+
ac.signal.addEventListener('abort', common.mustCall((event) => {
30+
ok(event.isTrusted);
31+
}));
32+
ac.abort();
33+
}
34+
35+
{
36+
// Tests that abort events have the same `isTrusted` reference
37+
const first = new AbortController();
38+
const second = new AbortController();
39+
let ev1, ev2;
40+
const ev3 = new Event('abort');
41+
first.signal.addEventListener('abort', common.mustCall((event) => {
42+
ev1 = event;
43+
}));
44+
second.signal.addEventListener('abort', common.mustCall((event) => {
45+
ev2 = event;
46+
}));
47+
first.abort();
48+
second.abort();
49+
const firstTrusted = Reflect.getOwnPropertyDescriptor(ev1, 'isTrusted').get;
50+
const secondTrusted = Reflect.getOwnPropertyDescriptor(ev2, 'isTrusted').get;
51+
const untrusted = Reflect.getOwnPropertyDescriptor(ev3, 'isTrusted').get;
52+
strictEqual(firstTrusted, secondTrusted);
53+
strictEqual(untrusted, firstTrusted);
54+
}

0 commit comments

Comments
 (0)