Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,11 @@ An invalid value has been specified for an HTTP/2 setting.

An operation was performed on a stream that had already been destroyed.

<a id="ERR_HTTP2_INVALID_TOKEN"></a>
### `ERR_HTTP2_INVALID_TOKEN`

An invalid HTTP/2 header was specified.

<a id="ERR_HTTP2_MAX_PENDING_SETTINGS_ACK"></a>
### `ERR_HTTP2_MAX_PENDING_SETTINGS_ACK`

Expand Down
2 changes: 2 additions & 0 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,8 @@ E('ERR_HTTP2_INVALID_SETTING_VALUE',
return `Invalid value for setting "${name}": ${actual}`;
}, TypeError, RangeError);
E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed', Error);
E('ERR_HTTP2_INVALID_TOKEN', '%s must be a valid HTTP2 token ["%s"]',
TypeError);
E('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK',
'Maximum number of pending settings acknowledgements', Error);
E('ERR_HTTP2_NESTED_PUSH',
Expand Down
14 changes: 13 additions & 1 deletion lib/internal/http2/compat.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const {
ERR_HTTP2_INFO_STATUS_NOT_ALLOWED,
ERR_HTTP2_INVALID_HEADER_VALUE,
ERR_HTTP2_INVALID_STREAM,
ERR_HTTP2_INVALID_TOKEN,
ERR_HTTP2_NO_SOCKET_MANIPULATION,
ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED,
ERR_HTTP2_STATUS_INVALID,
Expand All @@ -46,7 +47,13 @@ const {
hideStackFrames
} = require('internal/errors');
const { validateString } = require('internal/validators');
const { kSocket, kRequest, kProxySocket } = require('internal/http2/util');
const {
kSocket,
kRequest,
kProxySocket,
assertValidPseudoHeader
} = require('internal/http2/util');
const { _checkIsHttpToken: checkIsHttpToken } = require('_http_common');

const kBeginSend = Symbol('begin-send');
const kState = Symbol('state');
Expand Down Expand Up @@ -586,6 +593,11 @@ class Http2ServerResponse extends Stream {
return;
}

if (name[0] === ':')
assertValidPseudoHeader(name);
else if (!checkIsHttpToken(name))
this.destroy(new ERR_HTTP2_INVALID_TOKEN('Header name', name));

this[kHeaders][name] = value;
}

Expand Down
14 changes: 13 additions & 1 deletion lib/internal/http2/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ const tls = require('tls');
const { URL } = require('url');
const { setImmediate } = require('timers');

const { kIncomingMessage } = require('_http_common');
const {
kIncomingMessage,
_checkIsHttpToken: checkIsHttpToken
} = require('_http_common');
const { kServerResponse } = require('_http_server');
const JSStreamSocket = require('internal/js_stream_socket');

Expand All @@ -62,6 +65,7 @@ const {
ERR_HTTP2_INVALID_SESSION,
ERR_HTTP2_INVALID_SETTING_VALUE,
ERR_HTTP2_INVALID_STREAM,
ERR_HTTP2_INVALID_TOKEN,
ERR_HTTP2_MAX_PENDING_SETTINGS_ACK,
ERR_HTTP2_NESTED_PUSH,
ERR_HTTP2_NO_SOCKET_MANIPULATION,
Expand Down Expand Up @@ -108,6 +112,7 @@ const { onServerStream,

const {
assertIsObject,
assertValidPseudoHeader,
assertValidPseudoHeaderResponse,
assertValidPseudoHeaderTrailer,
assertWithinRange,
Expand Down Expand Up @@ -1622,6 +1627,13 @@ class ClientHttp2Session extends Http2Session {

this[kUpdateTimer]();

for (const i in headers) {
if (i[0] === ':') {
assertValidPseudoHeader(i);
} else if (i && !checkIsHttpToken(i))
this.destroy(new ERR_HTTP2_INVALID_TOKEN('Header name', i));
}

assertIsObject(headers, 'headers');
assertIsObject(options, 'options');

Expand Down
1 change: 1 addition & 0 deletions lib/internal/http2/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ function sessionName(type) {

module.exports = {
assertIsObject,
assertValidPseudoHeader,
assertValidPseudoHeaderResponse,
assertValidPseudoHeaderTrailer,
assertWithinRange,
Expand Down
31 changes: 31 additions & 0 deletions test/parallel/test-http2-invalidheaderfields-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto) { common.skip('missing crypto'); }
const assert = require('assert');
const http2 = require('http2');

const server1 = http2.createServer();

server1.listen(0, common.mustCall(() => {
const session = http2.connect(`http://localhost:${server1.address().port}`);
session.request({ 'no underscore': 123 });
session.on('error', common.mustCall((e) => {
assert.strictEqual(e.code, 'ERR_HTTP2_INVALID_TOKEN');
server1.close();
}));
}));

const server2 = http2.createServer(common.mustCall((req, res) => {
res.setHeader('x y z', 123);
res.end();
}));

server2.listen(0, common.mustCall(() => {
const session = http2.connect(`http://localhost:${server2.address().port}`);
const req = session.request();
req.on('error', common.mustCall((e) => {
assert.strictEqual(e.code, 'ERR_HTTP2_STREAM_ERROR');
session.close();
server2.close();
}));
}));