Skip to content

Commit

Permalink
events: make abort_controller event trusted
Browse files Browse the repository at this point in the history
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 <3889017+ExE-Boss@users.noreply.github.com>
Fixes: #35748

PR-URL: #35811
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
benjamingr authored and nodejs-github-bot committed Oct 28, 2020
1 parent 81ba3ae commit f20a783
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 6 deletions.
5 changes: 3 additions & 2 deletions doc/api/events.md
Expand Up @@ -1282,9 +1282,10 @@ This is not used in Node.js and is provided purely for completeness.
added: v14.5.0
-->

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

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

#### `event.preventDefault()`
<!-- YAML
Expand Down
7 changes: 5 additions & 2 deletions lib/internal/abort_controller.js
Expand Up @@ -11,7 +11,8 @@ const {

const {
EventTarget,
Event
Event,
kTrustEvent
} = require('internal/event_target');
const {
customInspectSymbol,
Expand Down Expand Up @@ -49,7 +50,9 @@ ObjectDefineProperties(AbortSignal.prototype, {
function abortSignal(signal) {
if (signal[kAborted]) return;
signal[kAborted] = true;
const event = new Event('abort');
const event = new Event('abort', {
[kTrustEvent]: true
});
if (typeof signal.onabort === 'function') {
signal.onabort(event);
}
Expand Down
15 changes: 14 additions & 1 deletion lib/internal/event_target.js
Expand Up @@ -9,10 +9,12 @@ const {
ObjectAssign,
ObjectDefineProperties,
ObjectDefineProperty,
ObjectGetOwnPropertyDescriptor,
String,
Symbol,
SymbolFor,
SymbolToStringTag,
SafeWeakSet,
} = primordials;

const {
Expand Down Expand Up @@ -41,6 +43,7 @@ const kRemoveListener = Symbol('kRemoveListener');
const kIsNodeStyleListener = Symbol('kIsNodeStyleListener');
const kMaxListeners = Symbol('kMaxListeners');
const kMaxListenersWarned = Symbol('kMaxListenersWarned');
const kTrustEvent = Symbol('kTrustEvent');

// Lazy load perf_hooks to avoid the additional overhead on startup
let perf_hooks;
Expand All @@ -61,7 +64,12 @@ const kBubbles = Symbol('bubbles');
const kComposed = Symbol('composed');
const kPropagationStopped = Symbol('propagationStopped');

const isTrusted = () => false;
const isTrustedSet = new SafeWeakSet();
const isTrusted = ObjectGetOwnPropertyDescriptor({
get isTrusted() {
return isTrustedSet.has(this);
}
}, 'isTrusted').get;

class Event {
constructor(type, options) {
Expand All @@ -77,6 +85,10 @@ class Event {
this[kDefaultPrevented] = false;
this[kTimestamp] = lazyNow();
this[kPropagationStopped] = false;
if (options != null && options[kTrustEvent]) {
isTrustedSet.add(this);
}

// isTrusted is special (LegacyUnforgeable)
ObjectDefineProperty(this, 'isTrusted', {
get: isTrusted,
Expand Down Expand Up @@ -573,5 +585,6 @@ module.exports = {
initNodeEventTarget,
kCreateEvent,
kNewListener,
kTrustEvent,
kRemoveListener,
};
4 changes: 4 additions & 0 deletions lib/internal/per_context/primordials.js
Expand Up @@ -101,6 +101,10 @@ primordials.SafeSet = makeSafe(
Set,
class SafeSet extends Set {}
);
primordials.SafeWeakSet = makeSafe(
WeakSet,
class SafeWeakSet extends WeakSet {}
);
primordials.SafePromise = makeSafe(
Promise,
class SafePromise extends Promise {}
Expand Down
34 changes: 33 additions & 1 deletion test/parallel/test-abortcontroller.js
@@ -1,11 +1,13 @@
// Flags: --no-warnings
// Flags: --no-warnings --expose-internals
'use strict';

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

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

{
// Tests that abort is fired with the correct event type on AbortControllers
const ac = new AbortController();
ok(ac.signal);
ac.signal.onabort = common.mustCall((event) => {
Expand All @@ -20,3 +22,33 @@ const { ok, strictEqual } = require('assert');
ac.abort();
ok(ac.signal.aborted);
}

{
// Tests that abort events are trusted
const ac = new AbortController();
ac.signal.addEventListener('abort', common.mustCall((event) => {
ok(event.isTrusted);
}));
ac.abort();
}

{
// Tests that abort events have the same `isTrusted` reference
const first = new AbortController();
const second = new AbortController();
let ev1, ev2;
const ev3 = new Event('abort');
first.signal.addEventListener('abort', common.mustCall((event) => {
ev1 = event;
}));
second.signal.addEventListener('abort', common.mustCall((event) => {
ev2 = event;
}));
first.abort();
second.abort();
const firstTrusted = Reflect.getOwnPropertyDescriptor(ev1, 'isTrusted').get;
const secondTrusted = Reflect.getOwnPropertyDescriptor(ev2, 'isTrusted').get;
const untrusted = Reflect.getOwnPropertyDescriptor(ev3, 'isTrusted').get;
strictEqual(firstTrusted, secondTrusted);
strictEqual(untrusted, firstTrusted);
}

0 comments on commit f20a783

Please sign in to comment.