Force no body on http 204 and 304
authorRyan Dahl <ry@tinyclouds.org>
Wed, 21 Apr 2010 22:15:21 +0000 (15:15 -0700)
committerRyan Dahl <ry@tinyclouds.org>
Wed, 21 Apr 2010 22:15:21 +0000 (15:15 -0700)
Thanks to tjholowayhuk@gmail.com for the test case.

lib/http.js
test/simple/test-http-304.js [new file with mode: 0644]

index 950fd4d..ad61baa 100644 (file)
@@ -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 (file)
index 0000000..9aadad4
--- /dev/null
@@ -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/')