From b9cf71959321927833eb0ae74c4ba0f94872a313 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Fri, 30 Aug 2019 12:13:58 +0200 Subject: [PATCH 1/4] stream: don't deadlock on aborted stream Not all streams (e.g. http.ClientRequest) will always emit 'close' after 'aborted'. --- lib/internal/streams/end-of-stream.js | 5 ++++ test/parallel/test-http-client-finished.js | 27 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 test/parallel/test-http-client-finished.js diff --git a/lib/internal/streams/end-of-stream.js b/lib/internal/streams/end-of-stream.js index 850e5d3796c448..09b23ddfaaaefc 100644 --- a/lib/internal/streams/end-of-stream.js +++ b/lib/internal/streams/end-of-stream.js @@ -82,12 +82,17 @@ function eos(stream, opts, callback) { stream.on('close', onlegacyfinish); } + if (typeof stream.aborted === 'boolean') { + stream.on('aborted', onclose); + } + stream.on('end', onend); stream.on('finish', onfinish); if (opts.error !== false) stream.on('error', onerror); stream.on('close', onclose); return function() { + stream.removeListener('aborted', onclose); stream.removeListener('complete', onfinish); stream.removeListener('abort', onclose); stream.removeListener('request', onrequest); diff --git a/test/parallel/test-http-client-finished.js b/test/parallel/test-http-client-finished.js new file mode 100644 index 00000000000000..24f686ad5b50ea --- /dev/null +++ b/test/parallel/test-http-client-finished.js @@ -0,0 +1,27 @@ +'use strict'; +const common = require('../common'); +const http = require('http'); +const { finished } = require('stream') + +{ + // abort before finished + + const server = http.createServer(function(req, res) { + res.write('asd') + }); + + server.listen(0, common.mustCall(function() { + const req = http.request({ + port: this.address().port + }) + .on('response', res => { + res.on('readable', () => ( + res.destroy() + )); + finished(res, common.mustCall(() => { + server.close(); + })); + }) + .end(); + })); +} From 6a3ebddf9dd6a2750cb1e7ed485bba858a49807d Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Fri, 30 Aug 2019 12:16:35 +0200 Subject: [PATCH 2/4] fixup: comments --- lib/internal/streams/end-of-stream.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/streams/end-of-stream.js b/lib/internal/streams/end-of-stream.js index 09b23ddfaaaefc..3f1c0f316cd3c6 100644 --- a/lib/internal/streams/end-of-stream.js +++ b/lib/internal/streams/end-of-stream.js @@ -82,6 +82,7 @@ function eos(stream, opts, callback) { stream.on('close', onlegacyfinish); } + // Not all streams will emit 'close' after 'aborted'. if (typeof stream.aborted === 'boolean') { stream.on('aborted', onclose); } From 0bd77cdf45661c12089e95e0abd405a63b530822 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sat, 31 Aug 2019 15:20:37 +0200 Subject: [PATCH 3/4] fixup: linting --- test/parallel/test-http-client-finished.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/parallel/test-http-client-finished.js b/test/parallel/test-http-client-finished.js index 24f686ad5b50ea..ba8d5102d99602 100644 --- a/test/parallel/test-http-client-finished.js +++ b/test/parallel/test-http-client-finished.js @@ -4,20 +4,20 @@ const http = require('http'); const { finished } = require('stream') { - // abort before finished + // Test abort before finished. const server = http.createServer(function(req, res) { - res.write('asd') + res.write('asd'); }); server.listen(0, common.mustCall(function() { - const req = http.request({ + http.request({ port: this.address().port }) .on('response', res => { - res.on('readable', () => ( - res.destroy() - )); + res.on('readable', () => { + res.destroy(); + }); finished(res, common.mustCall(() => { server.close(); })); From 523eb04179c9db0802ba6d98377df30da3db2a10 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Sun, 1 Sep 2019 15:49:09 +0200 Subject: [PATCH 4/4] fixup: linting --- test/parallel/test-http-client-finished.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-http-client-finished.js b/test/parallel/test-http-client-finished.js index ba8d5102d99602..2d7e5b95b3ca33 100644 --- a/test/parallel/test-http-client-finished.js +++ b/test/parallel/test-http-client-finished.js @@ -1,7 +1,7 @@ 'use strict'; const common = require('../common'); const http = require('http'); -const { finished } = require('stream') +const { finished } = require('stream'); { // Test abort before finished. @@ -14,7 +14,7 @@ const { finished } = require('stream') http.request({ port: this.address().port }) - .on('response', res => { + .on('response', (res) => { res.on('readable', () => { res.destroy(); });