Skip to content

Commit 4a0b66e

Browse files
devm33juanarbol
authored andcommitted
http2: send RST code 8 on AbortController signal
Fixes: #47321 Refs: https://www.rfc-editor.org/rfc/rfc7540#section-7 PR-URL: #48573 Reviewed-By: Rafael Gonzaga <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Minwoo Jung <[email protected]>
1 parent a316808 commit 4a0b66e

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

lib/internal/http2/core.js

+11-4
Original file line numberDiff line numberDiff line change
@@ -2319,10 +2319,17 @@ class Http2Stream extends Duplex {
23192319
// this stream's close and destroy operations.
23202320
// Previously, this always overrode a successful close operation code
23212321
// NGHTTP2_NO_ERROR (0) with sessionCode because the use of the || operator.
2322-
const code = (err != null ?
2323-
(sessionCode || NGHTTP2_INTERNAL_ERROR) :
2324-
(this.closed ? this.rstCode : sessionCode)
2325-
);
2322+
let code = this.closed ? this.rstCode : sessionCode;
2323+
if (err != null) {
2324+
if (sessionCode) {
2325+
code = sessionCode;
2326+
} else if (err instanceof AbortError) {
2327+
// Enables using AbortController to cancel requests with RST code 8.
2328+
code = NGHTTP2_CANCEL;
2329+
} else {
2330+
code = NGHTTP2_INTERNAL_ERROR;
2331+
}
2332+
}
23262333
const hasHandle = handle !== undefined;
23272334

23282335
if (!this.closed)

test/parallel/test-http2-client-destroy.js

+29
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,32 @@ const { getEventListeners } = require('events');
285285
testH2ConnectAbort(false);
286286
testH2ConnectAbort(true);
287287
}
288+
289+
// Destroy ClientHttp2Stream with AbortSignal
290+
{
291+
const server = h2.createServer();
292+
const controller = new AbortController();
293+
294+
server.on('stream', common.mustCall((stream) => {
295+
stream.on('error', common.mustNotCall());
296+
stream.on('close', common.mustCall(() => {
297+
assert.strictEqual(stream.rstCode, h2.constants.NGHTTP2_CANCEL);
298+
server.close();
299+
}));
300+
controller.abort();
301+
}));
302+
server.listen(0, common.mustCall(() => {
303+
const client = h2.connect(`http://localhost:${server.address().port}`);
304+
client.on('close', common.mustCall());
305+
306+
const { signal } = controller;
307+
const req = client.request({}, { signal });
308+
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
309+
req.on('error', common.mustCall((err) => {
310+
assert.strictEqual(err.code, 'ABORT_ERR');
311+
assert.strictEqual(err.name, 'AbortError');
312+
client.close();
313+
}));
314+
req.on('close', common.mustCall());
315+
}));
316+
}

0 commit comments

Comments
 (0)