Skip to content

Commit 7f4e1a7

Browse files
committedSep 19, 2023
[fix] Add missing rejection handler
Use `queueMicrotask()` when available and add a rejection handler to the shim for it.
1 parent 7460049 commit 7f4e1a7

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed
 

‎lib/receiver.js

+36-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ const { isValidStatusCode, isValidUTF8 } = require('./validation');
1515
const FastBuffer = Buffer[Symbol.species];
1616
const promise = Promise.resolve();
1717

18+
//
19+
// `queueMicrotask()` is not available in Node.js < 11.
20+
//
21+
const queueTask =
22+
typeof queueMicrotask === 'function' ? queueMicrotask : queueMicrotaskShim;
23+
1824
const GET_INFO = 0;
1925
const GET_PAYLOAD_LENGTH_16 = 1;
2026
const GET_PAYLOAD_LENGTH_64 = 2;
@@ -169,11 +175,7 @@ class Receiver extends Writable {
169175
//
170176
this._loop = false;
171177

172-
//
173-
// `queueMicrotask()` is not available in Node.js < 11 and is no
174-
// better anyway.
175-
//
176-
promise.then(() => {
178+
queueTask(() => {
177179
this._state = GET_INFO;
178180
this.startLoop(cb);
179181
});
@@ -646,3 +648,32 @@ function error(ErrorCtor, message, prefix, statusCode, errorCode) {
646648
err[kStatusCode] = statusCode;
647649
return err;
648650
}
651+
652+
/**
653+
* A shim for `queueMicrotask()`.
654+
*
655+
* @param {Function} cb Callback
656+
*/
657+
function queueMicrotaskShim(cb) {
658+
promise.then(cb).catch(throwErrorNextTick);
659+
}
660+
661+
/**
662+
* Throws an error.
663+
*
664+
* @param {Error} err The error to throw
665+
* @private
666+
*/
667+
function throwError(err) {
668+
throw err;
669+
}
670+
671+
/**
672+
* Throws an error in the next tick.
673+
*
674+
* @param {Error} err The error to throw
675+
* @private
676+
*/
677+
function throwErrorNextTick(err) {
678+
process.nextTick(throwError, err);
679+
}

‎test/receiver.test.js

+30
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const assert = require('assert');
44
const crypto = require('crypto');
5+
const EventEmitter = require('events');
56

67
const PerMessageDeflate = require('../lib/permessage-deflate');
78
const Receiver = require('../lib/receiver');
@@ -1175,4 +1176,33 @@ describe('Receiver', () => {
11751176

11761177
receiver.write(Buffer.from('8A01318A01328A0133', 'hex'));
11771178
});
1179+
1180+
it('does not swallow errors thrown from event handlers', (done) => {
1181+
const receiver = new Receiver();
1182+
let count = 0;
1183+
1184+
receiver.on('message', function () {
1185+
if (++count === 2) {
1186+
throw new Error('Oops');
1187+
}
1188+
});
1189+
1190+
assert.strictEqual(
1191+
process.listenerCount('uncaughtException'),
1192+
EventEmitter.usingDomains ? 2 : 1
1193+
);
1194+
1195+
const listener = process.listeners('uncaughtException').pop();
1196+
1197+
process.removeListener('uncaughtException', listener);
1198+
process.once('uncaughtException', (err) => {
1199+
assert.ok(err instanceof Error);
1200+
assert.strictEqual(err.message, 'Oops');
1201+
1202+
process.on('uncaughtException', listener);
1203+
done();
1204+
});
1205+
1206+
receiver.write(Buffer.from('82008200', 'hex'));
1207+
});
11781208
});

0 commit comments

Comments
 (0)
Please sign in to comment.