From 1fddc1fee84785d296e37337dcb0dc12c13a049f Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 13 Sep 2014 13:08:25 +0100 Subject: [PATCH] http: do not send `0\r\n\r\n` in TE HEAD responses When replying to a HEAD request, do not attempt to send the trailers and EOF sequence (`0\r\n\r\n`). The HEAD request MUST not have body. Quote from RFC: The presence of a message body in a response depends on both the request method to which it is responding and the response status code (Section 3.1.2). Responses to the HEAD request method (Section 4.3.2 of [RFC7231]) never include a message body because the associated response header fields (e.g., Transfer-Encoding, Content-Length, etc.), if present, indicate only what their values would have been if the request method had been GET (Section 4.3.1 of [RFC7231]). fix #8361 Reviewed-By: Timothy J Fontaine --- lib/http.js | 6 ++- test/simple/test-http-head-request.js | 58 ++++++++++++++++----------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/lib/http.js b/lib/http.js index 0623668c9deeb3..f87df173b31dc1 100644 --- a/lib/http.js +++ b/lib/http.js @@ -945,6 +945,10 @@ OutgoingMessage.prototype.end = function(data, encoding) { if (encoding === 'hex' || encoding === 'base64') hot = false; + // Transfer-encoding: chunked responses to HEAD requests + if (this._hasBody && this.chunkedEncoding) + hot = false; + if (hot) { // Hot path. They're doing // res.writeHead(); @@ -982,7 +986,7 @@ OutgoingMessage.prototype.end = function(data, encoding) { } if (!hot) { - if (this.chunkedEncoding) { + if (this._hasBody && this.chunkedEncoding) { ret = this._send('0\r\n' + this._trailer + '\r\n', 'ascii'); } else { // Force a flush, HACK. diff --git a/test/simple/test-http-head-request.js b/test/simple/test-http-head-request.js index 60982abcc00aa2..ca0f13a1a28830 100644 --- a/test/simple/test-http-head-request.js +++ b/test/simple/test-http-head-request.js @@ -26,32 +26,44 @@ var util = require('util'); var body = 'hello world\n'; +var id = 0; -var server = http.createServer(function(req, res) { - common.error('req: ' + req.method); - res.writeHead(200, {'Content-Length': body.length}); - res.end(); - server.close(); -}); +function test(headers) { + var port = common.PORT + id++; + + var server = http.createServer(function(req, res) { + console.error('req: %s headers: %j', req.method, headers); + res.writeHead(200, headers); + res.end(); + server.close(); + }); + + var gotEnd = false; -var gotEnd = false; - -server.listen(common.PORT, function() { - var request = http.request({ - port: common.PORT, - method: 'HEAD', - path: '/' - }, function(response) { - common.error('response start'); - response.on('end', function() { - common.error('response end'); - gotEnd = true; + server.listen(port, function() { + var request = http.request({ + port: port, + method: 'HEAD', + path: '/' + }, function(response) { + console.error('response start'); + response.on('end', function() { + console.error('response end'); + gotEnd = true; + }); + response.resume(); }); - response.resume(); + request.end(); }); - request.end(); -}); -process.on('exit', function() { - assert.ok(gotEnd); + process.on('exit', function() { + assert.ok(gotEnd); + }); +} + +test({ + 'Transfer-Encoding': 'chunked' +}); +test({ + 'Content-Length': body.length });