http2: send RST code 8 on AbortController signal

Fixes: https://github.com/nodejs/node/issues/47321
Refs: https://www.rfc-editor.org/rfc/rfc7540#section-7
PR-URL: https://github.com/nodejs/node/pull/48573
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
This commit is contained in:
Devraj Mehta 2023-07-05 20:59:39 -04:00 committed by GitHub
parent c3ab184373
commit b5e16adb1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 4 deletions

View File

@ -2319,10 +2319,17 @@ class Http2Stream extends Duplex {
// this stream's close and destroy operations.
// Previously, this always overrode a successful close operation code
// NGHTTP2_NO_ERROR (0) with sessionCode because the use of the || operator.
const code = (err != null ?
(sessionCode || NGHTTP2_INTERNAL_ERROR) :
(this.closed ? this.rstCode : sessionCode)
);
let code = this.closed ? this.rstCode : sessionCode;
if (err != null) {
if (sessionCode) {
code = sessionCode;
} else if (err instanceof AbortError) {
// Enables using AbortController to cancel requests with RST code 8.
code = NGHTTP2_CANCEL;
} else {
code = NGHTTP2_INTERNAL_ERROR;
}
}
const hasHandle = handle !== undefined;
if (!this.closed)

View File

@ -285,3 +285,32 @@ const { getEventListeners } = require('events');
testH2ConnectAbort(false);
testH2ConnectAbort(true);
}
// Destroy ClientHttp2Stream with AbortSignal
{
const server = h2.createServer();
const controller = new AbortController();
server.on('stream', common.mustCall((stream) => {
stream.on('error', common.mustNotCall());
stream.on('close', common.mustCall(() => {
assert.strictEqual(stream.rstCode, h2.constants.NGHTTP2_CANCEL);
server.close();
}));
controller.abort();
}));
server.listen(0, common.mustCall(() => {
const client = h2.connect(`http://localhost:${server.address().port}`);
client.on('close', common.mustCall());
const { signal } = controller;
const req = client.request({}, { signal });
assert.strictEqual(getEventListeners(signal, 'abort').length, 1);
req.on('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'ABORT_ERR');
assert.strictEqual(err.name, 'AbortError');
client.close();
}));
req.on('close', common.mustCall());
}));
}