summaryrefslogtreecommitdiffstats
path: root/test/tls-session-reuse.js
diff options
context:
space:
mode:
Diffstat (limited to 'test/tls-session-reuse.js')
-rw-r--r--test/tls-session-reuse.js185
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())