http: allow passing array of key/val into writeHead

Enables an optimization when the user already has the headers
in an array form, e.g. when proxying.

PR-URL: https://github.com/nodejs/node/pull/35274
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
Robert Nagy committed 2020-10-10 10:11:41 +02:00
1 parent 8d8e06a345
commit d70c0ed250
4 files changed
+95 -4

No files matched your search

+9 -1
View File
@@ -1797,6 +1797,9 @@ the request body should be sent. See the [`'checkContinue'`][] event on
<!-- YAML
added: v0.1.30
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/35274
description: Allow passing headers as an array.
- version:
- v11.10.0
- v10.17.0
@@ -1813,7 +1816,7 @@ changes:
* `statusCode` {number}
* `statusMessage` {string}
* `headers` {Object}
* `headers` {Object|Array}
* Returns: {http.ServerResponse}
Sends a response header to the request. The status code is a 3-digit HTTP
@@ -1821,6 +1824,11 @@ status code, like `404`. The last argument, `headers`, are the response headers.
Optionally one can give a human-readable `statusMessage` as the second
argument.
`headers` may be an `Array` where the keys and values are in the same list.
It is *not* a list of tuples. So, the even-numbered offsets are key values,
and the odd-numbered offsets are the associated values. The array is in the same
format as `request.rawHeaders`.
Returns a reference to the `ServerResponse`, so that calls can be chained.
```js
+13 -2
View File
@@ -53,6 +53,7 @@ const {
ERR_HTTP_TRAILER_INVALID,
ERR_INVALID_HTTP_TOKEN,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_INVALID_CHAR,
ERR_METHOD_NOT_IMPLEMENTED,
ERR_STREAM_CANNOT_PIPE,
@@ -381,8 +382,18 @@ function _storeHeader(firstLine, headers) {
processHeader(this, state, entry[0], entry[1], false);
}
} else if (ArrayIsArray(headers)) {
for (const entry of headers) {
processHeader(this, state, entry[0], entry[1], true);
if (headers.length && ArrayIsArray(headers[0])) {
for (const entry of headers) {
processHeader(this, state, entry[0], entry[1], true);
}
} else {
if (headers.length % 2 !== 0) {
throw new ERR_INVALID_ARG_VALUE('headers', headers);
}
for (let n = 0; n < headers.length; n += 2) {
processHeader(this, state, headers[n + 0], headers[n + 1], true);
}
}
} else {
for (const key in headers) {
+12 -1
View File
@@ -22,6 +22,7 @@
'use strict';
const {
ArrayIsArray,
Error,
ObjectKeys,
ObjectSetPrototypeOf,
@@ -67,6 +68,7 @@ const {
ERR_HTTP_INVALID_STATUS_CODE,
ERR_HTTP_SOCKET_ENCODING,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_INVALID_CHAR
} = codes;
const {
@@ -278,7 +280,16 @@ function writeHead(statusCode, reason, obj) {
if (this[kOutHeaders]) {
// Slow-case: when progressive API and header fields are passed.
let k;
if (obj) {
if (ArrayIsArray(obj)) {
if (obj.length % 2 !== 0) {
throw new ERR_INVALID_ARG_VALUE('headers', obj);
}
for (let n = 0; n < obj.length; n += 2) {
k = obj[n + 0];
if (k) this.setHeader(k, obj[n + 1]);
}
} else if (obj) {
const keys = ObjectKeys(obj);
// Retain for(;;) loop for performance reasons
// Refs: https://github.com/nodejs/node/pull/30958
+61
View File
@@ -0,0 +1,61 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const http = require('http');
// Verify that ServerResponse.writeHead() works with arrays.
{
const server = http.createServer(common.mustCall((req, res) => {
res.setHeader('test', '1');
res.writeHead(200, [ 'test', '2', 'test2', '2' ]);
res.end();
}));
server.listen(0, common.mustCall(() => {
http.get({ port: server.address().port }, common.mustCall((res) => {
assert.strictEqual(res.headers.test, '2');
assert.strictEqual(res.headers.test2, '2');
res.resume().on('end', common.mustCall(() => {
server.close();
}));
}));
}));
}
{
const server = http.createServer(common.mustCall((req, res) => {
res.writeHead(200, [ 'test', '1', 'test2', '2' ]);
res.end();
}));
server.listen(0, common.mustCall(function() {
http.get({ port: server.address().port }, common.mustCall((res) => {
assert.strictEqual(res.headers.test, '1');
assert.strictEqual(res.headers.test2, '2');
res.resume().on('end', common.mustCall(() => {
server.close();
}));
}));
}));
}
{
const server = http.createServer(common.mustCall((req, res) => {
try {
res.writeHead(200, [ 'test', '1', 'test2', '2', 'asd' ]);
} catch (err) {
assert.strictEqual(err.code, 'ERR_INVALID_ARG_VALUE');
}
res.end();
}));
server.listen(0, common.mustCall(function() {
http.get({ port: server.address().port }, common.mustCall((res) => {
res.resume().on('end', common.mustCall(() => {
server.close();
}));
}));
}));
}