Skip to content

Commit 80342f6

Browse files
committedMay 22, 2015
tls: use .destroy(err) instead of destroy+emit
Emit errors using `.destroy(err)` instead of `.destroy()` and `.emit('error', err)`. Otherwise `close` event is emitted with the `error` argument set to `false`, even if the connection was torn down because of the error. See: nodejs/node#1119 PR-URL: nodejs/node#1711 Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
1 parent 2b1c01c commit 80342f6

File tree

2 files changed

+64
-14
lines changed

2 files changed

+64
-14
lines changed
 

‎lib/_tls_wrap.js

+22-14
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function onhandshakestart() {
3838
// callback to destroy the connection right now, it would crash and burn.
3939
setImmediate(function() {
4040
var err = new Error('TLS session renegotiation attack detected.');
41-
self._tlsError(err);
41+
self._emitTLSError(err);
4242
});
4343
}
4444
}
@@ -233,7 +233,7 @@ function TLSSocket(socket, options) {
233233
// Proxy for API compatibility
234234
this.ssl = this._handle;
235235

236-
this.on('error', this._tlsError);
236+
this.on('error', this._emitTLSError);
237237

238238
this._init(socket, wrap);
239239

@@ -363,16 +363,15 @@ TLSSocket.prototype._init = function(socket, wrap) {
363363

364364
// Destroy socket if error happened before handshake's finish
365365
if (!self._secureEstablished) {
366-
self._tlsError(err);
367-
self.destroy();
366+
self.destroy(self._tlsError(err));
368367
} else if (options.isServer &&
369368
rejectUnauthorized &&
370369
/peer did not return a certificate/.test(err.message)) {
371370
// Ignore server's authorization errors
372371
self.destroy();
373372
} else {
374373
// Throw error
375-
self._tlsError(err);
374+
self._emitTLSError(err);
376375
}
377376
};
378377

@@ -416,7 +415,7 @@ TLSSocket.prototype._init = function(socket, wrap) {
416415
// Assume `tls.connect()`
417416
if (wrap) {
418417
wrap.on('error', function(err) {
419-
self._tlsError(err);
418+
self._emitTLSError(err);
420419
});
421420
} else {
422421
assert(!socket);
@@ -472,20 +471,27 @@ TLSSocket.prototype.getTLSTicket = function getTLSTicket() {
472471
};
473472

474473
TLSSocket.prototype._handleTimeout = function() {
475-
this._tlsError(new Error('TLS handshake timeout'));
474+
this._emitTLSError(new Error('TLS handshake timeout'));
475+
};
476+
477+
TLSSocket.prototype._emitTLSError = function(err) {
478+
var e = this._tlsError(err);
479+
if (e)
480+
this.emit('error', e);
476481
};
477482

478483
TLSSocket.prototype._tlsError = function(err) {
479484
this.emit('_tlsError', err);
480485
if (this._controlReleased)
481-
this.emit('error', err);
486+
return err;
487+
return null;
482488
};
483489

484490
TLSSocket.prototype._releaseControl = function() {
485491
if (this._controlReleased)
486492
return false;
487493
this._controlReleased = true;
488-
this.removeListener('error', this._tlsError);
494+
this.removeListener('error', this._emitTLSError);
489495
return true;
490496
};
491497

@@ -717,7 +723,11 @@ function Server(/* [options], listener */) {
717723
});
718724

719725
var errorEmitted = false;
720-
socket.on('close', function() {
726+
socket.on('close', function(err) {
727+
// Closed because of error - no need to emit it twice
728+
if (err)
729+
return;
730+
721731
// Emit ECONNRESET
722732
if (!socket._controlReleased && !errorEmitted) {
723733
errorEmitted = true;
@@ -936,8 +946,7 @@ exports.connect = function(/* [port, host], options, cb */) {
936946
socket.authorizationError = verifyError.code || verifyError.message;
937947

938948
if (options.rejectUnauthorized) {
939-
socket.emit('error', verifyError);
940-
socket.destroy();
949+
socket.destroy(verifyError);
941950
return;
942951
} else {
943952
socket.emit('secureConnect');
@@ -957,8 +966,7 @@ exports.connect = function(/* [port, host], options, cb */) {
957966
socket._hadError = true;
958967
var error = new Error('socket hang up');
959968
error.code = 'ECONNRESET';
960-
socket.destroy();
961-
socket.emit('error', error);
969+
socket.destroy(error);
962970
}
963971
}
964972
socket.once('end', onHangUp);

‎test/parallel/test-tls-close-error.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict';
2+
3+
var assert = require('assert');
4+
var common = require('../common');
5+
6+
if (!common.hasCrypto) {
7+
console.log('1..0 # Skipped: missing crypto');
8+
process.exit();
9+
}
10+
var tls = require('tls');
11+
12+
var fs = require('fs');
13+
var net = require('net');
14+
15+
var errorCount = 0;
16+
var closeCount = 0;
17+
18+
var server = tls.createServer({
19+
key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'),
20+
cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem')
21+
}, function(c) {
22+
}).listen(common.PORT, function() {
23+
var c = tls.connect(common.PORT, function() {
24+
assert(false, 'should not be called');
25+
});
26+
27+
c.on('error', function(err) {
28+
errorCount++;
29+
});
30+
31+
c.on('close', function(err) {
32+
if (err)
33+
closeCount++;
34+
35+
server.close();
36+
});
37+
});
38+
39+
process.on('exit', function() {
40+
assert.equal(errorCount, 1);
41+
assert.equal(closeCount, 1);
42+
});

0 commit comments

Comments
 (0)
Please sign in to comment.