diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index dade9a11014c01..bd0ed8ec8bd105 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -69,6 +69,7 @@ const HIGH_WATER_MARK = getDefaultHighWaterMark(); const { CRLF, debug } = common; const kCorked = Symbol('corked'); +const kWritable = Symbol('writable'); function nop() {} @@ -97,7 +98,6 @@ function OutgoingMessage() { // TCP socket and HTTP Parser and thus handle the backpressure. this.outputSize = 0; - this.writable = true; this.destroyed = false; this._last = false; @@ -127,6 +127,18 @@ function OutgoingMessage() { ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype); ObjectSetPrototypeOf(OutgoingMessage, Stream); +ObjectDefineProperty(OutgoingMessage.prototype, 'writable', { + get() { + // TODO (ronag): Add errored state? write/end might error/destroy one + // tick later. + return this[kWritable] !== false && !this.destroyed && !this.finished; + }, + set(val) { + // Backwards compatible. + this[kWritable] = !!val; + } +}); + ObjectDefineProperty(OutgoingMessage.prototype, 'writableFinished', { get() { return ( diff --git a/test/parallel/test-http-outgoing-destroy.js b/test/parallel/test-http-outgoing-destroy.js index 91c68aa9af3db0..a041a992545cc2 100644 --- a/test/parallel/test-http-outgoing-destroy.js +++ b/test/parallel/test-http-outgoing-destroy.js @@ -8,8 +8,10 @@ const OutgoingMessage = http.OutgoingMessage; { const msg = new OutgoingMessage(); assert.strictEqual(msg.destroyed, false); + assert.strictEqual(msg.writable, true); msg.destroy(); assert.strictEqual(msg.destroyed, true); + assert.strictEqual(msg.writable, false); let callbackCalled = false; msg.write('asd', common.mustCall((err) => { assert.strictEqual(err.code, 'ERR_STREAM_DESTROYED'); diff --git a/test/parallel/test-http-outgoing-finish-writable.js b/test/parallel/test-http-outgoing-finish-writable.js index e3c870164bac58..fd7bd98a724c63 100644 --- a/test/parallel/test-http-outgoing-finish-writable.js +++ b/test/parallel/test-http-outgoing-finish-writable.js @@ -3,9 +3,6 @@ const common = require('../common'); 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 - const server = http.createServer(common.mustCall(function(req, res) { assert.strictEqual(res.writable, true); assert.strictEqual(res.finished, false); @@ -14,7 +11,7 @@ const server = http.createServer(common.mustCall(function(req, res) { // 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); assert.strictEqual(res.writableEnded, true); @@ -32,9 +29,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-outgoing-finish.js b/test/parallel/test-http-outgoing-finish.js index 7464dd57ea1f31..d31c527580609a 100644 --- a/test/parallel/test-http-outgoing-finish.js +++ b/test/parallel/test-http-outgoing-finish.js @@ -73,4 +73,5 @@ function write(out) { console.log(`ok - ${name} endCb`); }); })); + assert.strictEqual(out.writable, false); } diff --git a/test/parallel/test-http-outgoing-writableFinished.js b/test/parallel/test-http-outgoing-writableFinished.js index 6f84d91e714790..8062b6e84054e1 100644 --- a/test/parallel/test-http-outgoing-writableFinished.js +++ b/test/parallel/test-http-outgoing-writableFinished.js @@ -22,11 +22,14 @@ server.on('listening', common.mustCall(function() { path: '/' }); + assert.strictEqual(clientRequest.writable, true); assert.strictEqual(clientRequest.writableFinished, false); clientRequest .on('finish', common.mustCall(() => { + assert.strictEqual(clientRequest.writable, false); assert.strictEqual(clientRequest.writableFinished, true); })) .end(); + assert.strictEqual(clientRequest.writable, false); assert.strictEqual(clientRequest.writableFinished, false); })); diff --git a/test/parallel/test-http-writable-true-after-close.js b/test/parallel/test-http-writable-true-after-close.js index c0db7c34492762..f515a2ec05e214 100644 --- a/test/parallel/test-http-writable-true-after-close.js +++ b/test/parallel/test-http-writable-true-after-close.js @@ -4,16 +4,13 @@ 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); + assert.strictEqual(res.writable, false); }); // on CentOS 5, 'finish' is emitted