diff --git a/lib/internal/streams/end-of-stream.js b/lib/internal/streams/end-of-stream.js index 7e640a33823a98..8eee330beced3a 100644 --- a/lib/internal/streams/end-of-stream.js +++ b/lib/internal/streams/end-of-stream.js @@ -21,6 +21,16 @@ function isRequest(stream) { return stream.setHeader && typeof stream.abort === 'function'; } +function isServerResponse(stream) { + return ( + typeof stream._sent100 === 'boolean' && + typeof stream._removedConnection === 'boolean' && + typeof stream._removedContLen === 'boolean' && + typeof stream._removedTE === 'boolean' && + typeof stream._closed === 'boolean' + ); +} + function isReadable(stream) { return typeof stream.readable === 'boolean' || typeof stream.readableEnded === 'boolean' || @@ -80,7 +90,7 @@ function eos(stream, options, callback) { // TODO (ronag): Improve soft detection to include core modules and // common ecosystem modules that do properly emit 'close' but fail // this generic check. - let willEmitClose = ( + let willEmitClose = isServerResponse(stream) || ( state && state.autoDestroy && (state.emitClose || isSocket(stream)) && diff --git a/test/parallel/test-http-outgoing-finished.js b/test/parallel/test-http-outgoing-finished.js new file mode 100644 index 00000000000000..7da1b7429ae946 --- /dev/null +++ b/test/parallel/test-http-outgoing-finished.js @@ -0,0 +1,32 @@ +'use strict'; +const common = require('../common'); +const { finished } = require('stream'); + +const http = require('http'); +const assert = require('assert'); + +const server = http.createServer(function(req, res) { + let closed = false; + res + .on('close', common.mustCall(() => { + closed = true; + finished(res, common.mustCall(() => { + server.close(); + })); + })) + .end(); + finished(res, common.mustCall(() => { + assert.strictEqual(closed, true); + })); + +}).listen(0, function() { + http + .request({ + port: this.address().port, + method: 'GET' + }) + .on('response', function(res) { + res.resume(); + }) + .end(); +});