'use strict'; const common = require('../common'); if (!common.hasCrypto) common.skip('missing crypto'); const fixtures = require('../common/fixtures'); const makeDuplexPair = require('../common/duplexpair'); const net = require('net'); const assert = require('assert'); const tls = require('tls'); tls.DEFAULT_MAX_VERSION = 'TLSv1.3'; // This test ensures that an instance of StreamWrap should emit "end" and // "close" when the socket on the other side call `destroy()` instead of // `end()`. // Refs: https://github.com/nodejs/node/issues/14605 const CONTENT = 'Hello World'; const tlsServer = tls.createServer( { key: fixtures.readKey('rsa_private.pem'), cert: fixtures.readKey('rsa_cert.crt'), ca: [fixtures.readKey('rsa_ca.crt')], }, (socket) => { socket.on('close', common.mustCall()); socket.write(CONTENT); socket.destroy(); socket.on('error', (err) => { // destroy() is sync, write() is async, whether write completes depends // on the protocol, it is not guaranteed by stream API. if (err.code === 'ERR_STREAM_DESTROYED') return; assert.ifError(err); }); }, ); const server = net.createServer((conn) => { conn.on('error', common.mustNotCall()); // Assume that we want to use data to determine what to do with connections. conn.once('data', common.mustCall((chunk) => { const { clientSide, serverSide } = makeDuplexPair(); serverSide.on('close', common.mustCall(() => { conn.destroy(); })); clientSide.pipe(conn); conn.pipe(clientSide); conn.on('close', common.mustCall(() => { clientSide.destroy(); })); clientSide.on('close', common.mustCall(() => { conn.destroy(); })); process.nextTick(() => { conn.unshift(chunk); }); tlsServer.emit('connection', serverSide); })); }); server.listen(0, () => { const port = server.address().port; const conn = tls.connect({ port, rejectUnauthorized: false }, () => { // Whether the server's write() completed before its destroy() is // indeterminate, but if data was written, we should receive it correctly. conn.on('data', (data) => { assert.strictEqual(data.toString('utf8'), CONTENT); }); conn.on('error', common.mustNotCall()); conn.on('close', common.mustCall(() => server.close())); }); });