// This tests that invalid TLS options do not result in an uncaught exception // after an HTTPS proxy tunnel has been established. import * as common from '../common/index.mjs'; import assert from 'node:assert'; import { once } from 'events'; import fixtures from '../common/fixtures.js'; import { createProxyServer } from '../common/proxy-server.js'; if (!common.hasCrypto) common.skip('missing crypto'); // https must be dynamically imported so that builds without crypto support // can skip it. const { default: https } = await import('node:https'); const server = https.createServer({ cert: fixtures.readKey('agent8-cert.pem'), key: fixtures.readKey('agent8-key.pem'), }, common.mustNotCall()); server.on('error', common.mustNotCall()); server.listen(0); await once(server, 'listening'); const { proxy, logs } = createProxyServer(); proxy.listen(0); await once(proxy, 'listening'); const serverHost = `localhost:${server.address().port}`; // tls.connect() throws for these options while building the secure context, // before any handshake happens. const testCases = [ { options: { minVersion: 'definitely-invalid' }, code: 'ERR_TLS_INVALID_PROTOCOL_VERSION' }, { options: { ciphers: 123 }, code: 'ERR_INVALID_ARG_TYPE' }, { options: { secureProtocol: 'definitely-invalid' }, code: 'ERR_TLS_INVALID_PROTOCOL_METHOD' }, ]; for (const { options, code } of testCases) { const agent = new https.Agent({ ca: fixtures.readKey('fake-startcom-root-cert.pem'), proxyEnv: { HTTPS_PROXY: `http://localhost:${proxy.address().port}`, }, }); const req = https.get({ host: 'localhost', port: server.address().port, path: '/test', agent, ...options, }, common.mustNotCall()); const [err] = await once(req, 'error'); assert.strictEqual(err.code, code); agent.destroy(); } // Verify that the requests went through the proxy and the tunnel was established. const requests = logs.filter((log) => !('error' in log)); // The client resets the tunnel as soon as tls.connect() throws, which the // proxy may observe as an ECONNRESET while still relaying it. const errors = logs.filter((log) => 'error' in log && log.error.code !== 'ECONNRESET'); assert.deepStrictEqual(requests, testCases.map(() => ({ method: 'CONNECT', url: serverHost, headers: { 'host': serverHost, }, }))); assert.deepStrictEqual(errors, []); proxy.close(); server.close();