diff --git a/lib/https/ca.js b/lib/https/ca.js index 1600a9eed..612dc182b 100644 --- a/lib/https/ca.js +++ b/lib/https/ca.js @@ -466,8 +466,7 @@ exports.getCustomCertsFiles = function() { exports.getRootCAFile = getRootCAFile; exports.serverAgent = hagent.serverAgent; -var SNI_OPTIONS = { SNICallback: SNICallback }; -exports.SNI_OPTIONS = SNI_OPTIONS; +exports.SNICallback = SNICallback; function addCallback(name, callback) { var cbList = cbs[name]; @@ -532,7 +531,7 @@ exports.getSNIServer = function(listener, callback, disableH2, requestCert) { if (curPort === false) { return; } - var options = SNI_OPTIONS; + var options = { SNICallback: SNICallback }; options.allowHTTP1 = enableH2; // 是否启用http2 if (requestCert) { options = extend({ diff --git a/lib/https/index.js b/lib/https/index.js index def4d80f3..42f481f2b 100644 --- a/lib/https/index.js +++ b/lib/https/index.js @@ -17,6 +17,7 @@ var socketMgr = require('../socket-mgr'); var hparser = require('hparser'); var properties = require('../rules/util').properties; var ca = require('./ca'); +var loadCert = require('./load-cert'); var h2Consts = config.enableH2 ? require('http2').constants : {}; var STATUS_CODES = http.STATUS_CODES || {}; @@ -28,13 +29,10 @@ var getDomain = ca.getDomain; var serverAgent = ca.serverAgent; var getSNIServer = ca.getSNIServer; var getHttp2Server = ca.getHttp2Server; -var remoteCerts = ca.remoteCerts; var LOCALHOST = '127.0.0.1'; var tunnelTmplData = new LRU({max: 3000, maxAge: 30000}); -var SNI_CALLBACK_RE = /^sniCallback:\/\/(?:whistle\.|plugin\.)?([a-z\d_\-]+)(?:\(([\s\S]*)\))?$/; var TIMEOUT = 6000; var CONN_TIMEOUT = 60000; -var certCallbacks = {}; var X_RE = /^x/; var proxy, server; @@ -926,64 +924,6 @@ function addClientInfo(socket, chunk, statusLine, clientIp, clientPort) { return Buffer.concat([Buffer.from(statusLine), chunk]); } -function loadCert(socket, callback) { - var servername = socket.servername; - var curCert = remoteCerts.get(servername); - var plugin = rules.resolveSNICallback(socket); - if (plugin) { - if (socket.rules) { - socket.rules.sniCallback = plugin; - } - if (SNI_CALLBACK_RE.test(plugin.matcher)) { - socket.sniRuleValue = RegExp.$2; - var pluginName = RegExp.$1; - plugin = pluginMgr.getPlugin(pluginName + ':'); - if (plugin) { - if (curCert && curCert.name) { - socket.hasCertCache = curCert.name + (curCert.mtime ? '+' + curCert.mtime : ''); - } - var cbKey = servername + '/' + pluginName; - var cbList = certCallbacks[cbKey]; - var handleCert = function(cert) { - if (cert === false) { - return callback(false); - } - if (cert && util.isString(cert.key) && util.isString(cert.cert)) { - socket.sniPlugin = cert.name; - if (!curCert || curCert.key !== cert.key || curCert.cert !== cert.cert) { - remoteCerts.set(servername, cert); - curCert = cert; - } - } else { - if (curCert) { - if (cert) { - socket.sniPlugin = curCert.name; - } else { - remoteCerts.del(servername); - curCert = null; - } - } - } - callback(curCert); - }; - if (cbList) { - return cbList.push(handleCert); - } - certCallbacks[cbKey] = [handleCert]; - return pluginMgr.loadCert(socket, plugin, function(cert) { - cbList = certCallbacks[cbKey]; - delete certCallbacks[cbKey]; - cbList && cbList.forEach(function(handleCb) { - handleCb(cert); - }); - }); - } - } - } - curCert && remoteCerts.del(servername); - callback(); -} - module.exports = function(socket, next, isWebPort) { var reqSocket, reqDestroyed, resDestroyed; var headersStr; diff --git a/lib/https/load-cert.js b/lib/https/load-cert.js new file mode 100644 index 000000000..61bde39ca --- /dev/null +++ b/lib/https/load-cert.js @@ -0,0 +1,66 @@ +var util = require('../util'); +var rules = require('../rules'); +var pluginMgr = require('../plugins'); +var ca = require('./ca'); + +var remoteCerts = ca.remoteCerts; +var SNI_CALLBACK_RE = /^sniCallback:\/\/(?:whistle\.|plugin\.)?([a-z\d_\-]+)(?:\(([\s\S]*)\))?$/; +var certCallbacks = {}; + +module.exports = function(socket, callback) { + var servername = socket.servername; + var curCert = remoteCerts.get(servername); + var plugin = rules.resolveSNICallback(socket); + if (plugin) { + if (socket.rules) { + socket.rules.sniCallback = plugin; + } + if (SNI_CALLBACK_RE.test(plugin.matcher)) { + socket.sniRuleValue = RegExp.$2; + var pluginName = RegExp.$1; + plugin = pluginMgr.getPlugin(pluginName + ':'); + if (plugin) { + if (curCert && curCert.name) { + socket.hasCertCache = curCert.name + (curCert.mtime ? '+' + curCert.mtime : ''); + } + var cbKey = servername + '/' + pluginName; + var cbList = certCallbacks[cbKey]; + var handleCert = function(cert) { + if (cert === false) { + return callback(false); + } + if (cert && util.isString(cert.key) && util.isString(cert.cert)) { + socket.sniPlugin = cert.name; + if (!curCert || curCert.key !== cert.key || curCert.cert !== cert.cert) { + remoteCerts.set(servername, cert); + curCert = cert; + } + } else { + if (curCert) { + if (cert) { + socket.sniPlugin = curCert.name; + } else { + remoteCerts.del(servername); + curCert = null; + } + } + } + callback(curCert); + }; + if (cbList) { + return cbList.push(handleCert); + } + certCallbacks[cbKey] = [handleCert]; + return pluginMgr.loadCert(socket, plugin, function(cert) { + cbList = certCallbacks[cbKey]; + delete certCallbacks[cbKey]; + cbList && cbList.forEach(function(handleCb) { + handleCb(cert); + }); + }); + } + } + } + curCert && remoteCerts.del(servername); + callback(); +}; diff --git a/lib/index.js b/lib/index.js index f1bd910b7..ad526a2dd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -115,7 +115,11 @@ function proxy(callback) { }); }; createNormalServer(config.httpPort, http); - createNormalServer(config.httpsPort, https, httpsUtil.SNI_OPTIONS); + createNormalServer(config.httpsPort, https, { + SNICallback: function(servername, callback) { + return httpsUtil.SNICallback(servername, callback); + } + }); if (config.socksPort) { ++count; var boundHost;