Skip to content

Commit 79acaf4

Browse files
perf: 优化fake服务和证书的缓存实现方式
1 parent 8117398 commit 79acaf4

7 files changed

Lines changed: 77 additions & 76 deletions

File tree

packages/core/src/config/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const defaultConfig = {
5050
enabled: true,
5151
host: '127.0.0.1',
5252
port: 31181,
53+
fakeServerMaxLength: 100, // fakeServer的最大缓存数量
5354
setting: {
5455
NODE_TLS_REJECT_UNAUTHORIZED: true,
5556
verifySsl: true,

packages/mitmproxy/src/lib/proxy/mitmproxy/createFakeServerCenter.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ module.exports = function createFakeServerCenter ({
99
caKeyPath,
1010
requestHandler,
1111
upgradeHandler,
12-
getCertSocketTimeout,
1312
}) {
1413
let caCert
1514
let caKey
@@ -31,6 +30,5 @@ module.exports = function createFakeServerCenter ({
3130
maxLength,
3231
requestHandler,
3332
upgradeHandler,
34-
getCertSocketTimeout,
3533
})
3634
}

packages/mitmproxy/src/lib/proxy/mitmproxy/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ module.exports = {
1717
caKeyPath,
1818
sslConnectInterceptor,
1919
createIntercepts,
20-
getCertSocketTimeout = 1000,
2120
middlewares = [],
2221
externalProxy,
2322
dnsConfig,
@@ -71,7 +70,6 @@ module.exports = {
7170
caKeyPath,
7271
requestHandler,
7372
upgradeHandler,
74-
getCertSocketTimeout,
7573
})
7674

7775
const connectHandler = createConnectHandler(
Lines changed: 26 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,51 @@
11
const tlsUtils = require('./tlsUtils')
2-
// const https = require('https')
2+
const LRUCache = require('lru-cache')
33
const log = require('../../../utils/util.log.server')
44

5+
const DEFAULT_MAX_LENGTH = 256
6+
57
module.exports = class CertAndKeyContainer {
68
constructor ({
7-
maxLength = 1000,
8-
// getCertSocketTimeout = 2 * 1000,
9+
maxLength = DEFAULT_MAX_LENGTH,
910
caCert,
1011
caKey,
1112
}) {
12-
this.queue = []
13-
this.maxLength = maxLength
14-
// this.getCertSocketTimeout = getCertSocketTimeout
13+
// 缓存键:dnsName
14+
this.cache = new LRUCache({
15+
maxSize: maxLength > 0 ? maxLength : DEFAULT_MAX_LENGTH,
16+
sizeCalculation: () => {
17+
return 1
18+
},
19+
dispose: (_evictCertPromiseObj, evictKey) => {
20+
log.error(`旧证书缓存被移除:${evictKey}`)
21+
},
22+
})
1523
this.caCert = caCert
1624
this.caKey = caKey
1725
}
1826

1927
addCertPromise (certPromiseObj) {
20-
if (this.queue.length >= this.maxLength) {
21-
const delCertObj = this.queue.shift()
22-
log.info(`超过最大证书数量${this.maxLength},删除旧证书。delCertObj:`, delCertObj)
23-
}
24-
this.queue.push(certPromiseObj)
25-
return certPromiseObj
28+
// 添加缓存
29+
this.cache.set(certPromiseObj.dnsName, certPromiseObj)
2630
}
2731

2832
getCertPromise (hostname, port, dnsName, mappingHostNames) {
29-
for (let i = this.queue.length - 1; i >= 0; i--) {
30-
const _certPromiseObj = this.queue[i]
31-
const certMappingHostNames = _certPromiseObj.mappingHostNames
32-
for (let j = 0; j < certMappingHostNames.length; j++) {
33-
const DNSName = certMappingHostNames[j]
34-
if (DNSName === dnsName || tlsUtils.isMappingHostName(DNSName, hostname)) {
35-
this.reRankCert(i)
36-
log.info(`Load fakeCertPromise from cache, hostname: ${hostname}:${port}, certPromiseObj: {"mappingHostNames":${JSON.stringify(_certPromiseObj.mappingHostNames)}}`)
37-
return _certPromiseObj.promise
38-
}
39-
}
40-
}
41-
42-
const certPromiseObj = {
43-
mappingHostNames,
33+
// 获取缓存
34+
const cached = this.cache.get(dnsName)
35+
if (cached) {
36+
log.info(`Load fakeCertPromise from cache, hostname: ${hostname}:${port}, certPromiseObj: {"mappingHostNames":${JSON.stringify(cached.mappingHostNames)}}`)
37+
return cached.promise
4438
}
4539

4640
log.info(`【CreateFakeCertificate】dnsName: ${dnsName}, hostname: ${hostname}:${port}`)
4741
const promise = tlsUtils.createFakeCertificateByDomain(this.caKey, this.caCert, dnsName, mappingHostNames)
4842

49-
certPromiseObj.promise = promise
50-
this.addCertPromise(certPromiseObj)
43+
this.addCertPromise({
44+
dnsName,
45+
mappingHostNames,
46+
promise,
47+
})
5148

5249
return promise
5350
}
54-
55-
reRankCert (index) {
56-
// index ==> queue foot
57-
this.queue.push((this.queue.splice(index, 1))[0])
58-
}
5951
}

packages/mitmproxy/src/lib/proxy/tls/FakeServersCenter.js

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,25 @@ const http = require('node:http')
22
const https = require('node:https')
33
const tls = require('node:tls')
44
const forge = require('node-forge')
5+
const LRUCache = require('lru-cache')
56
const CertAndKeyContainer = require('./CertAndKeyContainer')
6-
const tlsUtils = require('./tlsUtils')
77
const log = require('../../../utils/util.log.server')
88
const compatible = require('../compatible/compatible')
99

1010
const pki = forge.pki
1111

12+
// IPv4地址检测正则,提前编译,避免在 getDnsName 中重复创建。
13+
// 不使用 /g 标志:此处只做存在性检测(.test()),无需记录 lastIndex 状态。
14+
const IPv4_RE = /\b(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\b){3}/
15+
1216
// 获取DNS名称
1317
function getDnsName (hostname) {
1418
if (!hostname.includes('.')) {
1519
return hostname // 可能是IPv6地址,直接返回
1620
}
1721

1822
// 判断是否为IP
19-
if (hostname.match(/\b(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)(\.(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\b){3}/g)) {
23+
if (IPv4_RE.test(hostname)) {
2024
return hostname // 为IP,直接返回
2125
}
2226

@@ -29,31 +33,43 @@ function getDnsName (hostname) {
2933
return `*${hostname.substring(hostname.indexOf('.'))}`
3034
}
3135

36+
const DEFAULT_MAX_LENGTH = 256
37+
3238
module.exports = class FakeServersCenter {
33-
constructor ({ maxLength = 256, requestHandler, upgradeHandler, caCert, caKey, getCertSocketTimeout }) {
34-
this.queue = []
35-
this.maxLength = maxLength
39+
constructor ({
40+
maxLength = DEFAULT_MAX_LENGTH,
41+
requestHandler,
42+
upgradeHandler,
43+
caCert,
44+
caKey,
45+
}) {
46+
// 缓存键格式:`${dnsName}:${port}:${ssl}`
47+
this.cache = new LRUCache({
48+
maxSize: maxLength > 0 ? maxLength : DEFAULT_MAX_LENGTH,
49+
sizeCalculation: () => {
50+
return 1
51+
},
52+
dispose: (evictServerPromiseObj, evictDnsName) => {
53+
try {
54+
evictServerPromiseObj.serverObj.server.close()
55+
log.info(`旧fake服务缓存被移除,停止服务成功,${evictDnsName}`)
56+
} catch (e) {
57+
log.error(`旧fake服务缓存被移除,但停止服务失败,${evictDnsName} ->`, evictServerPromiseObj, `, error:`, e)
58+
}
59+
},
60+
})
3661
this.requestHandler = requestHandler
3762
this.upgradeHandler = upgradeHandler
3863
this.certAndKeyContainer = new CertAndKeyContainer({
39-
getCertSocketTimeout,
64+
maxLength: maxLength > 0 ? maxLength : DEFAULT_MAX_LENGTH,
4065
caCert,
4166
caKey,
4267
})
4368
}
4469

4570
addServerPromise (serverPromiseObj) {
46-
if (this.queue.length >= this.maxLength) {
47-
const delServerObj = this.queue.shift()
48-
try {
49-
log.info(`超过最大服务数量${this.maxLength},删除旧服务。delServerObj:`, delServerObj)
50-
delServerObj.serverObj.server.close()
51-
} catch (e) {
52-
log.error('`delServerObj.serverObj.server.close()` error:', e)
53-
}
54-
}
55-
this.queue.push(serverPromiseObj)
56-
return serverPromiseObj
71+
// 添加缓存
72+
this.cache.set(serverPromiseObj.cacheKey, serverPromiseObj)
5773
}
5874

5975
getServerPromise (hostname, port, ssl, manualCompatibleConfig) {
@@ -69,28 +85,22 @@ module.exports = class FakeServersCenter {
6985

7086
log.info(`getServerPromise, hostname: ${hostname}:${port}, ssl: ${ssl}, protocol: ${ssl ? 'https' : 'http'}`)
7187

72-
for (let i = this.queue.length - 1; i >= 0; i--) {
73-
const serverPromiseObj = this.queue[i]
74-
if (serverPromiseObj.port === port && serverPromiseObj.ssl === ssl) {
75-
const mappingHostNames = serverPromiseObj.mappingHostNames
76-
for (let j = 0; j < mappingHostNames.length; j++) {
77-
const DNSName = mappingHostNames[j]
78-
if (tlsUtils.isMappingHostName(DNSName, hostname)) {
79-
this.reRankServer(i)
80-
log.info(`Load fakeServerPromise from cache, hostname: ${hostname}:${port}, ssl: ${ssl}, serverPromiseObj: {"ssl":${serverPromiseObj.ssl},"port":${serverPromiseObj.port},"mappingHostNames":${JSON.stringify(serverPromiseObj.mappingHostNames)}}`)
81-
return serverPromiseObj.promise
82-
}
83-
}
84-
}
88+
const dnsName = getDnsName(hostname)
89+
const cacheKey = `${dnsName}:${port}:${ssl}`
90+
91+
const cachedServerObj = this.cache.get(cacheKey)
92+
if (cachedServerObj) {
93+
log.info(`Load fakeServerPromise from cache, hostname: ${hostname}:${port}, ssl: ${ssl}, serverPromiseObj: {"ssl":${cachedServerObj.ssl},"port":${cachedServerObj.port},"mappingHostNames":${JSON.stringify(cachedServerObj.mappingHostNames)}}`)
94+
return cachedServerObj.promise
8595
}
8696

87-
const dnsName = getDnsName(hostname)
8897
const mappingHostNames = [dnsName]
8998
if (dnsName.startsWith('*.')) {
9099
mappingHostNames.push(dnsName.replace('*.', ''))
91100
}
92101

93102
const serverPromiseObj = {
103+
cacheKey,
94104
port,
95105
ssl,
96106
mappingHostNames,
@@ -228,9 +238,4 @@ module.exports = class FakeServersCenter {
228238

229239
return promise
230240
}
231-
232-
reRankServer (index) {
233-
// index ==> queue foot
234-
this.queue.push((this.queue.splice(index, 1))[0])
235-
}
236241
}

packages/mitmproxy/src/options.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ module.exports = (serverConfig) => {
114114
const options = {
115115
host: serverConfig.host,
116116
port: serverConfig.port,
117+
maxLength: serverConfig.fakeServerMaxLength,
117118
dnsConfig: {
118119
preSetIpList,
119120
dnsMap: dnsUtil.initDNS(serverConfig.dns.providers, preSetIpList),

packages/mitmproxy/src/utils/util.match.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ const lodash = require('lodash')
22
const log = require('./util.log.server')
33
const mergeApi = require('@docmirror/dev-sidecar/src/merge')
44

5-
const urlRegexpCache = new Map()
5+
const LRUCache = require('lru-cache')
6+
7+
const urlRegexpCache = new LRUCache({
8+
maxSize: 512,
9+
sizeCalculation: () => {
10+
return 1
11+
},
12+
})
613

714
function isMatched (url, regexp) {
815
if (regexp === '.*' || regexp === '*' || regexp === 'true' || regexp === true) {
@@ -206,7 +213,6 @@ function matchHostnameAll (hostMap, hostname, action) {
206213

207214
module.exports = {
208215
isMatched,
209-
domainRegexply,
210216
domainMapRegexply,
211217
matchHostname,
212218
matchHostnameAll,

0 commit comments

Comments
 (0)