diff --git a/lib/http.js b/lib/http.js index b7e7afcbfb8..8a130915fe7 100644 --- a/lib/http.js +++ b/lib/http.js @@ -248,6 +248,13 @@ var dateExpression = /Date/i; var expectExpression = /Expect/i; var continueExpression = /100-continue/i; +var automaticHeaders = { + connection : true, + 'content-length' : true, + 'transfer-encoding' : true, + date : true +}; + var dateCache; function utcDate() { if (!dateCache) { @@ -441,6 +448,7 @@ function OutgoingMessage() { this.shouldKeepAlive = true; this.useChunkedEncodingByDefault = true; this.sendDate = false; + this._removedHeader = {}; this._hasBody = true; this._trailer = ''; @@ -599,7 +607,9 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) { } // keep-alive logic - if (sentConnectionHeader === false) { + if (this._removedHeader['connection']) { + this._last = true; + } else if (sentConnectionHeader === false) { var shouldSendKeepAlive = this.shouldKeepAlive && (sentContentLengthHeader || this.useChunkedEncodingByDefault || @@ -613,7 +623,7 @@ OutgoingMessage.prototype._storeHeader = function(firstLine, headers) { } if (sentContentLengthHeader == false && sentTransferEncodingHeader == false) { - if (this._hasBody) { + if (this._hasBody && !this._removedHeader['transfer-encoding']) { if (this.useChunkedEncodingByDefault) { messageHeader += 'Transfer-Encoding: chunked\r\n'; this.chunkedEncoding = true; @@ -649,6 +659,10 @@ OutgoingMessage.prototype.setHeader = function(name, value) { this._headerNames = this._headerNames || {}; this._headers[key] = value; this._headerNames[key] = name; + + if (automaticHeaders[key]) { + this._removedHeader[key] = false; + } }; @@ -673,9 +687,15 @@ OutgoingMessage.prototype.removeHeader = function(name) { throw new Error('Can\'t remove headers after they are sent.'); } - if (!this._headers) return; - var key = name.toLowerCase(); + + if (key === 'date') { + this.sendDate = false; + } else if (automaticHeaders[key]) { + this._removedHeader[key] = true; + } + + if (!this._headers) return; delete this._headers[key]; delete this._headerNames[key]; }; diff --git a/test/simple/test-http-remove-header-stays-removed.js b/test/simple/test-http-remove-header-stays-removed.js new file mode 100644 index 00000000000..b5a71aa4f5f --- /dev/null +++ b/test/simple/test-http-remove-header-stays-removed.js @@ -0,0 +1,58 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var common = require('../common'); +var assert = require('assert'); + +var http = require('http'); + +var server = http.createServer(function(request, response) { + // removed headers should stay removed, even if node automatically adds them + // to the output: + response.removeHeader('connection'); + response.removeHeader('transfer-encoding'); + + // make sure that removing and then setting still works: + response.removeHeader('date'); + response.setHeader('date', 'coffee o clock'); + + response.end('beep boop\n'); + + this.close(); +}); + +var response = ''; + +process.on('exit', function() { + assert.equal('beep boop\n', response); +}); + +server.listen(common.PORT, function() { + http.get({ port: common.PORT }, function(res) { + assert.equal(200, res.statusCode); + assert.deepEqual(res.headers, { date : 'coffee o clock' }); + + res.setEncoding('ascii'); + res.on('data', function(chunk) { + response += chunk; + }); + }); +});