Skip to content

Commit

Permalink
Only emit a warning on duplicate request headers (#1972)
Browse files Browse the repository at this point in the history
* only emit a warning on duplicate request headers

* use debug instead of warn

* Remove left over console and enforce with eslint
  • Loading branch information
mastermatt committed Dec 3, 2021
1 parent 263e31e commit c9517e1
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 12 deletions.
1 change: 1 addition & 0 deletions .eslintrc.yml
Expand Up @@ -29,6 +29,7 @@ rules:

# Nock additions.
strict: ['error', 'safe']
no-console: 'error'
no-loop-func: 'error'
no-var: 'error'
prefer-const: 'error'
Expand Down
14 changes: 10 additions & 4 deletions lib/common.js
Expand Up @@ -194,7 +194,7 @@ function isJSONContent(headers) {
*
* Duplicates throw an error.
*/
function headersFieldNamesToLowerCase(headers) {
function headersFieldNamesToLowerCase(headers, throwOnDuplicate) {
if (!isPlainObject(headers)) {
throw Error('Headers must be provided as an object')
}
Expand All @@ -203,9 +203,15 @@ function headersFieldNamesToLowerCase(headers) {
Object.entries(headers).forEach(([fieldName, fieldValue]) => {
const key = fieldName.toLowerCase()
if (lowerCaseHeaders[key] !== undefined) {
throw Error(
`Failed to convert header keys to lower case due to field name conflict: ${key}`
)
if (throwOnDuplicate) {
throw Error(
`Failed to convert header keys to lower case due to field name conflict: ${key}`
)
} else {
debug(
`Duplicate header provided in request: ${key}. Only the last value can be matched.`
)
}
}
lowerCaseHeaders[key] = fieldValue
})
Expand Down
5 changes: 4 additions & 1 deletion lib/intercepted_request_router.js
Expand Up @@ -40,7 +40,10 @@ class InterceptedRequestRouter {
// affecting the user so we use a clone of the object.
...options,
// We use lower-case header field names throughout Nock.
headers: common.headersFieldNamesToLowerCase(options.headers || {}),
headers: common.headersFieldNamesToLowerCase(
options.headers || {},
false
),
}
this.interceptors = interceptors

Expand Down
3 changes: 2 additions & 1 deletion lib/interceptor.js
Expand Up @@ -66,7 +66,8 @@ module.exports = class Interceptor {

// We use lower-case header field names throughout Nock.
this.reqheaders = common.headersFieldNamesToLowerCase(
scope.scopeOptions.reqheaders || {}
scope.scopeOptions.reqheaders || {},
true
)
this.badheaders = common.headersFieldsArrayToLowerCase(
scope.scopeOptions.badheaders || []
Expand Down
2 changes: 1 addition & 1 deletion lib/recorder.js
Expand Up @@ -168,7 +168,7 @@ let currentRecordingId = 0
const defaultRecordOptions = {
dont_print: false,
enable_reqheaders_recording: false,
logging: console.log,
logging: console.log, // eslint-disable-line no-console
output_objects: false,
use_separator: true,
}
Expand Down
13 changes: 8 additions & 5 deletions tests/test_common.js
Expand Up @@ -155,7 +155,7 @@ describe('`headersFieldNamesToLowerCase()`', () => {
'Content-typE': 'plain/text',
}
const inputClone = { ...input }
const result = common.headersFieldNamesToLowerCase(input)
const result = common.headersFieldNamesToLowerCase(input, true)
const expected = {
host: 'example.test',
'content-type': 'plain/text',
Expand All @@ -167,10 +167,13 @@ describe('`headersFieldNamesToLowerCase()`', () => {

it('throws on conflicting keys', () => {
expect(() =>
common.headersFieldNamesToLowerCase({
HoSt: 'example.test',
HOST: 'example.test',
})
common.headersFieldNamesToLowerCase(
{
HoSt: 'example.test',
HOST: 'example.test',
},
true
)
).to.throw(
'Failed to convert header keys to lower case due to field name conflict: host'
)
Expand Down
25 changes: 25 additions & 0 deletions tests/test_header_matching.js
Expand Up @@ -425,6 +425,31 @@ describe('Header matching', () => {
scope.done()
})

it('should only match the last duplicate request header', done => {
const scope = nock('http://example.test', {
reqheaders: {
'x-auth-token': 'biz',
},
})
.get('/')
.reply()

// Can't use Got here because it would change these headers
const req = http.get('http://example.test', {
headers: {
'x-auth-token': 'foo',
'X-Auth-Token': 'bar',
'X-AUTH-TOKEN': 'biz',
},
})

req.on('response', res => {
expect(res.statusCode).to.equal(200)
scope.done()
done()
})
})

// https://github.com/nock/nock/issues/966
it('mocking succeeds when mocked and specified request headers have falsy values', async () => {
const scope = nock('http://example.test', {
Expand Down

0 comments on commit c9517e1

Please sign in to comment.