diff options
Diffstat (limited to 'test/tls-session-reuse.js')
-rw-r--r-- | test/tls-session-reuse.js | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/test/tls-session-reuse.js b/test/tls-session-reuse.js new file mode 100644 index 0000000..ab012f1 --- /dev/null +++ b/test/tls-session-reuse.js @@ -0,0 +1,185 @@ +'use strict' + +const { readFileSync } = require('fs') +const { join } = require('path') +const https = require('https') +const crypto = require('crypto') +const { test, teardown } = require('tap') +const { Client, Pool } = require('..') +const { kSocket } = require('../lib/core/symbols') +const { nodeMajor } = require('../lib/core/util') + +const options = { + key: readFileSync(join(__dirname, 'fixtures', 'key.pem'), 'utf8'), + cert: readFileSync(join(__dirname, 'fixtures', 'cert.pem'), 'utf8') +} +const ca = readFileSync(join(__dirname, 'fixtures', 'ca.pem'), 'utf8') + +test('A client should disable session caching', { + skip: nodeMajor < 11 // tls socket session event has been added in Node 11. Cf. https://nodejs.org/api/tls.html#tls_event_session +}, t => { + const clientSessions = {} + let serverRequests = 0 + + t.test('Prepare request', t => { + t.plan(3) + const server = https.createServer(options, (req, res) => { + if (req.url === '/drop-key') { + server.setTicketKeys(crypto.randomBytes(48)) + } + serverRequests++ + res.end() + }) + + server.listen(0, function () { + const tls = { + ca, + rejectUnauthorized: false, + servername: 'agent1' + } + const client = new Client(`https://localhost:${server.address().port}`, { + pipelining: 0, + tls, + maxCachedSessions: 0 + }) + + t.teardown(() => { + client.close() + server.close() + }) + + const queue = [{ + name: 'first', + method: 'GET', + path: '/' + }, { + name: 'second', + method: 'GET', + path: '/' + }] + + function request () { + const options = queue.shift() + if (options.ciphers) { + // Choose different cipher to use different cache entry + tls.ciphers = options.ciphers + } else { + delete tls.ciphers + } + client.request(options, (err, data) => { + t.error(err) + clientSessions[options.name] = client[kSocket].getSession() + data.body.resume().on('end', () => { + if (queue.length !== 0) { + return request() + } + t.pass() + }) + }) + } + request() + }) + }) + + t.test('Verify cached sessions', t => { + t.plan(2) + t.equal(serverRequests, 2) + t.not( + clientSessions.first.toString('hex'), + clientSessions.second.toString('hex') + ) + }) + + t.end() +}) + +test('A pool should be able to reuse TLS sessions between clients', { + skip: nodeMajor < 11 // tls socket session event has been added in Node 11. Cf. https://nodejs.org/api/tls.html#tls_event_session +}, t => { + let serverRequests = 0 + + const REQ_COUNT = 10 + const ASSERT_PERFORMANCE_GAIN = false + + t.test('Prepare request', t => { + t.plan(2 + 1 + (ASSERT_PERFORMANCE_GAIN ? 1 : 0)) + const server = https.createServer(options, (req, res) => { + serverRequests++ + res.end() + }) + + let numSessions = 0 + const sessions = [] + + server.listen(0, async () => { + const poolWithSessionReuse = new Pool(`https://localhost:${server.address().port}`, { + pipelining: 0, + connections: 100, + maxCachedSessions: 1, + tls: { + ca, + rejectUnauthorized: false, + servername: 'agent1' + } + }) + const poolWithoutSessionReuse = new Pool(`https://localhost:${server.address().port}`, { + pipelining: 0, + connections: 100, + maxCachedSessions: 0, + tls: { + ca, + rejectUnauthorized: false, + servername: 'agent1' + } + }) + + poolWithSessionReuse.on('connect', (url, targets) => { + const y = targets[1][kSocket].getSession() + if (sessions.some(x => x.equals(y))) { + return + } + sessions.push(y) + numSessions++ + }) + + t.teardown(() => { + poolWithSessionReuse.close() + poolWithoutSessionReuse.close() + server.close() + }) + + function request (pool, expectTLSSessionCache) { + return new Promise((resolve, reject) => { + pool.request({ + method: 'GET', + path: '/' + }, (err, data) => { + if (err) return reject(err) + data.body.resume().on('end', resolve) + }) + }) + } + + async function runRequests (pool, numIterations, expectTLSSessionCache) { + const requests = [] + // For the session reuse, we first need one client to connect to receive a valid tls session to reuse + await request(pool, false) + while (numIterations--) { + requests.push(request(pool, expectTLSSessionCache)) + } + return await Promise.all(requests) + } + + await runRequests(poolWithoutSessionReuse, REQ_COUNT, false) + await runRequests(poolWithSessionReuse, REQ_COUNT, true) + + t.equal(numSessions, 2) + t.equal(serverRequests, 2 + REQ_COUNT * 2) + t.pass() + }) + }) + + t.end() +}) + +teardown(() => process.exit()) |