From 3934cb54853ca23cee7ef3c6206a5b1264f8ba6d Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 21 Apr 2010 15:15:21 -0700 Subject: [PATCH] Force no body on http 204 and 304 Thanks to tjholowayhuk@gmail.com for the test case. --- lib/http.js | 34 ++++++++++++++++++++++++++++------ test/simple/test-http-304.js | 19 +++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 test/simple/test-http-304.js diff --git a/lib/http.js b/lib/http.js index 950fd4db76..ad61baa42d 100644 --- a/lib/http.js +++ b/lib/http.js @@ -228,6 +228,8 @@ function OutgoingMessage (socket) { this.flushing = false; this.headWritten = false; + this._hasBody = true; + this.finished = false; } sys.inherits(OutgoingMessage, events.EventEmitter); @@ -309,12 +311,16 @@ OutgoingMessage.prototype.sendHeaderLines = function (firstLine, headers) { } if (sentContentLengthHeader == false && sentTransferEncodingHeader == false) { - if (this.useChunkedEncodingByDefault) { - messageHeader += "Transfer-Encoding: chunked\r\n"; - this.chunkedEncoding = true; - } - else { - this.closeOnFinish = true; + if (this._hasBody) { + if (this.useChunkedEncodingByDefault) { + messageHeader += "Transfer-Encoding: chunked\r\n"; + this.chunkedEncoding = true; + } else { + this.closeOnFinish = true; + } + } else { + // Make sure we don't end the 0\r\n\r\n at the end of the message. + this.chunkedEncoding = false; } } @@ -337,6 +343,10 @@ OutgoingMessage.prototype.write = function (chunk, encoding) { throw new Error("writeHead() must be called before write()") } + if (!this._hasBody) { + throw new Error("This type of response MUST NOT have a body."); + } + encoding = encoding || "ascii"; if (this.chunkedEncoding) { if (typeof chunk == 'string') { @@ -415,6 +425,18 @@ ServerResponse.prototype.writeHead = function (statusCode) { var statusLine = "HTTP/1.1 " + statusCode.toString() + " " + reasonPhrase + CRLF; + + if (statusCode === 204 || statusCode === 304) { + // RFC 2616, 10.2.5: + // The 204 response MUST NOT include a message-body, and thus is always + // terminated by the first empty line after the header fields. + // RFC 2616, 10.3.5: + // The 304 response MUST NOT contain a message-body, and thus is always + // terminated by the first empty line after the header fields. + this._hasBody = false; + } + + this.sendHeaderLines(statusLine, headers); this.headWritten = true; }; diff --git a/test/simple/test-http-304.js b/test/simple/test-http-304.js new file mode 100644 index 0000000000..9aadad4857 --- /dev/null +++ b/test/simple/test-http-304.js @@ -0,0 +1,19 @@ +require('../common'); + +var sys = require('sys'), + http = require('http'), + childProcess = require('child_process'); + +s = http.createServer(function (request, response) { + response.writeHead(304); + response.end(); +}) +s.listen(8000); + +childProcess.exec('curl http://127.0.0.1:8000/', function (err, stdout, stderr) { + if (err) throw err; + s.close(); + sys.puts('curled response correctly'); +}); + +sys.puts('Server running at http://127.0.0.1:8000/')