mirror of
https://github.com/avwo/whistle.git
synced 2026-10-29 15:09:28 +08:00
add server agent
This commit is contained in:
+16
-7
@@ -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
@@ -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);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user