bugfix: 修复因 `HttpsAgent` 为单例,导致并发请求时因启用了SSL校验导致 proxy 或 sni 请求失败的问题

pull/375/head
王良 2024-09-29 13:12:49 +08:00
parent 6064fe4ab1
commit bf84613f51
4 changed files with 34 additions and 20 deletions

View File

@ -116,12 +116,16 @@ module.exports = {
}
if (interceptOpt.sni != null) {
let unVerifySsl = rOptions.agent.options.rejectUnauthorized === false
rOptions.servername = interceptOpt.sni
if (rOptions.agent && rOptions.agent.options) {
rOptions.agent.options.rejectUnauthorized = false
if (rOptions.agent.options.rejectUnauthorized && rOptions.agent.unVerifySslAgent) {
// rOptions.agent.options.rejectUnauthorized = false // 不能直接在agent上进行修改属性值因为它采用了单例模式所有请求共用这个对象的
rOptions.agent = rOptions.agent.unVerifySslAgent
unVerifySsl = true
}
res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}, sni: ${interceptOpt.sni}`)
log.info('proxy intercept: hostname:', originHostname, ', target', proxyTarget, ', sni replace servername:', rOptions.servername)
res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}, sni: ${interceptOpt.sni}`, (unVerifySsl ? ', unVerifySsl' : ''))
log.info('proxy intercept: hostname:', originHostname, ', target', proxyTarget, ', sni replace servername:', rOptions.servername, (unVerifySsl ? ', unVerifySsl' : ''))
} else {
res.setHeader('DS-Interceptor', `proxy: ${proxyTarget}`)
log.info('proxy intercept: hostname:', originHostname, ', target', proxyTarget)

View File

@ -4,14 +4,17 @@ module.exports = {
requestIntercept (context, interceptOpt, req, res, ssl, next) {
const { rOptions, log } = context
let unVerifySsl = rOptions.agent.options.rejectUnauthorized === false
rOptions.servername = interceptOpt.sni
if (rOptions.agent && rOptions.agent.options) {
rOptions.agent.options.rejectUnauthorized = false
if (rOptions.agent.options.rejectUnauthorized && rOptions.agent.unVerifySslAgent) {
// rOptions.agent.options.rejectUnauthorized = false // 不能直接在agent上进行修改属性值因为它采用了单例模式所有请求共用这个对象的
rOptions.agent = rOptions.agent.unVerifySslAgent
unVerifySsl = true
}
res.setHeader('DS-Interceptor', `sni: ${interceptOpt.sni}`, (unVerifySsl ? ', unVerifySsl' : ''))
res.setHeader('DS-Interceptor', 'sni: ' + interceptOpt.sni)
log.info('sni intercept: sni replace servername:', rOptions.hostname, '➜', rOptions.servername)
log.info('sni intercept: sni replace servername:', rOptions.hostname, '➜', rOptions.servername, (unVerifySsl ? ', unVerifySsl' : ''))
return true
},
is (interceptOpt) {

View File

@ -24,15 +24,27 @@ function getTimeoutConfig (hostname, serverSetting) {
}
}
function createHttpsAgent (timeoutConfig) {
function createHttpsAgent (timeoutConfig, verifySsl) {
const key = timeoutConfig.timeout + '-' + timeoutConfig.keepAliveTimeout
if (!httpsAgentCache[key]) {
httpsAgentCache[key] = new HttpsAgent({
verifySsl = !!verifySsl
const agent = new HttpsAgent({
keepAlive: true,
timeout: timeoutConfig.timeout,
keepAliveTimeout: timeoutConfig.keepAliveTimeout,
rejectUnauthorized: verifySsl
})
agent.unVerifySslAgent = new HttpsAgent({
keepAlive: true,
timeout: timeoutConfig.timeout,
keepAliveTimeout: timeoutConfig.keepAliveTimeout,
rejectUnauthorized: false
})
httpsAgentCache[key] = agent
log.info('创建 HttpsAgent 成功, timeoutConfig:', timeoutConfig, ', verifySsl:', verifySsl)
}
return httpsAgentCache[key]
}
@ -45,13 +57,14 @@ function createHttpAgent (timeoutConfig) {
timeout: timeoutConfig.timeout,
keepAliveTimeout: timeoutConfig.keepAliveTimeout
})
log.info('创建 HttpsAgent 成功, timeoutConfig:', timeoutConfig)
}
return httpAgentCache[key]
}
function createAgent (protocol, timeoutConfig) {
function createAgent (protocol, timeoutConfig, verifySsl) {
return protocol === 'https:'
? createHttpsAgent(timeoutConfig)
? createHttpsAgent(timeoutConfig, verifySsl)
: createHttpAgent(timeoutConfig)
}
@ -110,7 +123,7 @@ util.getOptionsFromRequest = (req, ssl, externalProxy = null, serverSetting) =>
if (headers.connection !== 'close') {
const timeoutConfig = getTimeoutConfig(hostname, serverSetting)
// log.info(`get timeoutConfig '${hostname}':`, timeoutConfig)
agent = createAgent(protocol, timeoutConfig)
agent = createAgent(protocol, timeoutConfig, serverSetting.verifySsl)
headers.connection = 'keep-alive'
} else {
agent = false

View File

@ -18,12 +18,6 @@ module.exports = function createRequestHandler (createIntercepts, middlewares, e
const rOptions = commonUtil.getOptionsFromRequest(req, ssl, externalProxy, setting)
let url = `${rOptions.method}${rOptions.protocol}//${rOptions.hostname}:${rOptions.port}${rOptions.path}`
if (rOptions.agent) {
rOptions.agent.options.rejectUnauthorized = setting.verifySsl
} else if (rOptions.agent !== false) {
log.error('rOptions.agent 的值有问题:', rOptions)
}
if (rOptions.headers.connection === 'close') {
req.socket.setKeepAlive(false)
} else if (rOptions.customSocketId != null) { // for NTLM