Skip to content

Commit

Permalink
http2: Abort immediately if passed an already aborted signal
Browse files Browse the repository at this point in the history
- Also add test to that effect
  • Loading branch information
MadaraUchiha committed Nov 21, 2020
1 parent 3d5177d commit 9aca7c4
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 5 deletions.
14 changes: 9 additions & 5 deletions lib/internal/http2/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -1726,11 +1726,15 @@ class ClientHttp2Session extends Http2Session {
const { signal } = options;
if (signal) {
validateAbortSignal(signal, 'options.signal');
const listener = () => stream.destroy(new AbortError());
signal.addEventListener('abort', listener);
stream.once('close', () => {
signal.removeEventListener('abort', listener);
});
const aborter = () => stream.destroy(new AbortError());
if (signal.aborted) {
aborter();
} else {
signal.addEventListener('abort', aborter);
stream.once('close', () => {
signal.removeEventListener('abort', aborter);
});
}
}

const onConnect = FunctionPrototypeBind(requestOnConnect,
Expand Down
35 changes: 35 additions & 0 deletions test/parallel/test-http2-client-destroy.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,38 @@ const Countdown = require('../common/countdown');
assert.strictEqual(req.destroyed, true);
}));
}
// Pass an already destroyed signal to abort immediately.
{
const server = h2.createServer();
const controller = new AbortController();

server.on('stream', common.mustNotCall());
server.listen(0, common.mustCall(() => {
const client = h2.connect(`http://localhost:${server.address().port}`);
client.on('close', common.mustCall());

const { signal } = controller;
controller.abort();

assert.strictEqual(signal[kEvents].get('abort'), undefined);

client.on('error', common.mustCall(() => {
// After underlying stream dies, signal listener detached
assert.strictEqual(signal[kEvents].get('abort'), undefined);
}));

const req = client.request({}, { signal });
// Signal already aborted, so no event listener attached.
assert.strictEqual(signal[kEvents].get('abort'), undefined);

assert.strictEqual(req.aborted, false);
// Destroyed on same tick as request made
assert.strictEqual(req.destroyed, true);

req.on('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'ABORT_ERR');
assert.strictEqual(err.name, 'AbortError');
}));
req.on('close', common.mustCall(() => server.close()));
}));
}

0 comments on commit 9aca7c4

Please sign in to comment.