http2: fix FileHandle leak in respondWithFile

Ensure that the file handle is closed if header validation fails in
respondWithFile. This prevents ERR_INVALID_STATE errors where a
FileHandle object is closed during garbage collection.

PR-URL: https://github.com/nodejs/node/pull/61707
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
This commit is contained in:
sangwook authored and GitHub committed 2026-02-08 23:46:52 +00:00
1 parent 286828be01
commit f0be1c00da
2 files changed
+55

No files matched your search

+4
View File
@@ -2680,6 +2680,8 @@ function processRespondWithFD(self, fd, headers, offset = 0, length = -1,
try {
headersList = buildNgHeaderString(headers, assertValidPseudoHeaderResponse);
} catch (err) {
if (self.ownsFd)
tryClose(fd);
self.destroy(err);
return;
}
@@ -2693,6 +2695,8 @@ function processRespondWithFD(self, fd, headers, offset = 0, length = -1,
const ret = self[kHandle].respond(headersList, streamOptions);
if (ret < 0) {
if (self.ownsFd)
tryClose(fd);
self.destroy(new NghttpError(ret));
return;
}
@@ -0,0 +1,51 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const fixtures = require('../common/fixtures');
const assert = require('assert');
const http2 = require('http2');
const fs = require('fs');
const fname = fixtures.path('elipses.txt');
const server = http2.createServer();
server.on('stream', common.mustCall((stream) => {
const originalClose = fs.close;
let fdClosed = false;
fs.close = common.mustCall(function(fd, cb) {
fdClosed = true;
return originalClose.apply(this, arguments);
});
const headers = {
':method': 'GET',
'content-type': 'text/plain'
};
stream.respondWithFile(fname, headers);
stream.on('error', common.mustCall((err) => {
assert.strictEqual(err.code, 'ERR_HTTP2_INVALID_PSEUDOHEADER');
}));
stream.on('close', common.mustCall(() => {
fs.close = originalClose;
assert.strictEqual(fdClosed, true);
}));
}));
server.listen(0, common.mustCall(() => {
const client = http2.connect(`http://localhost:${server.address().port}`);
const req = client.request();
req.on('close', common.mustCall(() => {
client.close();
server.close();
}));
req.on('error', common.mustCall());
req.end();
}));