From 64934965a0b0c909ca8d0b4299e2aecfb3f39c15 Mon Sep 17 00:00:00 2001 From: Liam O'Boyle Date: Wed, 23 Mar 2016 10:23:35 +1100 Subject: [PATCH] Maintain request header casing. While headers are meant to be case sensitive, many servers do not respect this. Node maintains the casing of the request headers in order to work with this and http-browserify should do likewise in order to be consistent with the node implementation. This patch maintains the casing with which the header was last set, e.g. setting header "fOo", then header "Foo" will still only send one header, but will use the final casing "Foo". This is compatible with the node implementation in https://github.com/nodejs/node/blob/85ab4a5f1281c4e1dd06450ac7bd3250326267fa/lib/_http_outgoing.js --- lib/request.js | 8 ++++++-- test/request_url.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/request.js b/lib/request.js index 7b8b733..7dba0d9 100644 --- a/lib/request.js +++ b/lib/request.js @@ -36,6 +36,7 @@ var Request = module.exports = function (xhr, params) { }; self._headers = {}; + self._headerNames = {}; if (params.headers) { var keys = objectKeys(params.headers); @@ -78,6 +79,7 @@ inherits(Request, Stream); Request.prototype.setHeader = function (key, value) { this._headers[key.toLowerCase()] = value + this._headerNames[key.toLowerCase()] = key; }; Request.prototype.getHeader = function (key) { @@ -86,6 +88,7 @@ Request.prototype.getHeader = function (key) { Request.prototype.removeHeader = function (key) { delete this._headers[key.toLowerCase()] + delete this._headerNames[key.toLowerCase()] }; Request.prototype.write = function (s) { @@ -105,12 +108,13 @@ Request.prototype.end = function (s) { for (var i = 0; i < keys.length; i++) { var key = keys[i]; var value = this._headers[key]; + var name = this._headerNames[key]; if (isArray(value)) { for (var j = 0; j < value.length; j++) { - this.xhr.setRequestHeader(key, value[j]); + this.xhr.setRequestHeader(name, value[j]); } } - else this.xhr.setRequestHeader(key, value) + else this.xhr.setRequestHeader(name, value) } if (this.body.length === 0) { diff --git a/test/request_url.js b/test/request_url.js index 1f58f2d..57adefd 100644 --- a/test/request_url.js +++ b/test/request_url.js @@ -9,6 +9,7 @@ var noop = function() {}; global.XMLHttpRequest = function() { this.open = noop; this.send = noop; + this.setRequestHeader = noop; }; global.FormData = function () {}; @@ -112,3 +113,32 @@ test('Test POST XHR2 types', function(t) { }; request.end(new global.FormData()); }); + +test('Test header access is case insensitive, but is still sent in given case', function (t) { + t.plan(3); + + var Request = require('../lib/request'); + var headers = {}; + var xhr = function () { + this.open = noop; + this.send = noop; + this.setRequestHeader = function (key, value) { + headers[key] = value; + }; + }; + + var params = { + path: '/api/foo', + host: 'localhost', + scheme: 'http', + headers: { Foo: 'bar' } + }; + var request = new Request(new xhr, params); + request.end(); + + t.ok(request.getHeader('foo') === params.headers.Foo, 'headers should be accessible regardless of case'); + t.ok(headers['Foo'] === params.headers.Foo, 'the original header casing should be sent in the request'); + + request.removeHeader('foo'); + t.ok(request.getHeader('Foo') === undefined, 'headers should be removable regardless of case'); +});