Skip to content

Commit 24461fe

Browse files
committed
http2: clear the session timeout before marking it destroyed
closeSession() set SESSION_FLAGS_DESTROYED and then called session.setTimeout(0). setStreamTimeout() returns early when the session is destroyed, so the idle timer stayed armed and retained the session until the server timeout fired. Clear the timeout and remove its listeners before setting the destroyed flag. Fixes: #66885 Signed-off-by: huang <13165998033@163.com>
1 parent ef63226 commit 24461fe

2 files changed

Lines changed: 38 additions & 3 deletions

File tree

‎lib/internal/http2/core.js‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,13 +1303,16 @@ function closeSession(session, code, error) {
13031303
debugSessionObj(session, 'start closing/destroying', error);
13041304

13051305
const state = session[kState];
1306-
state.flags |= SESSION_FLAGS_DESTROYED;
1307-
state.destroyCode = code;
13081306

1309-
// Clear timeout and remove timeout listeners.
1307+
// Clear timeout and remove timeout listeners before marking the session
1308+
// destroyed: setTimeout() is a no-op once destroyed, so the idle timer
1309+
// would otherwise stay armed and retain the session.
13101310
session.setTimeout(0);
13111311
session.removeAllListeners('timeout');
13121312

1313+
state.flags |= SESSION_FLAGS_DESTROYED;
1314+
state.destroyCode = code;
1315+
13131316
const socket = session[kSocket];
13141317
const handle = session[kHandle];
13151318

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
const assert = require('assert');
7+
const http2 = require('http2');
8+
9+
// A destroyed session must not keep its idle timer armed: setTimeout() is a
10+
// no-op once the session is marked destroyed, so closeSession() has to clear
11+
// the timer first.
12+
const server = http2.createServer();
13+
server.setTimeout(30_000, common.mustNotCall());
14+
15+
server.on('session', common.mustCall((session) => {
16+
session.on('close', common.mustCall(() => {
17+
assert.strictEqual(session.timeout, 0);
18+
server.close();
19+
}));
20+
}));
21+
22+
server.on('stream', common.mustCall((stream) => {
23+
stream.respond({ ':status': 200 });
24+
stream.end('ok');
25+
}));
26+
27+
server.listen(0, common.mustCall(() => {
28+
const client = http2.connect(`http://localhost:${server.address().port}`);
29+
const req = client.request();
30+
req.resume();
31+
req.on('end', common.mustCall(() => client.close()));
32+
}));

0 commit comments

Comments
 (0)