add server agent

This commit is contained in:
avwo
2015-07-14 08:59:21 +08:00
parent c64b7f0fd2
commit 0a01e514bc
5 changed files with 130 additions and 59 deletions
+16 -7
View File
@@ -21,7 +21,7 @@ var CWD = {cwd: HTTPS_DIR};
var ROOT_KEY_PATH = path.join(HTTPS_DIR, 'root.key');
var ROOT_CRT_PATH = path.join(HTTPS_DIR, 'root.crt');
var HOSTNAME_RE = /^[.\-\w]+$/;
var CREATE_TIMEOUT = 10000;
var CREATE_TIMEOUT = 16000;
var existsRootCA, rootCAPromise;
var cache = {};
@@ -31,8 +31,13 @@ util.mkdir(HTTPS_DIR);
util.mkdir(CERTS_DIR);
function getCert(hostname){
return cache[hostname] || DEFAULT_CERT_CTX;
var hostname = cache[hostname];
return hostname && hostname.cert || DEFAULT_CERT;
}
function getCertContext(hostname) {
var hostname = cache[hostname];
return hostname && hostname.context || DEFAULT_CERT_CTX;
}
function createCert(hostname, callback) {
@@ -64,10 +69,13 @@ function createCert(hostname, callback) {
defer.reject(err);
}
cache[hostname] = createSecureContext({
key: keyBuffer,
cert: crtBuffer
});
cache[hostname] = {
context: createSecureContext({
key: keyBuffer,
cert: crtBuffer
}),
cert: [keyBuffer, crtBuffer]
};
defer.resolve();
};
@@ -197,4 +205,5 @@ function exec(args, callback) {
exports.getRootCA = getRootCA;
exports.createCert = createCert;
exports.getCert = getCert;
exports.getCertContext = getCertContext;
exports.clear = clear;
+22 -48
View File
@@ -8,11 +8,11 @@ var util = require('../../util');
var rules = require('../rules');
var parseReq = require('../proxy/parse-req');
var cert = require('./cert');
var ServerAgent = require('./server-agent'); //TODO 放到公共地方,可以destroy
var serverAgent = new ServerAgent();
var DEFAULT_CERT = cert.DEFAULT_CERT;
var LOCALHOST = '127.0.0.1';
var config, app;
var d = require('domain').create()
.on('error', util.noop);
function getFullUrl(socket, wss) {
return (wss ? 'wss:' : 'ws:') + '//' + socket.headers.host + socket.url;
@@ -67,12 +67,10 @@ function handleWebsocket(socket, wss, callback) {
}
if (wss) {
d.run(function() {//TODO 看下具体原因,为什么会抛出异常
reqSocket = tls.connect({
rejectUnauthorized: false,
socket: proxySocket
}, pipeData);
});
reqSocket = tls.connect({
rejectUnauthorized: false,
socket: proxySocket
}, pipeData);
} else {
reqSocket = proxySocket;
pipeData();
@@ -103,13 +101,11 @@ function handleWebsocket(socket, wss, callback) {
reqEmitter.emit('send');
var isWss = options.protocol == 'wss';
d.run(function() {//TODO 看下具体原因,为什么会抛出异常
reqSocket = (isWss ? tls : net).connect({
rejectUnauthorized: false,
host: ip,
port: options.port || (isWss ? 443 : 80)
}, pipeData);
});
reqSocket = (isWss ? tls : net).connect({
rejectUnauthorized: false,
host: ip,
port: options.port || (isWss ? 443 : 80)
}, pipeData);
}, true);
function pipeData() {
@@ -144,10 +140,11 @@ function handleWebsocket(socket, wss, callback) {
}
}
exports.dispatch = function dispatch(socket, hostname) {
module.exports = function dispatch(socket, hostname, _app) {
var reqSocket, buffer;
var content = '';
app = _app;
config = app.config;
function destroy() {
socket.destroy();
reqSocket && reqSocket.destroy();
@@ -188,8 +185,8 @@ exports.dispatch = function dispatch(socket, hostname) {
buffer = null;
} else {
cert.createCert(hostname, function(err) {
d.run(function() {//TODO 看下具体原因,为什么会抛出异常
reqSocket = net.connect(config.tlsport, LOCALHOST, function() {
serverAgent.createServer(hostname, handleTlsSocket, function(port) {
reqSocket = net.connect(port, LOCALHOST, function() {
reqSocket.write(buffer);
reqSocket.pipe(socket).pipe(reqSocket);
buffer = null;
@@ -235,38 +232,15 @@ function handleTlsSocket(socket) {
});
} else {
//https
d.run(function() {//TODO 看下具体原因,为什么会抛出异常
reqSocket = net.connect(config.port, LOCALHOST, function() {
headers[util.HTTPS_FIELD] = 1;
reqSocket.write(socket.getBuffer(headers));
socket.pipe(reqSocket).pipe(socket);
});
abortIfUnavailable(reqSocket);
});
reqSocket = net.connect(config.port, LOCALHOST, function() {
headers[util.HTTPS_FIELD] = 1;
reqSocket.write(socket.getBuffer(headers));
socket.pipe(reqSocket).pipe(socket);
});
abortIfUnavailable(reqSocket);
}
}, true);
}
exports.createServer = function createServer(_app) {
app = _app;
config = app.config;
d.run(function() {
var server = tls.createServer({
SNICallback: function(hostname, callback) {
if (typeof callback != 'function') {
return cert.getCert(hostname);
}
callback(null, cert.getCert(hostname));
},
key: DEFAULT_CERT[0],
cert: DEFAULT_CERT[1]
}, handleTlsSocket)
.listen(config.tlsport, 'localhost')
.on('error', util.noop)
.on('clientError', util.noop);
});
};
+89
View File
@@ -0,0 +1,89 @@
var tls = require('tls');
var Q = require('q');
var cert = require('./cert');
var MAX_SERVERS = 256;
var MAX_PORT = 60000;
var curPort = 50000;
function getServer(options, secureConnectionListener, callback) {
if (curPort > MAX_PORT) {
curPort = MIN_PORT = 40000;
}
var port = curPort++;
var server = tls.createServer(options, secureConnectionListener);
server.on('error', function() {
port = 0;
getServer(options, callback);
});
server.listen(port, 'localhost', function() {
port && callback(port);
});
}
function ServerAgent() {
this._cache = {};
this._serverCount = 0;
}
var proto = ServerAgent.prototype;
proto.createServer = function createServer(hostname, secureConnectionListener, callback) {
var self = this;
var promise = self._cache[hostname];
var defer;
if (!promise) {
defer = Q.defer();
self._cache[hostname] = promise = defer.promise;
}
promise.done(callback);
if (!defer) {
return ;
}
var certs = cert.getCert();
self.freeServer();
getServer({
key: certs[0],
cert: certs[1]
}, secureConnectionListener,
defer.resolve.bind(defer));
self._serverCount++;
return self;
};
proto.freeServer = function() {
if (this._serverCount < MAX_SERVERS) {
return;
}
var cache = this._cache;
for (var i in cache) {
var server = cache[i];
if (!server.connections) {
delete cache[i];
server.close();
if (--this._serverCount < MAX_SERVERS) {
return;
}
}
}
};
proto.destroy = function destroy() {
var cache = this._cache;
for (var i in cache) {
var server = cache[i];
delete cache[i];
server.close();
}
};
module.exports = ServerAgent;