From 6339876a003cad645f357a93d29720b6c75b8ea3 Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Thu, 14 May 2020 11:21:13 +0200 Subject: [PATCH 1/2] Proxy events --- index.js | 20 +++++++++++++++++ readme.md | 28 ------------------------ test.js | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 30 deletions(-) diff --git a/index.js b/index.js index 4d9b468..255ebbf 100644 --- a/index.js +++ b/index.js @@ -22,6 +22,10 @@ const knownProperties = [ ]; module.exports = (fromStream, toStream) => { + if (toStream._readableState.autoDestroy) { + throw new Error('The second stream must have the `autoDestroy` option set to `false`'); + } + const fromProperties = new Set(Object.keys(fromStream).concat(knownProperties)); const properties = {}; @@ -50,8 +54,24 @@ module.exports = (fromStream, toStream) => { Object.defineProperties(toStream, properties); fromStream.once('aborted', () => { + toStream.destroy(); + toStream.emit('aborted'); }); + fromStream.once('close', () => { + if (fromStream.complete) { + if (toStream.readableEnded) { + toStream.emit('close'); + } else { + toStream.once('end', () => { + toStream.emit('close'); + }); + } + } else { + toStream.emit('close'); + } + }); + return toStream; }; diff --git a/readme.md b/readme.md index d09f350..e968620 100644 --- a/readme.md +++ b/readme.md @@ -48,34 +48,6 @@ myStream.destroy(); Please note that `myStream` and `responseStream` never throws. The error is passed to the request instead. -**Note #2:** The `aborted` and `close` events are not proxied. You have to add them manually: - -```js -const stream = require('stream'); -const mimicResponse = require('mimic-response'); - -const responseStream = getHttpResponseStream(); -const myStream = new stream.PassThrough({ - destroy(error, callback) { - responseStream.destroy(); - - callback(error); - } -}); - -responseStream.once('aborted', () => { - myStream.destroy(); - - myStream.emit('aborted'); -}); - -responseStream.once('closed', () => { - myStream.emit('closed'); -}); - -responseStream.pipe(myStream); -``` - #### from Type: `Stream` diff --git a/test.js b/test.js index e074821..4360730 100644 --- a/test.js +++ b/test.js @@ -18,6 +18,14 @@ test.before(async () => { response.end('sdf'); }, 2); }); + + server.get('/aborted', (_request, response) => { + response.write('a'); + + setTimeout(() => { + response.socket.destroy(); + }, 2); + }); }); test('normal', async t => { @@ -27,7 +35,7 @@ test('normal', async t => { return this; }; - const toStream = new stream.PassThrough(); + const toStream = new stream.PassThrough({autoDestroy: false}); mimicResponse(response, toStream); t.is(toStream.statusCode, 200); @@ -53,7 +61,7 @@ test('do not overwrite prototype properties', async t => { return origOn.call(this, name, handler); }; - const toStream = new stream.PassThrough(); + const toStream = new stream.PassThrough({autoDestroy: false}); mimicResponse(response, toStream); t.false(Object.keys(toStream).includes('on')); @@ -67,3 +75,56 @@ test('do not overwrite prototype properties', async t => { t.true(toStream.complete); }); + +test('`aborted` event', async t => { + const response = await pify(http.get, {errorFirst: false})(`${server.url}/aborted`); + + const toStream = new stream.PassThrough({autoDestroy: false}); + mimicResponse(response, toStream); + + await pEvent(toStream, 'aborted'); + + t.true(toStream.destroyed); +}); + +test('autoDestroy must be false', async t => { + const response = await pify(http.get, {errorFirst: false})(`${server.url}/aborted`); + + const toStream = new stream.PassThrough({autoDestroy: true}); + + t.throws(() => mimicResponse(response, toStream), { + message: 'The second stream must have the `autoDestroy` option set to `false`' + }); +}); + +test('`close` event', async t => { + { + const response = await pify(http.get, {errorFirst: false})(server.url); + + const toStream = new stream.PassThrough({autoDestroy: false}); + mimicResponse(response, toStream); + + response.pipe(toStream); + toStream.resume(); + + await pEvent(toStream, 'close'); + + t.true(response.readableEnded); + t.true(toStream.readableEnded); + } + + { + const response = await pify(http.get, {errorFirst: false})(`${server.url}/aborted`); + + const toStream = new stream.PassThrough({autoDestroy: false}); + mimicResponse(response, toStream); + + response.pipe(toStream); + toStream.resume(); + + await pEvent(toStream, 'close'); + + t.false(response.readableEnded); + t.false(toStream.readableEnded); + } +}); From 96e7f0efc6906e05a1786389e29856939df7805c Mon Sep 17 00:00:00 2001 From: Szymon Marczak <36894700+szmarczak@users.noreply.github.com> Date: Thu, 14 May 2020 13:10:41 +0200 Subject: [PATCH 2/2] Fixes --- index.js | 6 +++--- test.js | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/index.js b/index.js index 255ebbf..404e111 100644 --- a/index.js +++ b/index.js @@ -61,12 +61,12 @@ module.exports = (fromStream, toStream) => { fromStream.once('close', () => { if (fromStream.complete) { - if (toStream.readableEnded) { - toStream.emit('close'); - } else { + if (toStream.readable) { toStream.once('end', () => { toStream.emit('close'); }); + } else { + toStream.emit('close'); } } else { toStream.emit('close'); diff --git a/test.js b/test.js index 4360730..6058bfd 100644 --- a/test.js +++ b/test.js @@ -6,6 +6,7 @@ import pify from 'pify'; import pEvent from 'p-event'; import mimicResponse from '.'; +const nodejsMajorVersion = process.versions.node.split('.')[0]; let server; test.before(async () => { @@ -41,7 +42,6 @@ test('normal', async t => { t.is(toStream.statusCode, 200); t.is(toStream.unicorn, '🦄'); t.is(toStream.getContext(), response.getContext()); - t.false(toStream.complete); response.resume(); await pEvent(response, 'end'); @@ -73,6 +73,8 @@ test('do not overwrite prototype properties', async t => { response.resume(); await pEvent(response, 'end'); + await new Promise(resolve => setImmediate(resolve)); + t.true(toStream.complete); }); @@ -104,13 +106,24 @@ test('`close` event', async t => { const toStream = new stream.PassThrough({autoDestroy: false}); mimicResponse(response, toStream); + t.true(response.readable); + + if (nodejsMajorVersion > 11) { + t.false(response.readableEnded); + } + response.pipe(toStream); toStream.resume(); await pEvent(toStream, 'close'); - t.true(response.readableEnded); - t.true(toStream.readableEnded); + t.false(response.readable); + t.false(toStream.readable); + + if (nodejsMajorVersion > 11) { + t.true(response.readableEnded); + t.true(toStream.readableEnded); + } } { @@ -119,12 +132,26 @@ test('`close` event', async t => { const toStream = new stream.PassThrough({autoDestroy: false}); mimicResponse(response, toStream); + t.true(response.readable); + + if (nodejsMajorVersion > 11) { + t.false(response.readableEnded); + } + response.pipe(toStream); toStream.resume(); await pEvent(toStream, 'close'); - t.false(response.readableEnded); - t.false(toStream.readableEnded); + if (nodejsMajorVersion < 12) { + t.false(response.readable); + t.true(toStream.readable); + } else if (nodejsMajorVersion < 13) { + t.true(response.readableEnded); + t.false(toStream.readableEnded); + } else { + t.false(response.readableEnded); + t.false(toStream.readableEnded); + } } });