From 4cce1b85afbe2e10956d663ff9ee646b7aeef769 Mon Sep 17 00:00:00 2001 From: koichik Date: Sun, 18 Dec 2011 02:09:16 +0900 Subject: [PATCH] tls: Fix node swallows openssl error on request Fixes #2308. Fixes #2246. --- doc/api/tls.markdown | 8 ++++ lib/tls.js | 15 +++++++ test/simple/test-https-invalid-key.js | 62 +++++++++++++++++++++++++++ test/simple/test-tls-invalid-key.js | 62 +++++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 test/simple/test-https-invalid-key.js create mode 100644 test/simple/test-tls-invalid-key.js diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown index ca60c658c1c..8db219008c8 100644 --- a/doc/api/tls.markdown +++ b/doc/api/tls.markdown @@ -237,6 +237,14 @@ server, you unauthorized connections may be accepted. SNI. +### Event: 'clientError' + +`function (exception) { }` + +When a client connection emits an 'error' event before secure connection is +established - it will be forwarded here. + + #### server.listen(port, [host], [callback]) Begin accepting connections on the specified `port` and `host`. If the diff --git a/lib/tls.js b/lib/tls.js index fc973efe3fa..b77dec43d18 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -720,6 +720,7 @@ SecurePair.prototype.maybeInitFinished = function() { SecurePair.prototype.destroy = function() { var self = this; + var error = this.ssl.error; if (!this._doneFlag) { this._doneFlag = true; @@ -735,6 +736,14 @@ SecurePair.prototype.destroy = function() { self.encrypted.emit('close'); self.cleartext.emit('close'); }); + + if (!this._secureEstablished) { + if (!error) { + error = new Error('socket hang up'); + error.code = 'ECONNRESET'; + } + this.emit('error', error); + } } }; @@ -904,6 +913,9 @@ function Server(/* [options], listener */) { } } }); + pair.on('error', function(err) { + self.emit('clientError', err); + }); }); if (listener) { @@ -1053,6 +1065,9 @@ exports.connect = function(port /* host, options, cb */) { cleartext.emit('secureConnect'); }); + pair.on('error', function(err) { + cleartext.emit('error', err); + }); cleartext._controlReleased = true; return cleartext; diff --git a/test/simple/test-https-invalid-key.js b/test/simple/test-https-invalid-key.js new file mode 100644 index 00000000000..82e05a2af9e --- /dev/null +++ b/test/simple/test-https-invalid-key.js @@ -0,0 +1,62 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +if (!process.versions.openssl) { + console.error('Skipping because node compiled without OpenSSL.'); + process.exit(0); +} + +var common = require('../common'); +var assert = require('assert'); +var https = require('https'); +var fs = require('fs'); +var path = require('path'); + +var options = { + key: fs.readFileSync(path.join(common.fixturesDir, 'keys/agent1-key.pem')), + cert: fs.readFileSync(path.join(common.fixturesDir, 'test_cert.pem')) +}; +var serverErrorHappened = false; +var clientErrorHappened = false; + +var server = https.Server(options, function(req, res) { + assert(false); +}); +server.on('clientError', function(err) { + serverErrorHappened = true; + common.debug('Server: ' + err); + server.close(); +}); + +server.listen(common.PORT, function() { + var req = https.get({port: common.PORT}, function(res) { + assert(false); + }); + req.on('error', function(err) { + clientErrorHappened = true; + common.debug('Client: ' + err); + }); +}); + +process.on('exit', function() { + assert(serverErrorHappened); + assert(clientErrorHappened); +}); diff --git a/test/simple/test-tls-invalid-key.js b/test/simple/test-tls-invalid-key.js new file mode 100644 index 00000000000..b4d842f2ef7 --- /dev/null +++ b/test/simple/test-tls-invalid-key.js @@ -0,0 +1,62 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +if (!process.versions.openssl) { + console.error('Skipping because node compiled without OpenSSL.'); + process.exit(0); +} + +var common = require('../common'); +var assert = require('assert'); +var tls = require('tls'); +var fs = require('fs'); +var path = require('path'); + +var options = { + key: fs.readFileSync(path.join(common.fixturesDir, 'keys/agent1-key.pem')), + cert: fs.readFileSync(path.join(common.fixturesDir, 'test_cert.pem')) +}; +var serverErrorHappened = false; +var clientErrorHappened = false; + +var server = tls.Server(options, function(socket) { + assert(false); +}); +server.on('clientError', function(err) { + serverErrorHappened = true; + common.debug('Server: ' + err); + server.close(); +}); + +server.listen(common.PORT, function() { + var client = tls.connect(common.PORT, function() { + assert(false); + }); + client.on('error', function(err) { + clientErrorHappened = true; + common.debug('Client: ' + err); + }); +}); + +process.on('exit', function() { + assert(serverErrorHappened); + assert(clientErrorHappened); +});