diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index a4a2b3ab144400..70a4bc60fa3eea 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -109,6 +109,26 @@ function OutgoingMessage() { Object.setPrototypeOf(OutgoingMessage.prototype, Stream.prototype); Object.setPrototypeOf(OutgoingMessage, Stream); +Object.defineProperty(OutgoingMessage.prototype, '_writableState', { + get: function() { + if (!this._writableStateProxy) { + const msg = this; + this._writableStateProxy = { + get finished() { + return ( + msg.finished && + msg.outputSize === 0 && + (!msg.socket || msg.socket.writableLength === 0) + ); + }, + get ended() { + return msg.finished; + } + }; + } + return this._writableStateProxy; + } +}); Object.defineProperty(OutgoingMessage.prototype, '_headers', { get: internalUtil.deprecate(function() { @@ -699,6 +719,7 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) { this.connection.uncork(); this.finished = true; + this.writable = false; // There is the first message on the outgoing queue, and we've sent // everything to the socket. diff --git a/test/parallel/test-http-outgoing-finish-writable.js b/test/parallel/test-http-outgoing-finish-writable.js index e03901fb6ddf07..f57474d63d735e 100644 --- a/test/parallel/test-http-outgoing-finish-writable.js +++ b/test/parallel/test-http-outgoing-finish-writable.js @@ -4,16 +4,14 @@ const assert = require('assert'); const http = require('http'); // Verify that after calling end() on an `OutgoingMessage` (or a type that -// inherits from `OutgoingMessage`), its `writable` property is not set to false +// inherits from `OutgoingMessage`), its `writable` property is set to false const server = http.createServer(common.mustCall(function(req, res) { assert.strictEqual(res.writable, true); assert.strictEqual(res.finished, false); res.end(); - // res.writable is set to false after it has finished sending - // Ref: https://github.com/nodejs/node/issues/15029 - assert.strictEqual(res.writable, true); + assert.strictEqual(res.writable, false); assert.strictEqual(res.finished, true); server.close(); @@ -30,9 +28,5 @@ server.on('listening', common.mustCall(function() { assert.strictEqual(clientRequest.writable, true); clientRequest.end(); - - // Writable is still true when close - // THIS IS LEGACY, we cannot change it - // unless we break error detection - assert.strictEqual(clientRequest.writable, true); + assert.strictEqual(clientRequest.writable, false); })); diff --git a/test/parallel/test-http-writable-true-after-close.js b/test/parallel/test-http-writable-true-after-close.js deleted file mode 100644 index c0db7c34492762..00000000000000 --- a/test/parallel/test-http-writable-true-after-close.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -const common = require('../common'); -const assert = require('assert'); -const { get, createServer } = require('http'); - -// res.writable should not be set to false after it has finished sending -// Ref: https://github.com/nodejs/node/issues/15029 - -let internal; -let external; - -// Proxy server -const server = createServer(common.mustCall((req, res) => { - const listener = common.mustCall(() => { - assert.strictEqual(res.writable, true); - }); - - // on CentOS 5, 'finish' is emitted - res.on('finish', listener); - // Everywhere else, 'close' is emitted - res.on('close', listener); - - get(`http://127.0.0.1:${internal.address().port}`, common.mustCall((inner) => { - inner.pipe(res); - })); -})).listen(0, () => { - // Http server - internal = createServer((req, res) => { - res.writeHead(200); - setImmediate(common.mustCall(() => { - external.abort(); - res.end('Hello World\n'); - })); - }).listen(0, () => { - external = get(`http://127.0.0.1:${server.address().port}`); - external.on('error', common.mustCall(() => { - server.close(); - internal.close(); - })); - }); -}); diff --git a/test/parallel/test-stream-pipeline-http.js b/test/parallel/test-stream-pipeline-http.js new file mode 100644 index 00000000000000..6019ff99a14037 --- /dev/null +++ b/test/parallel/test-stream-pipeline-http.js @@ -0,0 +1,29 @@ +'use strict'; + +const common = require('../common'); +const { get, createServer } = require('http'); +const { pipeline } = require('stream'); +const assert = require('assert'); + +let innerRequest; + +// Http server +createServer(common.mustCall((req, res) => { + res.writeHead(200); + setTimeout(() => { + innerRequest.abort(); + res.end('Hello World\n'); + }, 1000); +})).listen(3000); + +// Proxy server +createServer(common.mustCall((req, res) => { + get('http://127.0.0.1:3000', (inner) => { + pipeline(inner, res, (err) => { + assert(err); + }); + }); +})) +.listen(3001, common.mustCall(() => { + innerRequest = get('http://127.0.0.1:3001'); +}));