From 778f27dd19eddc00356a05bfca7358f352ffe405 Mon Sep 17 00:00:00 2001 From: Zach Bjornson Date: Fri, 8 Mar 2019 11:07:13 -0800 Subject: [PATCH 1/6] support res.removeLister("drain"), res.once("drain") Fixes #152 Fixes #135 --- index.js | 28 +++++++ test/compression.js | 193 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) diff --git a/index.js b/index.js index 1d089427..9d4b6a73 100644 --- a/index.js +++ b/index.js @@ -64,6 +64,7 @@ function compression (options) { var _end = res.end var _on = res.on + var _removeListener = res.removeListener var _write = res.write // flush @@ -131,6 +132,33 @@ function compression (options) { return this } + res.addListener = res.on + + res.removeListener = function removeListener (type, listener) { + if (!listeners || type !== 'drain') { + return _removeListener.call(this, type, listener) + } + + if (stream) { + return stream.removeListener(type, listener) + } + + // remove buffered listener + for (var i = listeners.length - 1; i >= 0; i--) { + if (listeners[i][0] === type && listeners[i][1] === listener) { + listeners.splice(i, 1) + } + } + + return this + } + + /* istanbul ignore next */ + if (res.off) { + // emitter.off was added in Node.js v10+; don't add it to earlier versions + res.off = res.removeListener + } + function nocompress (msg) { debug('no compression: %s', msg) addListeners(res, _on, listeners) diff --git a/test/compression.js b/test/compression.js index 6975ea0b..d1045acb 100644 --- a/test/compression.js +++ b/test/compression.js @@ -305,6 +305,192 @@ describe('compression()', function () { .expect(200, done) }) + it('should support removeListener("drain") after on("drain"); stream present', function (done) { + // compression doesn't proxy listenerCount() to the compression stream, so + // instead watch for a MaxListenersExceededWarning + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + var len = bytes('40kb') + var buf = Buffer.alloc(len, '.') + res.write(buf) + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.on('drain', listener) + res.removeListener('drain', listener) + } + res.end() + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) + }) + + it('should support removeListener("drain") after addListener("drain")', function (done) { + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + var len = bytes('40kb') + var buf = Buffer.alloc(len, '.') + res.write(buf) + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.addListener('drain', listener) + res.removeListener('drain', listener) + } + res.end() + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) + }) + + it('should support off("drain") after addListener("drain")', function (done) { + if (!require('events').EventEmitter.prototype.off) { // off was added in Node.js v10 + this.skip() + } + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + var len = bytes('40kb') + var buf = Buffer.alloc(len, '.') + res.write(buf) + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.addListener('drain', listener) + res.off('drain', listener) + } + res.end() + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) + }) + + it('should support removeListener("drain"); buffered', function (done) { + // Variant of above tests for scenario when the listener is buffered (stream + // is not yet present). + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.on('end', function () {}) + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.on('drain', listener) + res.removeListener('drain', listener) + } + res.end() + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) + }) + + it('should support removeListener("drain"); multiple bindings of same listener, buffered', function (done) { + // Variant of above test for scenario when the listener is buffered (stream + // is not yet present) and the same listener is added two or more times. + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.on('drain', listener) + res.on('drain', listener) + res.removeListener('drain', listener) + } + res.end() + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) + }) + + it('should not leak event listeners when res.unpipe() is used (#135)', function (done) { + // unpipe and stream.Readable were added in v0.9.4 + var stream = require('stream') + if (!(stream.Readable && stream.Readable.prototype.unpipe)) { + this.skip() + } + + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + var server = createServer({ threshold: 0 }, function (req, res) { + var times = 0 + var int = setInterval(function () { + var rs = require('fs').createReadStream('does not exist') + rs.on('error', function (e) { + rs.unpipe(res) + }) + rs.pipe(res) + if (times++ > res.getMaxListeners()) { + clearInterval(int) + res.end('hello, world') + } + }) + }) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) + }) + describe('threshold', function () { it('should not compress responses below the threshold size', function (done) { var server = createServer({ threshold: '1kb' }, function (req, res) { @@ -669,6 +855,13 @@ function createServer (opts, fn) { return } + if (typeof res.getMaxListeners !== 'function') { + // Added in v0.11.2 + res.getMaxListeners = function getMaxListeners () { + return 10 + } + } + fn(req, res) }) }) From 110da6724ecf0fd30e1ddda7dc6167dabe5afb6e Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 15 Jul 2020 22:39:41 -0400 Subject: [PATCH 2/6] WIP generic add listener interceptor --- index.js | 87 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/index.js b/index.js index 9d4b6a73..874ac586 100644 --- a/index.js +++ b/index.js @@ -63,10 +63,23 @@ function compression (options) { var stream var _end = res.end - var _on = res.on var _removeListener = res.removeListener var _write = res.write + // proxy drain events from stream + var _addListener = interceptAddListener(res, function (type, listener) { + if (!listeners || type !== 'drain') { + // skip intercept + return false + } else if (stream) { + // add listener to stream instead + stream.on(type, listener) + } else { + // buffer listeners for future stream + listeners.push([type, listener]) + } + }) + // flush res.flush = function flush () { if (stream) { @@ -117,23 +130,6 @@ function compression (options) { : stream.end() } - res.on = function on (type, listener) { - if (!listeners || type !== 'drain') { - return _on.call(this, type, listener) - } - - if (stream) { - return stream.on(type, listener) - } - - // buffer listeners for future stream - listeners.push([type, listener]) - - return this - } - - res.addListener = res.on - res.removeListener = function removeListener (type, listener) { if (!listeners || type !== 'drain') { return _removeListener.call(this, type, listener) @@ -161,7 +157,7 @@ function compression (options) { function nocompress (msg) { debug('no compression: %s', msg) - addListeners(res, _on, listeners) + addListeners(res, _addListener, listeners) listeners = null } @@ -240,7 +236,7 @@ function compression (options) { _end.call(res) }) - _on.call(res, 'drain', function onResponseDrain () { + _addListener.call(res, 'drain', function onResponseDrain () { stream.resume() }) }) @@ -254,9 +250,9 @@ function compression (options) { * @private */ -function addListeners (stream, on, listeners) { +function addListeners (stream, addListener, listeners) { for (var i = 0; i < listeners.length; i++) { - on.apply(stream, listeners[i]) + addListener.apply(stream, listeners[i]) } } @@ -274,6 +270,53 @@ function chunkLength (chunk, encoding) { : chunk.length } +/** + * Intercept add listener on event emitter. + * @private + */ + +function interceptAddListener (ee, fn) { + var _addListener = ee.addListener + var _on = ee.on + + if (_addListener) { + Object.defineProperty(ee, 'addListener', { + configurable: true, + value: addListener, + writable: true + }) + } + + if (_on) { + Object.defineProperty(ee, 'on', { + configurable: true, + value: on, + writable: true + }) + } + + return _addListener || _on || noop + + function addListener (type, listener) { + return fn.call(this, type, listener) === false + ? _addListener.call(this, type, listener) + : this + } + + function on (type, listener) { + return fn.call(this, type, listener) === false + ? _on.call(this, type, listener) + : this + } +} + +/** + * Reusable no-op function. + * @private + */ + +function noop () {} + /** * Default filter function. * @private From c0daad2b84fa47519534550355cb46b2b5be9202 Mon Sep 17 00:00:00 2001 From: Douglas Christopher Wilson Date: Wed, 15 Jul 2020 22:44:32 -0400 Subject: [PATCH 3/6] WIP generic remove listener interceptor --- index.js | 83 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/index.js b/index.js index 874ac586..80d0ca8d 100644 --- a/index.js +++ b/index.js @@ -63,7 +63,6 @@ function compression (options) { var stream var _end = res.end - var _removeListener = res.removeListener var _write = res.write // proxy drain events from stream @@ -80,6 +79,23 @@ function compression (options) { } }) + interceptRemoveListener(res, function (type, listener) { + if (!listeners || type !== 'drain') { + // skip intercept + return false + } else if (stream) { + // remove listener from stream + stream.removeListener(type, listener) + } else { + // remove buffered listener + for (var i = listeners.length - 1; i >= 0; i--) { + if (listeners[i][0] === type && listeners[i][1] === listener) { + listeners.splice(i, 1) + } + } + } + }) + // flush res.flush = function flush () { if (stream) { @@ -130,31 +146,6 @@ function compression (options) { : stream.end() } - res.removeListener = function removeListener (type, listener) { - if (!listeners || type !== 'drain') { - return _removeListener.call(this, type, listener) - } - - if (stream) { - return stream.removeListener(type, listener) - } - - // remove buffered listener - for (var i = listeners.length - 1; i >= 0; i--) { - if (listeners[i][0] === type && listeners[i][1] === listener) { - listeners.splice(i, 1) - } - } - - return this - } - - /* istanbul ignore next */ - if (res.off) { - // emitter.off was added in Node.js v10+; don't add it to earlier versions - res.off = res.removeListener - } - function nocompress (msg) { debug('no compression: %s', msg) addListeners(res, _addListener, listeners) @@ -310,6 +301,46 @@ function interceptAddListener (ee, fn) { } } +/** + * Intercept add listener on event emitter. + * @private + */ + +function interceptRemoveListener (ee, fn) { + var _removeListener = ee.removeListener + var _off = ee.off + + if (_removeListener) { + Object.defineProperty(ee, 'removeListener', { + configurable: true, + value: removeListener, + writable: true + }) + } + + if (_off) { + Object.defineProperty(ee, 'off', { + configurable: true, + value: off, + writable: true + }) + } + + return _removeListener || _off || noop + + function removeListener (type, listener) { + return fn.call(this, type, listener) === false + ? _removeListener.call(this, type, listener) + : this + } + + function off (type, listener) { + return fn.call(this, type, listener) === false + ? _off.call(this, type, listener) + : this + } +} + /** * Reusable no-op function. * @private From 93f7cb73e946219eef10f2c500d80f304ebb87f5 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sat, 3 May 2025 16:04:45 -0500 Subject: [PATCH 4/6] group test Signed-off-by: Sebastian Beltran --- test/compression.js | 324 ++++++++++++++++++++++---------------------- 1 file changed, 163 insertions(+), 161 deletions(-) diff --git a/test/compression.js b/test/compression.js index c47cf5d3..4df2fb7b 100644 --- a/test/compression.js +++ b/test/compression.js @@ -306,190 +306,192 @@ describe('compression()', function () { .expect(200, done) }) - it('should support removeListener("drain") after on("drain"); stream present', function (done) { - // compression doesn't proxy listenerCount() to the compression stream, so - // instead watch for a MaxListenersExceededWarning - var hasWarned = false - var onWarning = function () { - hasWarned = true - } - process.on('warning', onWarning) - var server = createServer({ threshold: 0 }, function (req, res) { - res.setHeader('Content-Type', 'text/plain') - var len = bytes('40kb') - var buf = Buffer.alloc(len, '.') - res.write(buf) - for (var times = 0; times < res.getMaxListeners() + 1; times++) { - var listener = function () {} - res.on('drain', listener) - res.removeListener('drain', listener) + describe('listeners', function () { + it('should support removeListener("drain") after on("drain"); stream present', function (done) { + // compression doesn't proxy listenerCount() to the compression stream, so + // instead watch for a MaxListenersExceededWarning + var hasWarned = false + var onWarning = function () { + hasWarned = true } - res.end() - }) - - request(server) - .get('/') - .set('Accept-Encoding', 'gzip') - .expect(function () { - process.removeListener('warning', onWarning) - assert.ok(!hasWarned) + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + var len = bytes('40kb') + var buf = Buffer.alloc(len, '.') + res.write(buf) + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.on('drain', listener) + res.removeListener('drain', listener) + } + res.end() }) - .expect(200, done) - }) - it('should support removeListener("drain") after addListener("drain")', function (done) { - var hasWarned = false - var onWarning = function () { - hasWarned = true - } - process.on('warning', onWarning) - var server = createServer({ threshold: 0 }, function (req, res) { - res.setHeader('Content-Type', 'text/plain') - var len = bytes('40kb') - var buf = Buffer.alloc(len, '.') - res.write(buf) - for (var times = 0; times < res.getMaxListeners() + 1; times++) { - var listener = function () {} - res.addListener('drain', listener) - res.removeListener('drain', listener) - } - res.end() + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) }) - request(server) - .get('/') - .set('Accept-Encoding', 'gzip') - .expect(function () { - process.removeListener('warning', onWarning) - assert.ok(!hasWarned) + it('should support removeListener("drain") after addListener("drain")', function (done) { + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + var len = bytes('40kb') + var buf = Buffer.alloc(len, '.') + res.write(buf) + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.addListener('drain', listener) + res.removeListener('drain', listener) + } + res.end() }) - .expect(200, done) - }) - it('should support off("drain") after addListener("drain")', function (done) { - if (!require('events').EventEmitter.prototype.off) { // off was added in Node.js v10 - this.skip() - } - var hasWarned = false - var onWarning = function () { - hasWarned = true - } - process.on('warning', onWarning) - var server = createServer({ threshold: 0 }, function (req, res) { - res.setHeader('Content-Type', 'text/plain') - var len = bytes('40kb') - var buf = Buffer.alloc(len, '.') - res.write(buf) - for (var times = 0; times < res.getMaxListeners() + 1; times++) { - var listener = function () {} - res.addListener('drain', listener) - res.off('drain', listener) - } - res.end() + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) }) - request(server) - .get('/') - .set('Accept-Encoding', 'gzip') - .expect(function () { - process.removeListener('warning', onWarning) - assert.ok(!hasWarned) + it('should support off("drain") after addListener("drain")', function (done) { + if (!require('events').EventEmitter.prototype.off) { // off was added in Node.js v10 + this.skip() + } + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + var len = bytes('40kb') + var buf = Buffer.alloc(len, '.') + res.write(buf) + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.addListener('drain', listener) + res.off('drain', listener) + } + res.end() }) - .expect(200, done) - }) - it('should support removeListener("drain"); buffered', function (done) { - // Variant of above tests for scenario when the listener is buffered (stream - // is not yet present). - var hasWarned = false - var onWarning = function () { - hasWarned = true - } - process.on('warning', onWarning) - var server = createServer({ threshold: 0 }, function (req, res) { - res.setHeader('Content-Type', 'text/plain') - res.on('end', function () {}) - for (var times = 0; times < res.getMaxListeners() + 1; times++) { - var listener = function () {} - res.on('drain', listener) - res.removeListener('drain', listener) - } - res.end() + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) }) - request(server) - .get('/') - .set('Accept-Encoding', 'gzip') - .expect(function () { - process.removeListener('warning', onWarning) - assert.ok(!hasWarned) + it('should support removeListener("drain"); buffered', function (done) { + // Variant of above tests for scenario when the listener is buffered (stream + // is not yet present). + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + res.on('end', function () {}) + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.on('drain', listener) + res.removeListener('drain', listener) + } + res.end() }) - .expect(200, done) - }) - it('should support removeListener("drain"); multiple bindings of same listener, buffered', function (done) { - // Variant of above test for scenario when the listener is buffered (stream - // is not yet present) and the same listener is added two or more times. - var hasWarned = false - var onWarning = function () { - hasWarned = true - } - process.on('warning', onWarning) - var server = createServer({ threshold: 0 }, function (req, res) { - res.setHeader('Content-Type', 'text/plain') - for (var times = 0; times < res.getMaxListeners() + 1; times++) { - var listener = function () {} - res.on('drain', listener) - res.on('drain', listener) - res.removeListener('drain', listener) - } - res.end() + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) }) - request(server) - .get('/') - .set('Accept-Encoding', 'gzip') - .expect(function () { - process.removeListener('warning', onWarning) - assert.ok(!hasWarned) + it('should support removeListener("drain"); multiple bindings of same listener, buffered', function (done) { + // Variant of above test for scenario when the listener is buffered (stream + // is not yet present) and the same listener is added two or more times. + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + process.on('warning', onWarning) + var server = createServer({ threshold: 0 }, function (req, res) { + res.setHeader('Content-Type', 'text/plain') + for (var times = 0; times < res.getMaxListeners() + 1; times++) { + var listener = function () {} + res.on('drain', listener) + res.on('drain', listener) + res.removeListener('drain', listener) + } + res.end() }) - .expect(200, done) - }) - it('should not leak event listeners when res.unpipe() is used (#135)', function (done) { - // unpipe and stream.Readable were added in v0.9.4 - var stream = require('stream') - if (!(stream.Readable && stream.Readable.prototype.unpipe)) { - this.skip() - } - - var hasWarned = false - var onWarning = function () { - hasWarned = true - } - var server = createServer({ threshold: 0 }, function (req, res) { - var times = 0 - var int = setInterval(function () { - var rs = require('fs').createReadStream('does not exist') - rs.on('error', function (e) { - rs.unpipe(res) + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) }) - rs.pipe(res) - if (times++ > res.getMaxListeners()) { - clearInterval(int) - res.end('hello, world') - } - }) + .expect(200, done) }) - request(server) - .get('/') - .set('Accept-Encoding', 'gzip') - .expect(function () { - process.removeListener('warning', onWarning) - assert.ok(!hasWarned) + it('should not leak event listeners when res.unpipe() is used (#135)', function (done) { + // unpipe and stream.Readable were added in v0.9.4 + var stream = require('stream') + if (!(stream.Readable && stream.Readable.prototype.unpipe)) { + this.skip() + } + + var hasWarned = false + var onWarning = function () { + hasWarned = true + } + var server = createServer({ threshold: 0 }, function (req, res) { + var times = 0 + var int = setInterval(function () { + var rs = require('fs').createReadStream('does not exist') + rs.on('error', function (e) { + rs.unpipe(res) + }) + rs.pipe(res) + if (times++ > res.getMaxListeners()) { + clearInterval(int) + res.end('hello, world') + } + }) }) - .expect(200, done) + + request(server) + .get('/') + .set('Accept-Encoding', 'gzip') + .expect(function () { + process.removeListener('warning', onWarning) + assert.ok(!hasWarned) + }) + .expect(200, done) + }) }) describe('http2', function () { From a68b46084204154c83a6b4d37fdbbf2dfa51bcc0 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sat, 3 May 2025 16:56:54 -0500 Subject: [PATCH 5/6] refactor: simplify event listener methods in intercept functions Signed-off-by: Sebastian Beltran --- index.js | 64 ++++++++++++++------------------------------- test/compression.js | 16 ------------ 2 files changed, 20 insertions(+), 60 deletions(-) diff --git a/index.js b/index.js index 5df2d42c..fabb18f5 100644 --- a/index.js +++ b/index.js @@ -299,34 +299,22 @@ function interceptAddListener (ee, fn) { var _on = ee.on if (_addListener) { - Object.defineProperty(ee, 'addListener', { - configurable: true, - value: addListener, - writable: true - }) + ee.addListener = function addListener (type, listener) { + return fn.call(this, type, listener) === false + ? _addListener.call(this, type, listener) + : this + } } if (_on) { - Object.defineProperty(ee, 'on', { - configurable: true, - value: on, - writable: true - }) + ee.on = function on (type, listener) { + return fn.call(this, type, listener) === false + ? _on.call(this, type, listener) + : this + } } return _addListener || _on || noop - - function addListener (type, listener) { - return fn.call(this, type, listener) === false - ? _addListener.call(this, type, listener) - : this - } - - function on (type, listener) { - return fn.call(this, type, listener) === false - ? _on.call(this, type, listener) - : this - } } /** @@ -339,34 +327,22 @@ function interceptRemoveListener (ee, fn) { var _off = ee.off if (_removeListener) { - Object.defineProperty(ee, 'removeListener', { - configurable: true, - value: removeListener, - writable: true - }) + ee.removeListener = function removeListener (type, listener) { + return fn.call(this, type, listener) === false + ? _removeListener.call(this, type, listener) + : this + } } if (_off) { - Object.defineProperty(ee, 'off', { - configurable: true, - value: off, - writable: true - }) + ee.off = function off (type, listener) { + return fn.call(this, type, listener) === false + ? _off.call(this, type, listener) + : this + } } return _removeListener || _off || noop - - function removeListener (type, listener) { - return fn.call(this, type, listener) === false - ? _removeListener.call(this, type, listener) - : this - } - - function off (type, listener) { - return fn.call(this, type, listener) === false - ? _off.call(this, type, listener) - : this - } } /** diff --git a/test/compression.js b/test/compression.js index 4df2fb7b..c9c8a190 100644 --- a/test/compression.js +++ b/test/compression.js @@ -368,9 +368,6 @@ describe('compression()', function () { }) it('should support off("drain") after addListener("drain")', function (done) { - if (!require('events').EventEmitter.prototype.off) { // off was added in Node.js v10 - this.skip() - } var hasWarned = false var onWarning = function () { hasWarned = true @@ -458,12 +455,6 @@ describe('compression()', function () { }) it('should not leak event listeners when res.unpipe() is used (#135)', function (done) { - // unpipe and stream.Readable were added in v0.9.4 - var stream = require('stream') - if (!(stream.Readable && stream.Readable.prototype.unpipe)) { - this.skip() - } - var hasWarned = false var onWarning = function () { hasWarned = true @@ -1457,13 +1448,6 @@ function createServer (opts, fn) { return } - if (typeof res.getMaxListeners !== 'function') { - // Added in v0.11.2 - res.getMaxListeners = function getMaxListeners () { - return 10 - } - } - fn(req, res) }) }) From b949affca51f60b69ccbffae7a6310cb62ecf524 Mon Sep 17 00:00:00 2001 From: Sebastian Beltran Date: Sat, 3 May 2025 17:15:58 -0500 Subject: [PATCH 6/6] refactor: update documentation for event listener interception Signed-off-by: Sebastian Beltran --- index.js | 2 +- test/compression.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index fabb18f5..87c31e24 100644 --- a/index.js +++ b/index.js @@ -318,7 +318,7 @@ function interceptAddListener (ee, fn) { } /** - * Intercept add listener on event emitter. + * Intercept remove listener on event emitter. * @private */ diff --git a/test/compression.js b/test/compression.js index c9c8a190..13074437 100644 --- a/test/compression.js +++ b/test/compression.js @@ -454,7 +454,8 @@ describe('compression()', function () { .expect(200, done) }) - it('should not leak event listeners when res.unpipe() is used (#135)', function (done) { + // https://github.com/expressjs/compression/issues/135 + it('should not leak event listeners when res.unpipe()', function (done) { var hasWarned = false var onWarning = function () { hasWarned = true