diff --git a/lib/headers.js b/lib/headers.js index 2d8c96e..25e49ff 100644 --- a/lib/headers.js +++ b/lib/headers.js @@ -5,6 +5,30 @@ */ const utils = require('./utils'); +const REFERER_HEADER_NAMES = ['referer', 'referrer']; + +/** + * Get a header value from the headers object. + * Because headers can be set in multiple ways, their names can be uppercased and lowercased. + * + * @param {Object} headers + * @param {string} name + * @returns + */ +function getHeaderValue(headers, name) { + const lowerName = name.toLowerCase(); + + return headers[ + Object.keys(headers).find((key) => { + const lowerKey = key.toLowerCase(); + return ( + lowerKey === lowerName || + (REFERER_HEADER_NAMES.includes(lowerKey) && REFERER_HEADER_NAMES.includes(lowerName)) + ); + }) + ]; +} + /** * Creates a Headers object that implements both Express.js style access * and the Web API Headers interface @@ -18,24 +42,17 @@ function createHeaders(headers = {}) { // Handle Headers interface methods switch (prop) { case 'get': - return (name) => { - const lowerName = name.toLowerCase(); - // Special case for referer/referrer - if (lowerName === 'referer' || lowerName === 'referrer') { - return target.referrer || target.referer; - } - return target[lowerName]; - }; + return (name) => getHeaderValue(target, name); case 'getAll': return (name) => { - const value = target[name.toLowerCase()]; + const value = getHeaderValue(target, name); if (!value) { return []; } return Array.isArray(value) ? value : [value]; }; case 'has': - return (name) => name.toLowerCase() in target; + return (name) => getHeaderValue(target, name) !== undefined; case 'set': return (name, value) => { // eslint-disable-next-line no-param-reassign @@ -82,7 +99,7 @@ function createHeaders(headers = {}) { } ); default: - return target[typeof prop === 'string' ? prop.toLowerCase() : prop]; + return typeof prop === 'string' ? getHeaderValue(target, prop) : target[prop]; } }, set(target, prop, value) { @@ -117,4 +134,4 @@ function createHeaders(headers = {}) { }); } -module.exports = { createHeaders }; +module.exports = { createHeaders, getHeaderValue }; diff --git a/lib/mockRequest.js b/lib/mockRequest.js index 34de081..6098eae 100644 --- a/lib/mockRequest.js +++ b/lib/mockRequest.js @@ -34,7 +34,7 @@ const accepts = require('accepts'); const parseRange = require('range-parser'); let { EventEmitter } = require('events'); const querystring = require('querystring'); -const { createHeaders } = require('./headers'); +const { createHeaders, getHeaderValue } = require('./headers'); const standardRequestOptions = [ 'method', @@ -130,7 +130,7 @@ function createRequest(options = {}) { * @api public */ mockRequest.getHeader = function getHeader(name) { - return mockRequest.headers.get(name); + return getHeaderValue(mockRequest.headers, name); }; mockRequest.header = mockRequest.getHeader; mockRequest.get = mockRequest.getHeader; diff --git a/test/lib/mockRequest.spec.ts b/test/lib/mockRequest.spec.ts index 3ef173e..de1f1e8 100644 --- a/test/lib/mockRequest.spec.ts +++ b/test/lib/mockRequest.spec.ts @@ -304,18 +304,46 @@ describe('mockRequest', () => { }); describe('.get()/.header()', () => { - it('should return header, when set', () => { + it('should return header, when set in constructor', () => { const options = { headers: { - key: 'value' + 'Content-type': 'value' } }; + const request = mockRequest.createRequest(options); - expect(request.get('key')).to.equal('value'); - expect(request.header('key')).to.equal('value'); - expect(request.headers.get('key')).to.equal('value'); - expect(request.getHeader('key')).to.equal('value'); - expect(request.headers.key).to.equal('value'); + expect(request.get('Content-type')).to.equal('value'); + expect(request.header('Content-type')).to.equal('value'); + expect(request.headers.get('Content-type')).to.equal('value'); + expect(request.getHeader('Content-type')).to.equal('value'); + expect(request.headers['Content-type']).to.equal('value'); + }); + + it('should return header, when set explicitly', () => { + const request = mockRequest.createRequest(); + + request.headers['Content-type'] = 'value'; + + expect(request.get('Content-type')).to.equal('value'); + expect(request.header('Content-type')).to.equal('value'); + expect(request.headers.get('Content-type')).to.equal('value'); + expect(request.getHeader('Content-type')).to.equal('value'); + expect(request.headers['Content-type']).to.equal('value'); + }); + + it('should return header, when set as an object (deprecated)', () => { + const request = mockRequest.createRequest(); + + // setting headers as an object is officially supported by Express + // @ts-expect-error + request.headers = { 'Content-type': 'value' }; + + expect(request.get('Content-type')).to.equal('value'); + expect(request.header('Content-type')).to.equal('value'); + expect(request.getHeader('Content-type')).to.equal('value'); + expect(request.headers['Content-type']).to.equal('value'); + + // request.headers.get() is not working in this case }); it('should return referer, when request as referrer', () => {