'use strict'; const common = require('../common'); const fixtures = require('../common/fixtures'); if (!common.hasCrypto) common.skip('missing crypto'); const assert = require('assert'); const net = require('net'); const h2 = require('http2'); const tlsOptions = { key: fixtures.readKey('agent1-key.pem'), cert: fixtures.readKey('agent1-cert.pem'), ALPNProtocols: ['h2'] }; // Create a net server that upgrades sockets to HTTP/2 manually, handles the // request, and then shuts down via a short socket timeout and a longer H2 session // timeout. This is an unconventional way to shut down a session (the underlying // socket closing first) but it should work - critically, it shouldn't segfault // (as it did until Node v20.5.1). let serverRawSocket; let serverH2Session; const netServer = net.createServer((socket) => { serverRawSocket = socket; h2Server.emit('connection', socket); }); const h2Server = h2.createSecureServer(tlsOptions, (req, res) => { res.writeHead(200); res.end(); }); h2Server.on('session', (session) => { serverH2Session = session; }); netServer.listen(0, common.mustCall(() => { const proxyClient = h2.connect(`https://localhost:${netServer.address().port}`, { rejectUnauthorized: false }); proxyClient.on('error', () => {}); proxyClient.on('close', common.mustCall(() => { netServer.close(); })); const req = proxyClient.request({ ':method': 'GET', ':path': '/' }); req.on('error', () => {}); req.on('response', common.mustCall((response) => { assert.strictEqual(response[':status'], 200); // Asynchronously shut down the server's connections after the response, // but not in the order it typically expects: setTimeout(() => { serverRawSocket.destroy(); setTimeout(() => { serverH2Session.close(); }, 10); }, 10); })); }));