http2: explicitly disallow nested push streams

Fixes: https://github.com/nodejs/node/issues/19095

PR-URL: https://github.com/nodejs/node/pull/22245
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
This commit is contained in:
James M Snell 2018-08-10 11:05:57 -07:00
parent f6eab1acf2
commit 78584b64d8
5 changed files with 22 additions and 0 deletions

View File

@ -956,6 +956,12 @@ required to send an acknowledgment that it has received and applied the new
be sent at any given time. This error code is used when that limit has been be sent at any given time. This error code is used when that limit has been
reached. reached.
<a id="ERR_HTTP2_NESTED_PUSH"></a>
### ERR_HTTP2_NESTED_PUSH
An attempt was made to initiate a new push stream from within a push stream.
Nested push streams are not permitted.
<a id="ERR_HTTP2_NO_SOCKET_MANIPULATION"></a> <a id="ERR_HTTP2_NO_SOCKET_MANIPULATION"></a>
### ERR_HTTP2_NO_SOCKET_MANIPULATION ### ERR_HTTP2_NO_SOCKET_MANIPULATION

View File

@ -1256,6 +1256,9 @@ Setting the weight of a push stream is not allowed in the `HEADERS` frame. Pass
a `weight` value to `http2stream.priority` with the `silent` option set to a `weight` value to `http2stream.priority` with the `silent` option set to
`true` to enable server-side bandwidth balancing between concurrent streams. `true` to enable server-side bandwidth balancing between concurrent streams.
Calling `http2stream.pushStream()` from within a pushed stream is not permitted
and will throw an error.
#### http2stream.respond([headers[, options]]) #### http2stream.respond([headers[, options]])
<!-- YAML <!-- YAML
added: v8.4.0 added: v8.4.0

View File

@ -566,6 +566,8 @@ E('ERR_HTTP2_INVALID_SETTING_VALUE',
E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed', Error); E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed', Error);
E('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK', E('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK',
'Maximum number of pending settings acknowledgements', Error); 'Maximum number of pending settings acknowledgements', Error);
E('ERR_HTTP2_NESTED_PUSH',
'A push stream cannot initiate another push stream.', Error);
E('ERR_HTTP2_NO_SOCKET_MANIPULATION', E('ERR_HTTP2_NO_SOCKET_MANIPULATION',
'HTTP/2 sockets should not be directly manipulated (e.g. read and written)', 'HTTP/2 sockets should not be directly manipulated (e.g. read and written)',
Error); Error);

View File

@ -48,6 +48,7 @@ const {
ERR_HTTP2_INVALID_SETTING_VALUE, ERR_HTTP2_INVALID_SETTING_VALUE,
ERR_HTTP2_INVALID_STREAM, ERR_HTTP2_INVALID_STREAM,
ERR_HTTP2_MAX_PENDING_SETTINGS_ACK, ERR_HTTP2_MAX_PENDING_SETTINGS_ACK,
ERR_HTTP2_NESTED_PUSH,
ERR_HTTP2_NO_SOCKET_MANIPULATION, ERR_HTTP2_NO_SOCKET_MANIPULATION,
ERR_HTTP2_OUT_OF_STREAMS, ERR_HTTP2_OUT_OF_STREAMS,
ERR_HTTP2_PAYLOAD_FORBIDDEN, ERR_HTTP2_PAYLOAD_FORBIDDEN,
@ -2159,6 +2160,8 @@ class ServerHttp2Stream extends Http2Stream {
pushStream(headers, options, callback) { pushStream(headers, options, callback) {
if (!this.pushAllowed) if (!this.pushAllowed)
throw new ERR_HTTP2_PUSH_DISABLED(); throw new ERR_HTTP2_PUSH_DISABLED();
if (this[kID] % 2 === 0)
throw new ERR_HTTP2_NESTED_PUSH();
const session = this[kSession]; const session = this[kSession];

View File

@ -22,6 +22,14 @@ server.on('stream', common.mustCall((stream, headers) => {
'x-push-data': 'pushed by server', 'x-push-data': 'pushed by server',
}); });
push.end('pushed by server data'); push.end('pushed by server data');
common.expectsError(() => {
push.pushStream({}, common.mustNotCall());
}, {
code: 'ERR_HTTP2_NESTED_PUSH',
type: Error
});
stream.end('test'); stream.end('test');
})); }));
} }