UNPKG

node-mitmproxy1

Version:
191 lines (160 loc) 5.63 kB
'use strict'; var url = require('url'); var Agent = require('./ProxyHttpAgent'); var HttpsAgent = require('./ProxyHttpsAgent'); var hpa = require('https-proxy-agent'); var spa = require('socks-proxy-agent'); var util = exports; var httpsAgent = new HttpsAgent({ keepAlive: true, timeout: 60000, keepAliveTimeout: 30000, // free socket keepalive for 30 seconds rejectUnauthorized: false }); var httpAgent = new Agent({ keepAlive: true, timeout: 60000, keepAliveTimeout: 30000 // free socket keepalive for 30 seconds }); var socketId = 0; // 移除旧的agentObj,现在使用优化的agentCache Map // 缓存URL解析结果以提升性能 var urlCache = new Map(); var maxCacheSize = 1000; // 优化的URL解析函数 function parseUrlCached(urlStr) { if (urlCache.has(urlStr)) { return urlCache.get(urlStr); } var parsed = url.parse(urlStr); // 限制缓存大小,防止内存泄漏 if (urlCache.size >= maxCacheSize) { var firstKey = urlCache.keys().next().value; urlCache.delete(firstKey); } urlCache.set(urlStr, parsed); return parsed; } util.getOptionsFormRequest = function (req, ssl) { var externalProxy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; // 预先计算常用值 var defaultPort = ssl ? 443 : 80; var protocol = ssl ? 'https:' : 'http:'; var reqHeaders = req.headers; // 检查必需的host header if (!reqHeaders.host) { throw new Error('Host header is required'); } // 优化host解析,避免不必要的split var colonIndex = reqHeaders.host.indexOf(':'); var hostname = colonIndex === -1 ? reqHeaders.host : reqHeaders.host.substring(0, colonIndex); var port = colonIndex === -1 ? defaultPort : parseInt(reqHeaders.host.substring(colonIndex + 1), 10) || defaultPort; // 缓存URL解析 var urlObject = parseUrlCached(req.url); // 处理外部代理 var externalProxyUrl = null; if (externalProxy) { if (typeof externalProxy === 'string') { externalProxyUrl = externalProxy; } else if (typeof externalProxy === 'function') { try { externalProxyUrl = externalProxy(req, ssl); } catch (e) { console.error(e); } } } // 优化agent选择逻辑 var agent = false; var useKeepAlive = false; if (!externalProxyUrl) { // 检查是否使用keep-alive if (reqHeaders.connection !== 'close') { agent = ssl ? httpsAgent : httpAgent; useKeepAlive = true; } } else { agent = util.getAgentObject(externalProxyUrl, urlObject); } // 构建基础options对象 var options = { protocol: protocol, hostname: hostname, method: req.method, port: port, path: urlObject.path, headers: reqHeaders, agent: agent }; // 处理HTTP代理的特殊情况 if (protocol === 'http:' && externalProxyUrl) { var externalURL = parseUrlCached(externalProxyUrl); if (externalURL.protocol === 'http:') { options.hostname = externalURL.hostname; options.port = externalURL.port; options.path = 'http://' + urlObject.host + urlObject.path; } } // 处理NTLM认证的socket ID if (req.socket.customSocketId) { options.customSocketId = req.socket.customSocketId; } else if (reqHeaders.authorization) { options.customSocketId = req.socket.customSocketId = socketId++; } // 优化headers处理,只在需要时修改 if (useKeepAlive || reqHeaders['proxy-connection']) { // 只在需要时创建headers副本 options.headers = Object.assign({}, reqHeaders); delete options.headers['proxy-connection']; if (useKeepAlive) { options.headers.connection = 'keep-alive'; } } return options; }; // 优化的agent缓存管理 var agentCache = new Map(); var maxAgentCacheSize = 100; // 清理过期的agent连接 function cleanupAgentCache() { if (agentCache.size > maxAgentCacheSize) { // 删除最旧的一半缓存项 var keysToDelete = Array.from(agentCache.keys()).slice(0, Math.floor(maxAgentCacheSize / 2)); keysToDelete.forEach(function (key) { var agent = agentCache.get(key); if (agent && typeof agent.destroy === 'function') { agent.destroy(); } agentCache.delete(key); }); } } util.getAgentObject = function (proxyUrl, targetUrlObj) { // 使用缓存的URL解析结果 var parsedUrl = parseUrlCached(proxyUrl); // 创建更精确的缓存key,包含协议和认证信息 var cacheKey = parsedUrl.protocol + '//' + (parsedUrl.auth ? parsedUrl.auth + '@' : '') + parsedUrl.host + '-' + targetUrlObj.host; if (agentCache.has(cacheKey)) { return agentCache.get(cacheKey); } // 清理缓存以防止内存泄漏 cleanupAgentCache(); // 创建优化配置的agent选项 var agentOptions = { keepAlive: true, keepAliveMsecs: 30000, timeout: 90000, maxSockets: 10, maxFreeSockets: 6, scheduling: 'lifo' }; var agent = void 0; if (proxyUrl.startsWith('socks')) { agent = new spa.SocksProxyAgent(proxyUrl, agentOptions); } else { agent = new hpa.HttpsProxyAgent(proxyUrl, agentOptions); } // 缓存agent实例 agentCache.set(cacheKey, agent); return agent; };