From fe838611f6d768a6b400e9ff13fabd07ffe47b6a Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Thu, 10 Feb 2011 16:29:34 -0800 Subject: [PATCH] Fixed field merging with progressive fields on writeHead() --- lib/http.js | 46 ++++++++++++++++++++---- test/simple/test-http-mutable-headers.js | 15 +++++++- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/lib/http.js b/lib/http.js index 9506a8ca50..356495f5b7 100644 --- a/lib/http.js +++ b/lib/http.js @@ -303,9 +303,6 @@ function OutgoingMessage() { this._trailer = ''; this.finished = false; - - this._headers = {}; - this._headerNames = {}; } util.inherits(OutgoingMessage, stream.Stream); @@ -507,6 +504,8 @@ OutgoingMessage.prototype.setHeader = function(name, value) { } var key = name.toLowerCase(); + this._headers = this._headers || {}; + this._headerNames = this._headerNames || {}; this._headers[key] = value; this._headerNames[key] = name; }; @@ -521,6 +520,8 @@ OutgoingMessage.prototype.getHeader = function(name) { throw new Error("Can't use mutable header APIs after sent."); } + if (!this._headers) return; + var key = name.toLowerCase(); return this._headers[key]; }; @@ -535,6 +536,8 @@ OutgoingMessage.prototype.removeHeader = function(name) { throw new Error("Can't remove headers after they are sent."); } + if (!this._headers) return; + var key = name.toLowerCase(); delete this._headers[key]; delete this._headerNames[key]; @@ -545,6 +548,9 @@ OutgoingMessage.prototype._renderHeaders = function() { if (this._header) { throw new Error("Can't render headers after they are sent to the client."); } + + if (!this._headers) return {}; + var headers = {}; var keys = Object.keys(this._headers); for (var i = 0, l = keys.length; i < l; i++) { @@ -754,7 +760,7 @@ ServerResponse.prototype.writeContinue = function() { }; ServerResponse.prototype._implicitHeader = function() { - this.writeHead(this.statusCode, this._renderHeaders()); + this.writeHead(this.statusCode); }; ServerResponse.prototype.writeHead = function(statusCode) { @@ -768,10 +774,36 @@ ServerResponse.prototype.writeHead = function(statusCode) { headerIndex = 1; } - if (typeof arguments[headerIndex] == 'object') { - headers = arguments[headerIndex]; + var obj = arguments[headerIndex]; + + if (obj && this._headers) { + // Slow-case: when progressive API and header fields are passed. + headers = this._renderHeaders(); + + if (Array.isArray(obj)) { + // handle array case + // TODO: remove when array is no longer accepted + var field; + for (var i = 0, len = obj.length; i < len; ++i) { + field = obj[i][0]; + if (field in headers) { + obj.push([field, headers[field]]); + } + } + headers = obj; + + } else { + // handle object case + for (var k in obj) { + if (k) headers[k] = obj[k]; + } + } + } else if (this._headers) { + // only progressive api is used + headers = this._renderHeaders(); } else { - headers = {}; + // only writeHead() called + headers = obj; } var statusLine = 'HTTP/1.1 ' + statusCode.toString() + ' ' + diff --git a/test/simple/test-http-mutable-headers.js b/test/simple/test-http-mutable-headers.js index 8b44cd0c27..844c817b39 100644 --- a/test/simple/test-http-mutable-headers.js +++ b/test/simple/test-http-mutable-headers.js @@ -48,6 +48,12 @@ var s = http.createServer(function(req, res) { res.setHeader('transfer-encoding', 'chunked'); assert.equal(res.getHeader('Transfer-Encoding'), 'chunked'); break; + + case 'writeHead': + res.statusCode = 404; + res.setHeader('x-foo', 'keyboard cat'); + res.writeHead(200, { 'x-foo': 'bar', 'x-bar': 'baz' }); + break; } res.statusCode = 201; @@ -92,6 +98,13 @@ function nextTest () { case 'transferEncoding': assert.equal(response.headers['transfer-encoding'], 'chunked'); + test = 'writeHead'; + break; + + case 'writeHead': + assert.equal(response.headers['x-foo'], 'bar'); + assert.equal(response.headers['x-bar'], 'baz'); + assert.equal(200, response.statusCode); test = 'end'; break; @@ -114,6 +127,6 @@ function nextTest () { process.on('exit', function() { - assert.equal(3, testsComplete); + assert.equal(4, testsComplete); });