Files
node/test/parallel/test-http2-compat-serverresponse-createpushresponse-refused.js
Matteo Collina 4830c1180c http2: handle errors on compat push response streams
`response.createPushResponse()` wrapped the pushed stream in an
`Http2ServerResponse` without attaching an 'error' listener. Request
streams get one from `Http2ServerRequest`, but pushed streams have no
request, so a peer refusing the push with a non-clean RST_STREAM code
(e.g. REFUSED_STREAM) before the response finished emitted an unhandled
'error' on `response.stream` unless the application listened on it.

Attach `onStreamError` to the pushed stream before invoking the
callback, and make `onStreamError` tolerate the `null` request that
core sets on every stream.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/67053
Reviewed-By: Tim Perry <pimterry@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-11-05 21:54:08 +00:00

49 lines
1.5 KiB
JavaScript

'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
// A client refusing a push created through the compat API with
// RST_STREAM(REFUSED_STREAM) must not crash the server with an unhandled
// 'error' event on the pushed stream.
const assert = require('assert');
const http2 = require('http2');
const server = http2.createServer(common.mustCall((req, res) => {
res.createPushResponse({ ':path': '/style.css' }, common.mustSucceed((pushRes) => {
pushRes.on('close', common.mustCall());
pushRes.setHeader('content-type', 'text/css');
pushRes.end('body { color: red }');
}));
res.end('hello');
}));
server.listen(0, common.mustCall(() => {
// A zero initial window keeps the pushed body from completing before the
// client refuses it, so the server sees a peer reset with its writable
// side still pending.
const client = http2.connect(`http://localhost:${server.address().port}`, {
settings: { initialWindowSize: 0 },
});
client.on('stream', common.mustCall((pushed) => {
pushed.on('error', common.expectsError({
code: 'ERR_HTTP2_STREAM_ERROR',
}));
pushed.close(http2.constants.NGHTTP2_REFUSED_STREAM);
// Reopen the window so the main response can complete.
client.settings({ initialWindowSize: 65535 });
}));
const req = client.request({ ':path': '/' });
req.resume();
req.on('close', common.mustCall(() => {
assert.strictEqual(req.rstCode, http2.constants.NGHTTP2_NO_ERROR);
client.close();
server.close();
}));
req.end();
}));