114 lines
3.6 KiB
JavaScript
114 lines
3.6 KiB
JavaScript
const https = require('https')
|
|
const tlsUtils = require('./tlsUtils')
|
|
const CertAndKeyContainer = require('./CertAndKeyContainer')
|
|
const forge = require('node-forge')
|
|
const pki = forge.pki
|
|
// const colors = require('colors')
|
|
const tls = require('tls')
|
|
const log = require('../../../utils/util.log')
|
|
module.exports = class FakeServersCenter {
|
|
constructor ({ maxLength = 256, requestHandler, upgradeHandler, caCert, caKey, getCertSocketTimeout }) {
|
|
this.queue = []
|
|
this.maxLength = maxLength
|
|
this.requestHandler = requestHandler
|
|
this.upgradeHandler = upgradeHandler
|
|
this.certAndKeyContainer = new CertAndKeyContainer({
|
|
getCertSocketTimeout,
|
|
caCert,
|
|
caKey
|
|
})
|
|
}
|
|
|
|
addServerPromise (serverPromiseObj) {
|
|
if (this.queue.length >= this.maxLength) {
|
|
const delServerObj = this.queue.shift()
|
|
try {
|
|
log.info('超过最大服务数量,删除旧服务', delServerObj)
|
|
delServerObj.serverObj.server.close()
|
|
} catch (e) {
|
|
log.info(e)
|
|
}
|
|
}
|
|
this.queue.push(serverPromiseObj)
|
|
return serverPromiseObj
|
|
}
|
|
|
|
getServerPromise (hostname, port) {
|
|
for (let i = 0; i < this.queue.length; i++) {
|
|
const serverPromiseObj = this.queue[i]
|
|
const mappingHostNames = serverPromiseObj.mappingHostNames
|
|
for (let j = 0; j < mappingHostNames.length; j++) {
|
|
const DNSName = mappingHostNames[j]
|
|
if (tlsUtils.isMappingHostName(DNSName, hostname)) {
|
|
this.reRankServer(i)
|
|
return serverPromiseObj.promise
|
|
}
|
|
}
|
|
}
|
|
|
|
const serverPromiseObj = {
|
|
mappingHostNames: [hostname] // temporary hostname
|
|
}
|
|
|
|
const promise = new Promise((resolve, reject) => {
|
|
(async () => {
|
|
const certObj = await this.certAndKeyContainer.getCertPromise(hostname, port)
|
|
const cert = certObj.cert
|
|
const key = certObj.key
|
|
const certPem = pki.certificateToPem(cert)
|
|
const keyPem = pki.privateKeyToPem(key)
|
|
const fakeServer = new https.Server({
|
|
key: keyPem,
|
|
cert: certPem,
|
|
SNICallback: (hostname, done) => {
|
|
(async () => {
|
|
const certObj = await this.certAndKeyContainer.getCertPromise(hostname, port)
|
|
log.info('sni callback:', hostname)
|
|
done(null, tls.createSecureContext({
|
|
key: pki.privateKeyToPem(certObj.key),
|
|
cert: pki.certificateToPem(certObj.cert)
|
|
}))
|
|
})()
|
|
}
|
|
})
|
|
const serverObj = {
|
|
cert,
|
|
key,
|
|
server: fakeServer,
|
|
port: 0 // if prot === 0 ,should listen server's `listening` event.
|
|
}
|
|
serverPromiseObj.serverObj = serverObj
|
|
fakeServer.listen(0, () => {
|
|
const address = fakeServer.address()
|
|
serverObj.port = address.port
|
|
})
|
|
fakeServer.on('request', (req, res) => {
|
|
const ssl = true
|
|
this.requestHandler(req, res, ssl)
|
|
})
|
|
fakeServer.on('error', (e) => {
|
|
log.error(e)
|
|
})
|
|
fakeServer.on('listening', () => {
|
|
const mappingHostNames = tlsUtils.getMappingHostNamesFromCert(certObj.cert)
|
|
serverPromiseObj.mappingHostNames = mappingHostNames
|
|
resolve(serverObj)
|
|
})
|
|
fakeServer.on('upgrade', (req, socket, head) => {
|
|
const ssl = true
|
|
this.upgradeHandler(req, socket, head, ssl)
|
|
})
|
|
})()
|
|
})
|
|
|
|
serverPromiseObj.promise = promise
|
|
|
|
return (this.addServerPromise(serverPromiseObj)).promise
|
|
}
|
|
|
|
reRankServer (index) {
|
|
// index ==> queue foot
|
|
this.queue.push((this.queue.splice(index, 1))[0])
|
|
}
|
|
}
|