Skip to content

Commit c70b9f0

Browse files
authored
fix(request): request headers array (nodejs#1807)
* fix(request): request headers arry * Add more tests specific to request * Allow all primitive types * Object and not array * Check values in array
1 parent fcc1698 commit c70b9f0

File tree

3 files changed

+104
-4
lines changed

3 files changed

+104
-4
lines changed

lib/core/request.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,17 @@ class Request {
271271
}
272272
}
273273

274+
function processHeaderValue (key, val) {
275+
if (val && (typeof val === 'object' && !Array.isArray(val))) {
276+
throw new InvalidArgumentError(`invalid ${key} header`)
277+
} else if (headerCharRegex.exec(val) !== null) {
278+
throw new InvalidArgumentError(`invalid ${key} header`)
279+
}
280+
return `${key}: ${val}\r\n`
281+
}
282+
274283
function processHeader (request, key, val) {
275-
if (val && typeof val === 'object') {
284+
if (val && (typeof val === 'object' && !Array.isArray(val))) {
276285
throw new InvalidArgumentError(`invalid ${key} header`)
277286
} else if (val === undefined) {
278287
return
@@ -329,10 +338,14 @@ function processHeader (request, key, val) {
329338
throw new NotSupportedError('expect header not supported')
330339
} else if (tokenRegExp.exec(key) === null) {
331340
throw new InvalidArgumentError('invalid header key')
332-
} else if (headerCharRegex.exec(val) !== null) {
333-
throw new InvalidArgumentError(`invalid ${key} header`)
334341
} else {
335-
request.headers += `${key}: ${val}\r\n`
342+
if (Array.isArray(val)) {
343+
for (let i = 0; i < val.length; i++) {
344+
request.headers += processHeaderValue(key, val[i])
345+
}
346+
} else {
347+
request.headers += processHeaderValue(key, val)
348+
}
336349
}
337350
}
338351

test/headers-as-array.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,69 @@ test('handle headers as array', (t) => {
2525
})
2626
})
2727

28+
test('handle multi-valued headers as array', (t) => {
29+
t.plan(1)
30+
const headers = ['a', '1', 'b', '2', 'c', '3', 'd', '4', 'd', '5']
31+
32+
const server = createServer((req, res) => {
33+
t.match(req.headers, { a: '1', b: '2', c: '3', d: '4, 5' })
34+
res.end()
35+
})
36+
t.teardown(server.close.bind(server))
37+
server.listen(0, () => {
38+
const client = new Client(`http://localhost:${server.address().port}`)
39+
t.teardown(client.destroy.bind(client))
40+
41+
client.request({
42+
path: '/',
43+
method: 'GET',
44+
headers
45+
}, () => {})
46+
})
47+
})
48+
49+
test('handle headers with array', (t) => {
50+
t.plan(1)
51+
const headers = { a: '1', b: '2', c: '3', d: ['4'] }
52+
53+
const server = createServer((req, res) => {
54+
t.match(req.headers, { a: '1', b: '2', c: '3', d: '4' })
55+
res.end()
56+
})
57+
t.teardown(server.close.bind(server))
58+
server.listen(0, () => {
59+
const client = new Client(`http://localhost:${server.address().port}`)
60+
t.teardown(client.destroy.bind(client))
61+
62+
client.request({
63+
path: '/',
64+
method: 'GET',
65+
headers
66+
}, () => {})
67+
})
68+
})
69+
70+
test('handle multi-valued headers', (t) => {
71+
t.plan(1)
72+
const headers = { a: '1', b: '2', c: '3', d: ['4', '5'] }
73+
74+
const server = createServer((req, res) => {
75+
t.match(req.headers, { a: '1', b: '2', c: '3', d: '4, 5' })
76+
res.end()
77+
})
78+
t.teardown(server.close.bind(server))
79+
server.listen(0, () => {
80+
const client = new Client(`http://localhost:${server.address().port}`)
81+
t.teardown(client.destroy.bind(client))
82+
83+
client.request({
84+
path: '/',
85+
method: 'GET',
86+
headers
87+
}, () => {})
88+
})
89+
})
90+
2891
test('fail if headers array is odd', (t) => {
2992
t.plan(2)
3093
const headers = ['a', '1', 'b', '2', 'c', '3', 'd']

test/node-fetch/main.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,30 @@ describe('node-fetch', () => {
185185
})
186186
})
187187

188+
it('should send request with custom headers array', () => {
189+
const url = `${base}inspect`
190+
const options = {
191+
headers: { 'x-custom-header': ['abc'] }
192+
}
193+
return fetch(url, options).then(res => {
194+
return res.json()
195+
}).then(res => {
196+
expect(res.headers['x-custom-header']).to.equal('abc')
197+
})
198+
})
199+
200+
it('should send request with multi-valued headers', () => {
201+
const url = `${base}inspect`
202+
const options = {
203+
headers: { 'x-custom-header': ['abc', '123'] }
204+
}
205+
return fetch(url, options).then(res => {
206+
return res.json()
207+
}).then(res => {
208+
expect(res.headers['x-custom-header']).to.equal('abc,123')
209+
})
210+
})
211+
188212
it('should accept headers instance', () => {
189213
const url = `${base}inspect`
190214
const options = {

0 commit comments

Comments
 (0)