Skip to content

Commit

Permalink
http2: compat support for array headers
Browse files Browse the repository at this point in the history
PR-URL: #42901
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ricky Zhou <0x19951125@gmail.com>
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
  • Loading branch information
y1d7ng authored and RafaelGSS committed May 10, 2022
1 parent 9ee7d9e commit bfbf965
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 37 deletions.
2 changes: 1 addition & 1 deletion doc/api/http2.md
Original file line number Diff line number Diff line change
Expand Up @@ -3985,7 +3985,7 @@ changes:

* `statusCode` {number}
* `statusMessage` {string}
* `headers` {Object}
* `headers` {Object|Array}
* Returns: {http2.Http2ServerResponse}

Sends a response header to the request. The status code is a 3-digit HTTP
Expand Down
16 changes: 13 additions & 3 deletions lib/internal/http2/compat.js
Original file line number Diff line number Diff line change
Expand Up @@ -682,9 +682,19 @@ class Http2ServerResponse extends Stream {

let i;
if (ArrayIsArray(headers)) {
for (i = 0; i < headers.length; i++) {
const header = headers[i];
this[kSetHeader](header[0], header[1]);
if (headers.length && ArrayIsArray(headers[0])) {
for (i = 0; i < headers.length; i++) {
const header = headers[i];
this[kSetHeader](header[0], header[1]);
}
} else {
if (headers.length % 2 !== 0) {
throw new ERR_INVALID_ARG_VALUE('headers', headers);
}

for (i = 0; i < headers.length; i += 2) {
this[kSetHeader](headers[i], headers[i + 1]);
}
}
} else if (typeof headers === 'object') {
const keys = ObjectKeys(headers);
Expand Down
118 changes: 85 additions & 33 deletions test/parallel/test-http2-compat-serverresponse-writehead-array.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,92 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const h2 = require('http2');

// Http2ServerResponse.writeHead should support nested arrays

const server = h2.createServer();
server.listen(0, common.mustCall(() => {
const port = server.address().port;
server.once('request', common.mustCall((request, response) => {
const returnVal = response.writeHead(200, [
['foo', 'bar'],
['ABC', 123],
]);
assert.strictEqual(returnVal, response);
response.end(common.mustCall(() => { server.close(); }));
const http2 = require('http2');

// Http2ServerResponse.writeHead should support arrays and nested arrays

{
const server = http2.createServer();
server.listen(0, common.mustCall(() => {
const port = server.address().port;

server.once('request', common.mustCall((request, response) => {
const returnVal = response.writeHead(200, [
['foo', 'bar'],
['ABC', 123],
]);
assert.strictEqual(returnVal, response);
response.end(common.mustCall(() => { server.close(); }));
}));

const client = http2.connect(`http://localhost:${port}`, common.mustCall(() => {
const request = client.request();

request.on('response', common.mustCall((headers) => {
assert.strictEqual(headers.foo, 'bar');
assert.strictEqual(headers.abc, '123');
assert.strictEqual(headers[':status'], 200);
}, 1));
request.on('end', common.mustCall(() => {
client.close();
}));
request.end();
request.resume();
}));
}));
}

{
const server = http2.createServer();
server.listen(0, common.mustCall(() => {
const port = server.address().port;

server.once('request', common.mustCall((request, response) => {
const returnVal = response.writeHead(200, ['foo', 'bar', 'ABC', 123]);
assert.strictEqual(returnVal, response);
response.end(common.mustCall(() => { server.close(); }));
}));

const client = http2.connect(`http://localhost:${port}`, common.mustCall(() => {
const request = client.request();

request.on('response', common.mustCall((headers) => {
assert.strictEqual(headers.foo, 'bar');
assert.strictEqual(headers.abc, '123');
assert.strictEqual(headers[':status'], 200);
}, 1));
request.on('end', common.mustCall(() => {
client.close();
}));
request.end();
request.resume();
}));
}));
}

{
const server = http2.createServer();
server.listen(0, common.mustCall(() => {
const port = server.address().port;

server.once('request', common.mustCall((request, response) => {
try {
response.writeHead(200, ['foo', 'bar', 'ABC', 123, 'extra']);
} catch (err) {
assert.strictEqual(err.code, 'ERR_INVALID_ARG_VALUE');
}

response.end(common.mustCall(() => { server.close(); }));
}));

const client = http2.connect(`http://localhost:${port}`, common.mustCall(() => {
const request = client.request();

const url = `http://localhost:${port}`;
const client = h2.connect(url, common.mustCall(() => {
const headers = {
':path': '/',
':method': 'GET',
':scheme': 'http',
':authority': `localhost:${port}`
};
const request = client.request(headers);
request.on('response', common.mustCall((headers) => {
assert.strictEqual(headers.foo, 'bar');
assert.strictEqual(headers.abc, '123');
assert.strictEqual(headers[':status'], 200);
}, 1));
request.on('end', common.mustCall(() => {
client.close();
request.on('end', common.mustCall(() => {
client.close();
}));
request.end();
request.resume();
}));
request.end();
request.resume();
}));
}));
}

0 comments on commit bfbf965

Please sign in to comment.