-
Notifications
You must be signed in to change notification settings - Fork 29.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tls: ensure TLS Sockets are closed if the underlying wrap closes
This fixes a potential segfault, among various other likely-related issues, which all occur because TLSSockets were not informed if their underlying stream was closed in many cases. This also significantly modifies an existing TLS test. With this change in place, that test no longer works, as it tries to mess with internals to trigger a race, and those internals are now cleaned up earlier. This test has been simplified to a more general TLS shutdown test. PR-URL: #49327 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
- Loading branch information
Showing
3 changed files
with
91 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
'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('close', common.mustCall(() => { | ||
netServer.close(); | ||
})); | ||
|
||
const req = proxyClient.request({ | ||
':method': 'GET', | ||
':path': '/' | ||
}); | ||
|
||
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); | ||
})); | ||
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters