diff options
author | Ben Noordhuis <info@bnoordhuis.nl> | 2013-05-30 01:12:11 +0400 |
---|---|---|
committer | Ben Noordhuis <info@bnoordhuis.nl> | 2013-05-30 01:12:11 +0400 |
commit | 28659aba37fc9136dad6181306696ce4a6d6ba3f (patch) | |
tree | 4e99c61affcf631f37c99d687f49a9a0c45d0247 /lib/tls.js | |
parent | ba048e72b02e17f0c73e0dcb7d37e76a03327c5a (diff) | |
parent | 9826b1549396ed05011d523ab5bf7a344b8cb8b6 (diff) |
Merge remote-tracking branch 'origin/v0.10'
Conflicts:
deps/uv/ChangeLog
deps/uv/src/unix/stream.c
deps/uv/src/version.c
lib/tls.js
Diffstat (limited to 'lib/tls.js')
-rw-r--r-- | lib/tls.js | 102 |
1 files changed, 75 insertions, 27 deletions
diff --git a/lib/tls.js b/lib/tls.js index 4f170324b9a..92ec579fb97 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -250,6 +250,8 @@ function CryptoStream(pair, options) { this._pendingCallback = null; this._doneFlag = false; this._retryAfterPartial = false; + this._halfRead = false; + this._sslOutCb = null; this._resumingSession = false; this._reading = true; this._destroyed = false; @@ -278,8 +280,14 @@ function onCryptoStreamFinish() { // NOTE: first call checks if client has sent us shutdown, // second call enqueues shutdown into the BIO. if (this.pair.ssl.shutdown() !== 1) { + if (this.pair.ssl && this.pair.ssl.error) + return this.pair.error(); + this.pair.ssl.shutdown(); } + + if (this.pair.ssl && this.pair.ssl.error) + return this.pair.error(); } } else { debug('encrypted.onfinish'); @@ -309,6 +317,19 @@ function onCryptoStreamEnd() { } +// NOTE: Called once `this._opposite` is set. +CryptoStream.prototype.init = function init() { + var self = this; + this._opposite.on('sslOutEnd', function() { + if (self._sslOutCb) { + var cb = self._sslOutCb; + self._sslOutCb = null; + cb(null); + } + }); +}; + + CryptoStream.prototype._write = function write(data, encoding, cb) { assert(this._pending === null); @@ -337,28 +358,36 @@ CryptoStream.prototype._write = function write(data, encoding, cb) { return cb(this.pair.error(true)); } + // Whole buffer was written + if (written === data.length) { + if (this === this.pair.cleartext) { + debug('cleartext.write succeed with ' + written + ' bytes'); + } else { + debug('encrypted.write succeed with ' + written + ' bytes'); + } + + // Invoke callback only when all data read from opposite stream + if (this._opposite._halfRead) { + assert(this._sslOutCb === null); + this._sslOutCb = cb; + } else { + cb(null); + } + } + // Force SSL_read call to cycle some states/data inside OpenSSL this.pair.cleartext.read(0); // Cycle encrypted data - if (this.pair.encrypted._internallyPendingBytes()) { + if (this.pair.encrypted._internallyPendingBytes()) this.pair.encrypted.read(0); - } // Get NPN and Server name when ready this.pair.maybeInitFinished(); - // Whole buffer was written if (written === data.length) { - if (this === this.pair.cleartext) { - debug('cleartext.write succeed with %d bytes', data.length); - } else { - debug('encrypted.write succeed with %d bytes', data.length); - } - - return cb(null); - } - if (written !== 0 && written !== -1) { + return; + } else if (written !== 0 && written !== -1) { assert(!this._retryAfterPartial); this._retryAfterPartial = true; this._write(data.slice(written), encoding, cb); @@ -460,25 +489,42 @@ CryptoStream.prototype._read = function read(size) { this._opposite._done(); // EOF - return this.push(null); + this.push(null); + } else { + // Bail out + this.push(''); } - - // Bail out - return this.push(''); + } else { + // Give them requested data + if (this.ondata) { + var self = this; + this.ondata(pool, start, start + bytesRead); + + // Consume data automatically + // simple/test-https-drain fails without it + process.nextTick(function() { + self.read(bytesRead); + }); + } + this.push(pool.slice(start, start + bytesRead)); } - // Give them requested data - if (this.ondata) { - var self = this; - this.ondata(pool, start, start + bytesRead); + // Let users know that we've some internal data to read + var halfRead = this._internallyPendingBytes() !== 0; - // Consume data automatically - // simple/test-https-drain fails without it - process.nextTick(function() { - self.read(bytesRead); - }); + // Smart check to avoid invoking 'sslOutEnd' in the most of the cases + if (this._halfRead !== halfRead) { + this._halfRead = halfRead; + + // Notify listeners about internal data end + if (this === this.pair.cleartext) { + debug('cleartext.sslOutEnd'); + } else { + debug('encrypted.sslOutEnd'); + } + + this.emit('sslOutEnd'); } - return this.push(pool.slice(start, start + bytesRead)); }; @@ -590,7 +636,7 @@ CryptoStream.prototype.destroySoon = function(err) { if (this.writable) this.end(); - if (this._writableState.finished) + if (this._writableState.finished && this._opposite._ended) this.destroy(); else this.once('finish', this.destroy); @@ -871,6 +917,8 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized, /* Let streams know about each other */ this.cleartext._opposite = this.encrypted; this.encrypted._opposite = this.cleartext; + this.cleartext.init(); + this.encrypted.init(); process.nextTick(function() { /* The Connection may be destroyed by an abort call */ |