diff --git a/index.js b/index.js index c84bda1..196bf09 100644 --- a/index.js +++ b/index.js @@ -50,6 +50,7 @@ class ZlibBase extends Minipass { throw new TypeError('invalid options for ZlibBase constructor') super(opts) + this[_sawError] = false this[_ended] = false this[_opts] = opts @@ -64,7 +65,12 @@ class ZlibBase extends Minipass { } this[_onError] = (err) => { + // no sense raising multiple errors, since we abort on the first one. + if (this[_sawError]) + return + this[_sawError] = true + // there is no way to cleanly recover. // continuing only obscures problems. this.close() @@ -157,6 +163,8 @@ class ZlibBase extends Minipass { // `_processChunk()` adds an 'error' listener. If we don't remove it // after each call, these handlers start piling up. this[_handle].removeAllListeners('error') + // make sure OUR error listener is still attached tho + this[_handle].on('error', er => this[_onError](new ZlibError(er))) } } diff --git a/test/multiple-errors-handled.js b/test/multiple-errors-handled.js new file mode 100644 index 0000000..d41f1a8 --- /dev/null +++ b/test/multiple-errors-handled.js @@ -0,0 +1,54 @@ +const t = require('tap') +const { Gzip } = require('../') + +t.test('only raise once if emitted before writing', t => { + t.plan(1) + + const gz = new Gzip() + + // dirty hack to get at the internal handle + const kHandle = Object.getOwnPropertySymbols(gz) + .filter(sym => sym.toString() === 'Symbol(handle)')[0] + + gz.once('error', er => t.match(er, { message: 'zlib: fart' })) + const handle = gz[kHandle] + handle.emit('error', new Error('fart')) + handle.emit('error', new Error('poop')) +}) + +t.test('only raise once if emitted after writing', t => { + t.plan(1) + + const gz = new Gzip() + + // dirty hack to get at the internal handle + const kHandle = Object.getOwnPropertySymbols(gz) + .filter(sym => sym.toString() === 'Symbol(handle)')[0] + + gz.once('error', er => t.match(er, { message: 'zlib: fart' })) + + gz.write('hello, ') + + const handle = gz[kHandle] + handle.emit('error', new Error('fart')) + handle.emit('error', new Error('poop')) +}) + +t.test('only raise once if emitted after writing after emitting', t => { + t.plan(1) + + const gz = new Gzip() + + // dirty hack to get at the internal handle + const kHandle = Object.getOwnPropertySymbols(gz) + .filter(sym => sym.toString() === 'Symbol(handle)')[0] + + gz.once('error', er => t.match(er, { message: 'zlib: fart' })) + + gz.write('hello, ') + + const handle = gz[kHandle] + handle.emit('error', new Error('fart')) + gz.write(' world') + handle.emit('error', new Error('poop')) +})