diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 24aae1caca69d3..cf208b9177e2d7 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -493,6 +493,12 @@ function _storeHeader(firstLine, headers) { if (!this._hasBody) { // Make sure we don't end the 0\r\n\r\n at the end of the message. this.chunkedEncoding = false; + // For HEAD responses, include Content-Length if known so that + // the client can determine message boundaries for keep-alive. + if (!this._removedContLen && + typeof this._contentLength === 'number') { + header += 'Content-Length: ' + this._contentLength + '\r\n'; + } } else if (!this.useChunkedEncodingByDefault) { this._last = true; } else if (!state.trailer && diff --git a/test/parallel/test-http-head-response-content-length-keep-alive.js b/test/parallel/test-http-head-response-content-length-keep-alive.js new file mode 100644 index 00000000000000..7a81190221d817 --- /dev/null +++ b/test/parallel/test-http-head-response-content-length-keep-alive.js @@ -0,0 +1,35 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +// This test ensures that HEAD responses include a Content-Length header +// when the server calls res.end() without explicit headers, so that +// HTTP keep-alive works correctly for HEAD requests. +// Ref: https://github.com/nodejs/node/issues/28438 + +const server = http.createServer(common.mustCall(function(req, res) { + res.end(); +}, 2)); + +server.listen(0, common.mustCall(function() { + const port = this.address().port; + const agent = new http.Agent({ keepAlive: true }); + + // First: verify GET response includes Content-Length + const getReq = http.request({ port, method: 'GET', agent }, common.mustCall(function(res) { + assert.strictEqual(res.headers['content-length'], '0'); + + // Second: verify HEAD response also includes Content-Length + const headReq = http.request({ port, method: 'HEAD', agent }, common.mustCall(function(res) { + assert.strictEqual(res.headers['content-length'], '0', + 'HEAD response should include Content-Length for keep-alive'); + agent.destroy(); + server.close(); + })); + headReq.end(); + + res.resume(); + })); + getReq.end(); +}));