Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
events: add type check for event name
According to docs only string/symbol are allowed but the checks done are
more relaxed and allow additionally number/bigint as it seems they are
used in user land modules.
  • Loading branch information
Flarna committed Jan 28, 2020
commit b952d9f41c2c7d4b92c962fa44961bd39373bda9
22 changes: 22 additions & 0 deletions lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ function checkListener(listener) {
}
}

function checkType(type) {
Comment thread
Flarna marked this conversation as resolved.
Outdated
// Besides string/symbol also numeric types are seen in the wild
switch (typeof type) {
case 'string':
case 'symbol':
case 'number':
case 'bigint':
return;
}
throw new ERR_INVALID_ARG_TYPE('type', ['string', 'symbol'], type);
}

ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', {
enumerable: true,
get: function() {
Expand Down Expand Up @@ -351,6 +363,7 @@ function _addListener(target, type, listener, prepend) {
let events;
let existing;

checkType(type);
checkListener(listener);

events = target._events;
Expand Down Expand Up @@ -457,6 +470,7 @@ EventEmitter.prototype.removeListener =
function removeListener(type, listener) {
let originalListener;

checkType(type);
checkListener(listener);

const events = this._events;
Expand Down Expand Up @@ -511,6 +525,10 @@ EventEmitter.prototype.off = EventEmitter.prototype.removeListener;

EventEmitter.prototype.removeAllListeners =
function removeAllListeners(type) {
if (arguments.length !== 0) {
checkType(type);
}

const events = this._events;
if (events === undefined)
return this;
Expand Down Expand Up @@ -556,6 +574,8 @@ EventEmitter.prototype.removeAllListeners =
};

function _listeners(target, type, unwrap) {
checkType(type);

const events = target._events;

if (events === undefined)
Expand Down Expand Up @@ -590,6 +610,8 @@ EventEmitter.listenerCount = function(emitter, type) {

EventEmitter.prototype.listenerCount = listenerCount;
function listenerCount(type) {
checkType(type);

const events = this._events;

if (events !== undefined) {
Expand Down
21 changes: 21 additions & 0 deletions test/parallel/test-event-emitter-add-listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,24 @@ assert.throws(() => {
message: 'The "listener" argument must be of type function. ' +
'Received null'
});

// Verify that illegal types for event name are rejected
[
() => {},
undefined,
{},
async function named() {},
/regex/,
true,
null
].forEach((value) => {
assert.throws(() => {
const ee = new EventEmitter();
ee.on(value, () => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol.' +
common.invalidArgTypeHelper(value)
});
});
18 changes: 18 additions & 0 deletions test/parallel/test-event-emitter-listener-count.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,21 @@ assert.strictEqual(emitter.listenerCount('foo'), 2);
assert.strictEqual(emitter.listenerCount('bar'), 0);
assert.strictEqual(emitter.listenerCount('baz'), 1);
assert.strictEqual(emitter.listenerCount(123), 1);

assert.throws(() => {
EventEmitter.listenerCount(emitter, () => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol. ' +
'Received type function ([Function (anonymous)])'
});

assert.throws(() => {
emitter.listenerCount(() => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol. ' +
'Received type function ([Function (anonymous)])'
});
20 changes: 20 additions & 0 deletions test/parallel/test-event-emitter-listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,23 @@ function listener4() {
assert.strictEqual(rawListener.length, 1);
assert.strictEqual(rawListener[0](), 1);
}

{
const ee = new events.EventEmitter();
assert.throws(() => {
ee.listeners(() => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol. ' +
'Received type function ([Function (anonymous)])'
});
assert.throws(() => {
ee.rawListeners(() => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol. ' +
'Received type function ([Function (anonymous)])'
});
}
23 changes: 0 additions & 23 deletions test/parallel/test-event-emitter-max-listeners-warning-for-null.js

This file was deleted.

11 changes: 11 additions & 0 deletions test/parallel/test-event-emitter-once.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ assert.throws(() => {
'Received null'
});

// Verify that the type must be a string or symbol
assert.throws(() => {
const ee = new EventEmitter();
ee.once(() => {}, () => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol. ' +
'Received type function ([Function (anonymous)])'
});

{
// once() has different code paths based on the number of arguments being
// emitted. Verify that all of the cases are covered.
Expand Down
11 changes: 11 additions & 0 deletions test/parallel/test-event-emitter-prepend.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ assert.throws(() => {
'Received null'
});

// Verify that the type must be a string or symbol
assert.throws(() => {
const ee = new EventEmitter();
ee.prependOnceListener(() => {}, () => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol. ' +
'Received type function ([Function (anonymous)])'
});

// Test fallback if prependListener is undefined.
const stream = require('stream');

Expand Down
12 changes: 12 additions & 0 deletions test/parallel/test-event-emitter-remove-all-listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,15 @@ function expect(expected) {
ee._events = undefined;
assert.strictEqual(ee, ee.removeAllListeners());
}

{
assert.throws(() => {
const ee = new events.EventEmitter();
ee.removeAllListeners(() => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol. ' +
'Received type function ([Function (anonymous)])'
});
}
13 changes: 13 additions & 0 deletions test/parallel/test-event-emitter-remove-listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,19 @@ assert.throws(() => {
'Received null'
});

// Verify that the removed type must be a function
{
assert.throws(() => {
const ee = new EventEmitter();
ee.removeAllListeners(() => {});
}, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "type" argument must be one of type string or symbol. ' +
'Received type function ([Function (anonymous)])'
});
}

{
const ee = new EventEmitter();
const listener = () => {};
Expand Down