Permalink
Browse files

Generate Date headers on responses when not already present.

  • Loading branch information...
1 parent d653732 commit 1e425e3fa774fefd3553ecaa6f0ac35f9b0a1355 @mnot mnot committed with isaacs Feb 14, 2012
@@ -344,6 +344,13 @@ or
response.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]);
+### response.sendDate
+
+When true, the Date header will be automatically generated and sent in
+the response if it is not already present in the headers. Defaults to true.
+
+This should only be disabled for testing; HTTP requires the Date header
+in responses.
### response.getHeader(name)
View
@@ -226,9 +226,22 @@ var transferEncodingExpression = /Transfer-Encoding/i;
var closeExpression = /close/i;
var chunkExpression = /chunk/i;
var contentLengthExpression = /Content-Length/i;
+var dateExpression = /Date/i;
var expectExpression = /Expect/i;
var continueExpression = /100-continue/i;
+var dateCache;
+function utcDate() {
+ if (! dateCache) {
+ var d = new Date();
+ dateCache = d.toUTCString();
+ setTimeout(function () {
+ dateCache = undefined;
+ }, 1000 - d.getMilliseconds());
+ }
+ return dateCache;
+}
+
@tj
tj Feb 17, 2012

should this maybe be specific (or somehow tied to) server instances? so that on close the cyclic timeout stops

@mnot
mnot Feb 17, 2012

It's not really cyclic; if no responses are sent, there isn't a callback. So when a server stops, the timeout function will be called at most once.

Also, Date isn't really instance-specific...

@tj
tj Feb 17, 2012

sure, cool that's the part I was worried about (just glanced at the code)

@bobrik
bobrik Feb 17, 2012

When server stopped it's probably better to clearTimeout. Not a big deal, btw

/* Abstract base class for ServerRequest and ClientResponse. */
function IncomingMessage(socket) {
@@ -383,6 +396,7 @@ function OutgoingMessage() {
this.chunkedEncoding = false;
this.shouldKeepAlive = true;
this.useChunkedEncodingByDefault = true;
+ this.sendDate = false;
this._hasBody = true;
this._trailer = '';
@@ -473,6 +487,7 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
var sentConnectionHeader = false;
var sentContentLengthHeader = false;
var sentTransferEncodingHeader = false;
+ var sentDateHeader = false;
var sentExpect = false;
// firstLine in the case of request is: 'GET /index.html HTTP/1.1\r\n'
@@ -498,7 +513,8 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
} else if (contentLengthExpression.test(field)) {
sentContentLengthHeader = true;
-
+ } else if (dateExpression.test(field)) {
+ sentDateHeader = true;
} else if (expectExpression.test(field)) {
sentExpect = true;
}
@@ -529,6 +545,11 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) {
}
}
+ // Date header
+ if (this.sendDate == true && sentDateHeader == false) {
+ messageHeader += "Date: " + utcDate() + CRLF;
+ }
+
// keep-alive logic
if (sentConnectionHeader === false) {
if (this.shouldKeepAlive &&
@@ -816,6 +837,8 @@ function ServerResponse(req) {
if (req.method === 'HEAD') this._hasBody = false;
+ this.sendDate = true;
+
if (req.httpVersionMajor < 1 || req.httpVersionMinor < 1) {
this.useChunkedEncodingByDefault = false;
this.shouldKeepAlive = false;
@@ -104,6 +104,7 @@ function test(handler, request_generator, response_validator) {
assert.equal('1.0', req.httpVersion);
assert.equal(1, req.httpVersionMajor);
assert.equal(0, req.httpVersionMinor);
+ res.sendDate = false;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello, '); res._send('');
res.write('world!'); res._send('');
@@ -140,6 +141,7 @@ function test(handler, request_generator, response_validator) {
assert.equal('1.1', req.httpVersion);
assert.equal(1, req.httpVersionMajor);
assert.equal(1, req.httpVersionMinor);
+ res.sendDate = false;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello, '); res._send('');
res.write('world!'); res._send('');
@@ -0,0 +1,35 @@
+var common = require("../common");
+var assert = require('assert');
+var http = require("http");
+
+var testResBody = "other stuff!\n";
+
+var server = http.createServer(function(req, res) {
+ assert.ok(! ("date" in req.headers),
+ "Request headers contained a Date."
+ );
+ res.writeHead(200, {
+ 'Content-Type' : 'text/plain',
+ });
+ res.end(testResBody);
+});
+server.listen(common.PORT);
+
+
+server.addListener("listening", function() {
+ var options = {
+ port: common.PORT,
+ path: "/",
+ method: "GET"
+ }
+ var req = http.request(options, function (res) {
+ assert.ok("date" in res.headers,
+ "Response headers didn't contain a Date."
+ );
+ res.addListener('end', function () {
+ server.close();
+ process.exit();
+ });
+ });
+ req.end();
+});
@@ -56,7 +56,7 @@ server.listen(common.PORT, function() {
var maxAndExpected = [ // for client
[20, 20],
[1200, 1200],
- [0, N + 2], // Connection and Transfer-Encoding
+ [0, N + 3], // Connection, Date and Transfer-Encoding
];
doRequest();

4 comments on commit 1e425e3

@s3u
s3u commented on 1e425e3 Feb 15, 2012

Finally! Thanks @mnot

@ry
ry commented on 1e425e3 Feb 16, 2012

Now much does this slow down our hello-world benchmark?

@mnot
mnot commented on 1e425e3 Feb 16, 2012

Last I checked, it was in the noise; the expensive part was the toUTCString(), and that's cached.

@rtomayko

❤️

Please sign in to comment.