diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 388204fbf2ceb4..cb09e764fefdfb 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -260,18 +260,6 @@ function _writeRaw(data, encoding, callback) { // There might be pending data in the this.output buffer. if (this.outputData.length) { this._flushOutput(conn); - } else if (!data.length) { - if (typeof callback === 'function') { - // If the socket was set directly it won't be correctly initialized - // with an async_id_symbol. - // TODO(AndreasMadsen): @trevnorris suggested some more correct - // solutions in: - // https://github.com/nodejs/node/pull/14389/files#r128522202 - defaultTriggerAsyncIdScope(conn[async_id_symbol], - process.nextTick, - callback); - } - return true; } // Directly write to socket. return conn.write(data, encoding, callback); @@ -593,14 +581,6 @@ function write_(msg, chunk, encoding, callback, fromEnd) { ['string', 'Buffer'], chunk); } - - // If we get an empty string or buffer, then just do nothing, and - // signal the user to keep writing. - if (chunk.length === 0) { - debug('received empty string or buffer and waiting for more input'); - return true; - } - if (!fromEnd && msg.connection && !msg[kIsCorked]) { msg.connection.cork(); msg[kIsCorked] = true; @@ -608,7 +588,7 @@ function write_(msg, chunk, encoding, callback, fromEnd) { } var len, ret; - if (msg.chunkedEncoding) { + if (msg.chunkedEncoding && chunk.length !== 0) { if (typeof chunk === 'string') len = Buffer.byteLength(chunk, encoding); else diff --git a/test/parallel/test-http-outgoing-message-inheritance.js b/test/parallel/test-http-outgoing-message-inheritance.js index 9beb4aeff17fab..335a9a28956108 100644 --- a/test/parallel/test-http-outgoing-message-inheritance.js +++ b/test/parallel/test-http-outgoing-message-inheritance.js @@ -10,19 +10,23 @@ const assert = require('assert'); // Fixes: https://github.com/nodejs/node/issues/14381 class Response extends OutgoingMessage { - constructor() { - super({ method: 'GET', httpVersionMajor: 1, httpVersionMinor: 1 }); - } - _implicitHeader() {} } const res = new Response(); + +let firstChunk = true; + const ws = new Writable({ write: common.mustCall((chunk, encoding, callback) => { - assert(chunk.toString().match(/hello world/)); + if (firstChunk) { + assert(chunk.toString().endsWith('hello world')); + firstChunk = false; + } else { + assert.strictEqual(chunk.length, 0); + } setImmediate(callback); - }) + }, 2) }); res.socket = ws; diff --git a/test/parallel/test-http-outgoing-message-write-callback.js b/test/parallel/test-http-outgoing-message-write-callback.js new file mode 100644 index 00000000000000..a51d37351d4c9e --- /dev/null +++ b/test/parallel/test-http-outgoing-message-write-callback.js @@ -0,0 +1,37 @@ +'use strict'; + +const common = require('../common'); + +// This test ensures that the callback of `OutgoingMessage.prototype.write()` is +// called also when writing empty chunks. + +const assert = require('assert'); +const http = require('http'); +const stream = require('stream'); + +const expected = ['a', 'b', '', Buffer.alloc(0), 'c']; +const results = []; + +const writable = new stream.Writable({ + write(chunk, encoding, callback) { + setImmediate(callback); + } +}); + +const res = new http.ServerResponse({ + method: 'GET', + httpVersionMajor: 1, + httpVersionMinor: 1 +}); + +res.assignSocket(writable); + +for (const chunk of expected) { + res.write(chunk, () => { + results.push(chunk); + }); +} + +res.end(common.mustCall(() => { + assert.deepStrictEqual(results, expected); +})); diff --git a/test/parallel/test-http-server-response-standalone.js b/test/parallel/test-http-server-response-standalone.js index a50974d2d31566..3c91dd0889b066 100644 --- a/test/parallel/test-http-server-response-standalone.js +++ b/test/parallel/test-http-server-response-standalone.js @@ -15,11 +15,18 @@ const res = new ServerResponse({ httpVersionMinor: 1 }); +let firstChunk = true; + const ws = new Writable({ write: common.mustCall((chunk, encoding, callback) => { - assert(chunk.toString().match(/hello world/)); + if (firstChunk) { + assert(chunk.toString().endsWith('hello world')); + firstChunk = false; + } else { + assert.strictEqual(chunk.length, 0); + } setImmediate(callback); - }) + }, 2) }); res.assignSocket(ws);