From 4a2792cd2f86403a71edf65d82600b6aad5713bf Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Mon, 9 Dec 2013 19:47:55 +0400 Subject: [PATCH] tls: emit 'end' on .receivedShutdown NOTE: Also removed `.receivedShutdown` method of `Connection` it wasn't documented anywhere, and was rewritten with `true` after receiving `close_notify`. fix #6638 --- lib/tls.js | 13 +++++-- src/node_crypto.cc | 15 ------- src/node_crypto.h | 1 - test/simple/test-tls-close-notify.js | 58 ++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 test/simple/test-tls-close-notify.js diff --git a/lib/tls.js b/lib/tls.js index ab2704445f9bfb..5d04da59fe7430 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -486,16 +486,21 @@ CryptoStream.prototype._read = function read(size) { if (bytesRead === 0) { // EOF when cleartext has finished and we have nothing to read - if (this._opposite._finished && this._internallyPendingBytes() === 0) { + if (this._opposite._finished && this._internallyPendingBytes() === 0 || + this.pair.ssl && this.pair.ssl.receivedShutdown) { // Perform graceful shutdown this._done(); // No half-open, sorry! - if (this === this.pair.cleartext) + if (this === this.pair.cleartext) { this._opposite._done(); - // EOF - this.push(null); + // EOF + this.push(null); + } else if (!this.pair.ssl || !this.pair.ssl.receivedShutdown) { + // EOF + this.push(null); + } } else { // Bail out this.push(''); diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 3e77918abb94ff..87025dd6b760cc 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -1022,7 +1022,6 @@ void Connection::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "getCurrentCipher", Connection::GetCurrentCipher); NODE_SET_PROTOTYPE_METHOD(t, "start", Connection::Start); NODE_SET_PROTOTYPE_METHOD(t, "shutdown", Connection::Shutdown); - NODE_SET_PROTOTYPE_METHOD(t, "receivedShutdown", Connection::ReceivedShutdown); NODE_SET_PROTOTYPE_METHOD(t, "close", Connection::Close); #ifdef OPENSSL_NPN_NEGOTIATED @@ -1766,20 +1765,6 @@ Handle Connection::Shutdown(const Arguments& args) { } -Handle Connection::ReceivedShutdown(const Arguments& args) { - HandleScope scope; - - Connection *ss = Connection::Unwrap(args); - - if (ss->ssl_ == NULL) return False(); - int r = SSL_get_shutdown(ss->ssl_); - - if (r & SSL_RECEIVED_SHUTDOWN) return True(); - - return False(); -} - - Handle Connection::IsInitFinished(const Arguments& args) { HandleScope scope; diff --git a/src/node_crypto.h b/src/node_crypto.h index 01a052855aac18..e4c3cfb3927b15 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -186,7 +186,6 @@ class Connection : ObjectWrap { static v8::Handle VerifyError(const v8::Arguments& args); static v8::Handle GetCurrentCipher(const v8::Arguments& args); static v8::Handle Shutdown(const v8::Arguments& args); - static v8::Handle ReceivedShutdown(const v8::Arguments& args); static v8::Handle Start(const v8::Arguments& args); static v8::Handle Close(const v8::Arguments& args); diff --git a/test/simple/test-tls-close-notify.js b/test/simple/test-tls-close-notify.js new file mode 100644 index 00000000000000..95fa65320d2a52 --- /dev/null +++ b/test/simple/test-tls-close-notify.js @@ -0,0 +1,58 @@ +// 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 assert = require('assert'); +var fs = require('fs'); +var net = require('net'); +var tls = require('tls'); + +var common = require('../common'); + +var ended = 0; + +var server = tls.createServer({ + key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'), + cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem') +}, function(c) { + // Send close-notify without shutting down TCP socket + if (c.pair.ssl.shutdown() !== 1) + c.pair.ssl.shutdown(); +}).listen(common.PORT, function() { + var c = tls.connect(common.PORT, { + rejectUnauthorized: false + }, function() { + // Ensure that we receive 'end' event anyway + c.on('end', function() { + ended++; + c.destroy(); + server.close(); + }); + }); +}); + +process.on('exit', function() { + assert.equal(ended, 1); +});