diff --git a/lib/_http_server.js b/lib/_http_server.js index 3e19f1ba78e7cc..775090b373f696 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -373,9 +373,18 @@ function writeHead(statusCode, reason, obj) { throw new ERR_INVALID_ARG_VALUE('headers', obj); } + // Headers in obj should override previous headers but still + // allow explicit duplicates. To do so, we first remove any + // existing conflicts, then use appendHeader. + + for (let n = 0; n < obj.length; n += 2) { + k = obj[n + 0]; + this.removeHeader(k); + } + for (let n = 0; n < obj.length; n += 2) { k = obj[n + 0]; - if (k) this.setHeader(k, obj[n + 1]); + if (k) this.appendHeader(k, obj[n + 1]); } } else if (obj) { const keys = ObjectKeys(obj); diff --git a/test/parallel/test-http-write-head-after-set-header.js b/test/parallel/test-http-write-head-after-set-header.js new file mode 100644 index 00000000000000..019a0aa50a2540 --- /dev/null +++ b/test/parallel/test-http-write-head-after-set-header.js @@ -0,0 +1,47 @@ +'use strict'; + +const common = require('../common'); +const Countdown = require('../common/countdown'); +const assert = require('assert'); +const { createServer, request } = require('http'); + +const server = createServer(common.mustCall((req, res) => { + if (req.url.includes('setHeader')) { + res.setHeader('set-val', 'abc'); + } + + res.writeHead(200, [ + 'array-val', '1', + 'array-val', '2', + ]); + + res.end(); +}, 2)); + +const countdown = new Countdown(2, () => server.close()); + +server.listen(0, common.mustCall(() => { + request({ + port: server.address().port + }, common.mustCall((res) => { + assert.deepStrictEqual(res.rawHeaders.slice(0, 4), [ + 'array-val', '1', + 'array-val', '2', + ]); + + countdown.dec(); + })).end(); + + request({ + port: server.address().port, + path: '/?setHeader' + }, common.mustCall((res) => { + assert.deepStrictEqual(res.rawHeaders.slice(0, 6), [ + 'set-val', 'abc', + 'array-val', '1', + 'array-val', '2', + ]); + + countdown.dec(); + })).end(); +}));