http2: submit RST_STREAM before emitting 'aborted'

Signed-off-by: lazerg <lazerg2@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/66314
Fixes: https://github.com/nodejs/node/issues/66306
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
This commit is contained in:
Lazizbek Ergashev authored and GitHub committed 2026-09-29 10:27:53 +00:00
1 parent 691cf6245c
commit 1f26576a3f
2 files changed
+40 -7

No files matched your search

+8 -7
View File
@@ -2153,14 +2153,7 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
stream.setTimeout(0);
stream.removeAllListeners('timeout');
// Emit 'aborted' if the user hadn't ended the writable yet. This is
// unusual and doesn't match 'error' but is deprecated & preserved for
// backward compat (DEP0207).
const { ending } = stream._writableState;
if (!ending && !stream.aborted) {
state.flags |= STREAM_FLAGS_ABORTED;
stream.emit('aborted');
}
if (rstStreamStatus !== kNoRstStream) {
// If the user already called .end() and writes are still draining,
@@ -2174,6 +2167,14 @@ function closeStream(stream, code, rstStreamStatus = kSubmitRstStream) {
}
}
// Emit 'aborted' if the user hadn't ended the writable yet. This is
// unusual and doesn't match 'error' but is deprecated & preserved for
// backward compat (DEP0207).
if (!ending && !stream.aborted) {
state.flags |= STREAM_FLAGS_ABORTED;
stream.emit('aborted');
}
if (type === NGHTTP2_SESSION_CLIENT) {
if (onClientStreamCloseChannel.hasSubscribers) {
onClientStreamCloseChannel.publish({ stream });
@@ -0,0 +1,32 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const http2 = require('http2');
const { NGHTTP2_CANCEL } = http2.constants;
const server = http2.createServer();
server.on('stream', common.mustCall((stream) => {
stream.respond();
stream.on('error', common.expectsError({
code: 'ERR_HTTP2_STREAM_ABORTED',
}));
stream.on('close', common.mustCall(() => {
assert.strictEqual(stream.rstCode, NGHTTP2_CANCEL);
server.close();
}));
}));
server.listen(0, common.mustCall(() => {
const client = http2.connect(`http://localhost:${server.address().port}`);
const req = client.request({ ':method': 'POST' });
req.on('aborted', common.mustCall(() => req.destroy()));
req.on('close', common.mustCall(() => client.close()));
req.on('response', common.mustCall(() => {
req.close(NGHTTP2_CANCEL);
}));
}));