Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP/2 compat API assumes the wrong format when accepting raw headers #42898

Closed
pimterry opened this issue Apr 28, 2022 · 0 comments · Fixed by #42901
Closed

HTTP/2 compat API assumes the wrong format when accepting raw headers #42898

pimterry opened this issue Apr 28, 2022 · 0 comments · Fixed by #42901
Labels
http2 Issues or PRs related to the http2 subsystem.

Comments

@pimterry
Copy link
Member

Version

v18.0.0 (and v14.19.1)

Platform

Linux Zapp 5.4.0-109-generic #123-Ubuntu SMP Fri Apr 8 09:10:54 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

http2

What steps will reproduce the bug?

This code runs an HTTP/2 server, sends a request to it, and responds using writeHead with a raw header array:

const http2 = require('http2');
const server = http2.createServer((req, res) => {
  res.setHeader('Content-Type', 'text/html');
  res.setHeader('X-Foo', 'bar');
  res.writeHead(200, [ 'Content-Type', 'text/plain; charset=utf-8' ]);
  res.end('ok');
});
server.listen(8080)

const client = http2.connect('http://localhost:8080');
client.on('error', (err) => console.error(err));

const req = client.request({ ':path': '/' });

req.on('response', (headers, flags) => {
  for (const name in headers) {
    console.log(`HEADER: ${name}: ${headers[name]}`);
  }
});

req.setEncoding('utf8');
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
  console.log(`\n${data}`);
  client.close();
});
req.end();

How often does it reproduce? Is there a required condition?

Always, I'm fairly sure this applies for all node versions, all platforms.

What is the expected behavior?

The client should print headers including Content-Type: text/plain; charset=utf-8

What do you see instead?

The script above actually prints:

HEADER: :status: 200
HEADER: content-type: text/html
HEADER: x-foo: bar
HEADER: c: o
HEADER: t: e
HEADER: date: Thu, 28 Apr 2022 17:50:19 GMT

ok

Note the c: o, t: e headers (from COntent..., TExt/plain...)

Additional information

The issue is in the writeHead last argument. The writeHead method should support raw headers provided as a flat array of [key, value, key, value] as documented in the HTTP/1 docs:

headers may be an Array where the keys and values are in the same list. It is not a list of tuples.

The HTTP/2 implementation has an array case that tries to do this (here) but it incorrectly assumes that the array will actually be [[key, value], [key, value]], and so it ends up pulling out individual characters instead.

In fact, the HTTP/1 API does support both flat arrays and also (undocumented) tuple arrays (only in some cases, see here) which may have caused this confusion. The flat array is the documented format though, and the only one that works in all cases, so that's what HTTP/2 should support (or both, I guess).

@VoltrexKeyva VoltrexKeyva added the http2 Issues or PRs related to the http2 subsystem. label Apr 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
http2 Issues or PRs related to the http2 subsystem.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants