net: Defer reading until listeners could be added

Defer reading until user-land has a chance to add listeners. This
allows the TLS wrapper to listen for _tlsError and trigger a
clientError event if the socket already has data that could trigger.

Fixes: https://github.com/nodejs/io.js/issues/1114
PR-URL: https://github.com/nodejs/io.js/pull/1496
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
This commit is contained in:
James Hartig 2015-06-08 18:25:06 -04:00 committed by Brendan Ashworth
parent 7a3006efe4
commit 061342a500
3 changed files with 63 additions and 11 deletions

View File

@ -209,6 +209,20 @@ function onocspresponse(resp) {
this.emit('OCSPResponse', resp);
}
function initRead(tls, wrapped) {
// If we were destroyed already don't bother reading
if (!tls._handle)
return;
// Socket already has some buffered data - emulate receiving it
if (wrapped && wrapped._readableState && wrapped._readableState.length) {
var buf;
while ((buf = wrapped.read()) !== null)
tls._handle.receive(buf);
}
tls.read(0);
}
/**
* Provides a wrap of socket stream to do encrypted communication.
@ -257,7 +271,9 @@ function TLSSocket(socket, options) {
// starting the flow of the data
this.readable = true;
this.writable = true;
this.read(0);
// Read on next tick so the caller has a chance to setup listeners
process.nextTick(initRead, this, socket);
}
util.inherits(TLSSocket, net.Socket);
exports.TLSSocket = TLSSocket;
@ -416,13 +432,6 @@ TLSSocket.prototype._init = function(socket, wrap) {
if (options.handshakeTimeout > 0)
this.setTimeout(options.handshakeTimeout, this._handleTimeout);
// Socket already has some buffered data - emulate receiving it
if (socket && socket._readableState && socket._readableState.length) {
var buf;
while ((buf = socket.read()) !== null)
ssl.receive(buf);
}
if (socket instanceof net.Socket) {
this._parent = socket;

View File

@ -0,0 +1,46 @@
'use strict';
var common = require('../common');
var assert = require('assert');
if (!common.hasCrypto) {
console.log('1..0 # Skipped: missing crypto');
process.exit();
}
var tls = require('tls');
var fs = require('fs');
var net = require('net');
var bonkers = new Buffer(1024);
bonkers.fill(42);
var receivedError = false;
var options = {
key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'),
cert: fs.readFileSync(common.fixturesDir + '/keys/agent1-cert.pem')
};
var server = net.createServer(function(c) {
setTimeout(function() {
var s = new tls.TLSSocket(c, {
isServer: true,
secureContext: tls.createSecureContext(options)
});
s.on('_tlsError', function() {
receivedError = true;
});
s.on('close', function() {
server.close();
s.destroy();
});
}, 200);
}).listen(common.PORT, function() {
var c = net.connect({port: common.PORT}, function() {
c.write(bonkers);
});
});
process.on('exit', function() {
assert.ok(receivedError);
});

View File

@ -13,7 +13,6 @@ var net = require('net');
var sent = 'hello world';
var received = '';
var ended = 0;
var options = {
key: fs.readFileSync(common.fixturesDir + '/keys/agent1-key.pem'),
@ -32,7 +31,6 @@ var server = net.createServer(function(c) {
});
s.on('end', function() {
ended++;
server.close();
s.destroy();
});
@ -47,5 +45,4 @@ var server = net.createServer(function(c) {
process.on('exit', function() {
assert.equal(received, sent);
assert.equal(ended, 1);
});