Skip to content

tls: deprecate newSession/resumeSession events #5774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions doc/api/tls.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ established it will be forwarded here.

### Event: 'newSession'

Stability: 0 - Deprecated: Use synchronous `newSession` option-callback of
[`tls.createServer`][] instead.

`function (sessionId, sessionData, callback) { }`

Emitted on creation of TLS session. May be used to store sessions in external
Expand Down Expand Up @@ -243,6 +246,9 @@ certificates.

### Event: 'resumeSession'

Stability: 0 - Deprecated: Use synchronous `resumeSession` option-callback of
[`tls.createServer`][] instead.

`function (sessionId, callback) { }`

Emitted when client wants to resume previous TLS session. Event listener may
Expand Down Expand Up @@ -898,6 +904,13 @@ automatically set as a listener for the [`'secureConnection'`][] event. The
SSL version 3. The possible values depend on your installation of
OpenSSL and are defined in the constant [SSL_METHODS][].

- `newSession`: A callback to invoke when creating new TLS session
(Signature: `newSession(sessionId, sessionData)`).

- `resumeSession`: A callback to invoke when client attempts to resume some
TLS session by id (Signature: `resumeSession(sessionId)`, should return
`undefined` or `Buffer` instance with `sessionData` from `newSession`).

Here is a simple example echo server:

```js
Expand Down
11 changes: 11 additions & 0 deletions lib/_tls_common.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,14 @@ exports.translatePeerCertificate = function translatePeerCertificate(c) {
}
return c;
};

exports.deprecateAsyncSessionAPI = function deprecateAsyncSessionAPI(server) {
const asyncSessionWarning = internalUtil.deprecate(() => {},
'server.on(\'newSession\')/server.on(\'resumeSession\') are deprecated.' +
' Please upgrade to synchronous API and pass these callbacks in ' +
'options.newSession (options.resumeSession).');
server.on('newListener', (type) => {
if (/^(new|resume)Session$/.test(type))
asyncSessionWarning();
});
};
29 changes: 24 additions & 5 deletions lib/_tls_wrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,16 @@ function loadSession(self, hello, cb) {
cb(null, ret);
}

if (hello.sessionId.length <= 0 ||
hello.tlsTicket ||
self.server &&
!self.server.emit('resumeSession', hello.sessionId, onSession)) {
if (hello.sessionId.length <= 0 || hello.tlsTicket) {
return cb(null);
}

assert(self.server);
if (self.server.onResumeSession) {
return onSession(null, self.server.onResumeSession(hello.sessionId));
}

if (!self.server.emit('resumeSession', hello.sessionId, onSession)) {
cb(null);
}
}
Expand Down Expand Up @@ -183,6 +189,12 @@ function onnewsession(key, session) {
var once = false;

this._newSessionPending = true;
if (this.server.onNewSession) {
this.server.onNewSession(key, session);
done();
return;
}

if (!this.server.emit('newSession', key, session, done))
done();

Expand Down Expand Up @@ -398,7 +410,9 @@ TLSSocket.prototype._init = function(socket, wrap) {
ssl.handshakes = 0;

if (this.server) {
if (this.server.listenerCount('resumeSession') > 0 ||
if (this.server.onNewSession ||
this.server.onResumeSession ||
this.server.listenerCount('resumeSession') > 0 ||
this.server.listenerCount('newSession') > 0) {
ssl.enableSessionCallbacks();
}
Expand Down Expand Up @@ -828,6 +842,8 @@ function Server(/* [options], listener */) {
if (listener) {
this.on('secureConnection', listener);
}

common.deprecateAsyncSessionAPI(this);
}

util.inherits(Server, net.Server);
Expand Down Expand Up @@ -902,6 +918,9 @@ Server.prototype.setOptions = function(options) {
.digest('hex')
.slice(0, 32);
}

if (options.newSession) this.onNewSession = options.newSession;
if (options.resumeSession) this.onResumeSession = options.resumeSession;
};

// SNI Contexts High-Level API
Expand Down
95 changes: 58 additions & 37 deletions test/parallel/test-tls-session-cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,7 @@ if (!common.hasCrypto) {
return;
}

doTest({ tickets: false }, function() {
doTest({ tickets: true }, function() {
console.error('all done');
});
});

function doTest(testOptions, callback) {
const doTest = (testOptions, callback) => {
var assert = require('assert');
var tls = require('tls');
var fs = require('fs');
Expand All @@ -38,8 +32,23 @@ function doTest(testOptions, callback) {
var resumeCount = 0;
var session;

var server = tls.createServer(options, function(cleartext) {
cleartext.on('error', function(er) {
if (testOptions.sync) {
options.newSession = (id, data) => {
assert.ok(!session);
session = { id: id, data: data };
};

options.resumeSession = (id) => {
++resumeCount;
assert.ok(session);
assert.equal(session.id.toString('hex'), id.toString('hex'));

return session.data;
};
}

var server = tls.createServer(options, (cleartext) => {
cleartext.on('error', (er) => {
// We're ok with getting ECONNRESET in this test, but it's
// timing-dependent, and thus unreliable. Any other errors
// are just failures, though.
Expand All @@ -49,27 +58,30 @@ function doTest(testOptions, callback) {
++requestCount;
cleartext.end();
});
server.on('newSession', function(id, data, cb) {
// Emulate asynchronous store
setTimeout(function() {
assert.ok(!session);
session = {
id: id,
data: data
};
cb();
}, 1000);
});
server.on('resumeSession', function(id, callback) {
++resumeCount;
assert.ok(session);
assert.equal(session.id.toString('hex'), id.toString('hex'));

// Just to check that async really works there
setTimeout(function() {
callback(null, session.data);
}, 100);
});

if (!testOptions.sync) {
server.on('newSession', (id, data, cb) => {
// Emulate asynchronous store
setTimeout(() => {
assert.ok(!session);
session = {
id: id,
data: data
};
cb();
}, 1000);
});
server.on('resumeSession', (id, callback) => {
++resumeCount;
assert.ok(session);
assert.equal(session.id.toString('hex'), id.toString('hex'));

// Just to check that async really works there
setTimeout(() => {
callback(null, session.data);
}, 100);
});
}

var args = [
's_client',
Expand All @@ -85,25 +97,25 @@ function doTest(testOptions, callback) {
if (common.isWindows)
args.push('-no_rand_screen');

server.listen(common.PORT, function() {
server.listen(common.PORT, () => {
var client = spawn(common.opensslCli, args, {
stdio: [ 0, 1, 'pipe' ]
stdio: [ 0, 'ignore', 'pipe' ]
});
var err = '';
client.stderr.setEncoding('utf8');
client.stderr.on('data', function(chunk) {
client.stderr.on('data', (chunk) => {
err += chunk;
});
client.on('exit', function(code) {
client.on('exit', (code) => {
console.error('done');
assert.equal(code, 0);
server.close(function() {
server.close(() => {
setTimeout(callback, 100);
});
});
});

process.on('exit', function() {
process.on('exit', () => {
if (testOptions.tickets) {
assert.equal(requestCount, 6);
assert.equal(resumeCount, 0);
Expand All @@ -114,4 +126,13 @@ function doTest(testOptions, callback) {
assert.equal(resumeCount, 5);
}
});
}
};

doTest({ tickets: false, sync: false }, () => {
doTest({ tickets: true, sync: false }, () => {
doTest({ tickets: false, sync: true }, () => {
console.error('all done');
});
});
});