From 922c8d667be084baac8a7a5a89dd372d61514a07 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Mon, 16 Nov 2020 00:19:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20response=E6=8B=A6=E6=88=AA=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- packages/core/src/config/index.js | 13 +- .../src/lib/interceptor/impl/abort.js | 3 +- .../src/lib/interceptor/impl/proxy.js | 4 +- .../src/lib/interceptor/impl/redirect.js | 4 +- .../src/lib/interceptor/impl/script.js | 23 ++ .../mitmproxy/src/lib/interceptor/index.js | 3 +- packages/mitmproxy/src/lib/monkey/grants.js | 8 + packages/mitmproxy/src/lib/monkey/index.js | 67 ++++ .../src/lib/monkey/scripts/github.script | 287 ++++++++++++++++++ .../lib/proxy/middleware/FilterMiddleware.js | 0 .../lib/proxy/middleware/HtmlMiddleware.js | 66 ++-- .../proxy/middleware/MapLocalMiddleware.js | 0 .../proxy/middleware/MapRemoteMiddleware.js | 0 .../proxy/mitmproxy/createRequestHandler.js | 69 +++-- .../src/lib/proxy/mitmproxy/index.js | 6 +- packages/mitmproxy/src/options.js | 36 +-- .../mitmproxy/test/lib/monkey/indexTest.js | 3 + 18 files changed, 498 insertions(+), 97 deletions(-) create mode 100644 packages/mitmproxy/src/lib/interceptor/impl/script.js create mode 100644 packages/mitmproxy/src/lib/monkey/grants.js create mode 100644 packages/mitmproxy/src/lib/monkey/index.js create mode 100644 packages/mitmproxy/src/lib/monkey/scripts/github.script delete mode 100644 packages/mitmproxy/src/lib/proxy/middleware/FilterMiddleware.js delete mode 100644 packages/mitmproxy/src/lib/proxy/middleware/MapLocalMiddleware.js delete mode 100644 packages/mitmproxy/src/lib/proxy/middleware/MapRemoteMiddleware.js create mode 100644 packages/mitmproxy/test/lib/monkey/indexTest.js diff --git a/README.md b/README.md index 42a67ac6..d239c839 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ ### 2、 dns优选 根据网络状况智能解析域名ip地址,获取最佳网络速度 比如: -1. 解决git push 偶尔失败需要输入账号密码的问题(fatal: TaskCanceledException encountered) +1. 解决git push 偶尔失败需要输入账号密码的问题( +fatal: TaskCanceledException encountered / fatal: HttpRequestException encountered) 2. 解决github头像加载不出来的问题 3. 解决gist.github.com访问不到的问题 diff --git a/packages/core/src/config/index.js b/packages/core/src/config/index.js index 2475110c..caa224e5 100644 --- a/packages/core/src/config/index.js +++ b/packages/core/src/config/index.js @@ -19,6 +19,9 @@ module.exports = { }, '/.*/.*/blame/': { redirect: 'hub.fastgit.org' + }, + '/.*/[^\\/]*$': { + script: 'console.log("123123132")' } }, 'raw.githubusercontent.com': { @@ -101,12 +104,12 @@ module.exports = { } }, mapping: { - 'img.shields.io': 'aliyun', - '*.github.com': 'aliyun', - '*.githubusercontent.com': 'aliyun', - '*.githubassets.com': 'aliyun', + 'img.shields.io': 'usa', + '*.github.com': 'usa', + '*.githubusercontent.com': 'usa', + '*.githubassets.com': 'usa', // "解决push的时候需要输入密码的问题", - 'github.com': 'aliyun' + 'github.com': 'usa' } } }, diff --git a/packages/mitmproxy/src/lib/interceptor/impl/abort.js b/packages/mitmproxy/src/lib/interceptor/impl/abort.js index 2b0ade3e..65c45856 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/abort.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/abort.js @@ -2,11 +2,12 @@ module.exports = function createIntercept (context) { const { log } = context return { - requestInterceptor (interceptOpt, rOptions, req, res, ssl) { + requestIntercept (interceptOpt, rOptions, req, res, ssl) { log.info('abort:', rOptions.hostname, req.url) res.writeHead(403) res.write('DevSidecar 403: \n\n request abort, this request is matched by abort intercept.\n\n 因配置abort拦截器,本请求将取消') res.end() + return true// 是否结束 }, is (interceptOpt) { return !!interceptOpt.abort diff --git a/packages/mitmproxy/src/lib/interceptor/impl/proxy.js b/packages/mitmproxy/src/lib/interceptor/impl/proxy.js index 44e270fe..02f0931d 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/proxy.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/proxy.js @@ -2,13 +2,13 @@ const url = require('url') module.exports = function createInterceptor (context) { const { log } = context return { - requestInterceptor (interceptOpt, rOptions, req, res, ssl, next) { + requestIntercept (interceptOpt, rOptions, req, res, ssl, next) { let proxyTarget = interceptOpt.proxy + req.url if (interceptOpt.replace) { const regexp = new RegExp(interceptOpt.replace) proxyTarget = req.url.replace(regexp, interceptOpt.proxy) } - console.log('proxy', rOptions.path, rOptions.url) + log.info('proxy', rOptions.path, rOptions.url) // const backup = interceptOpt.backup const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : rOptions.protocol + '//' + proxyTarget // eslint-disable-next-line node/no-deprecated-api diff --git a/packages/mitmproxy/src/lib/interceptor/impl/redirect.js b/packages/mitmproxy/src/lib/interceptor/impl/redirect.js index 07d7af84..b38aa675 100644 --- a/packages/mitmproxy/src/lib/interceptor/impl/redirect.js +++ b/packages/mitmproxy/src/lib/interceptor/impl/redirect.js @@ -1,7 +1,7 @@ module.exports = function createInterceptor (context) { const { log } = context return { - requestInterceptor (interceptOpt, rOptions, req, res, ssl) { + requestIntercept (interceptOpt, rOptions, req, res, ssl) { const url = req.url let redirect if (typeof interceptOpt.redirect === 'string') { @@ -12,7 +12,7 @@ module.exports = function createInterceptor (context) { log.info('请求重定向:', rOptions.hostname, url, redirect) res.writeHead(302, { Location: redirect }) res.end() - return true + return true// 是否结束 }, is (interceptOpt) { return interceptOpt.redirect // 如果配置中有redirect,那么这个配置是需要redirect拦截的 diff --git a/packages/mitmproxy/src/lib/interceptor/impl/script.js b/packages/mitmproxy/src/lib/interceptor/impl/script.js new file mode 100644 index 00000000..83f094c1 --- /dev/null +++ b/packages/mitmproxy/src/lib/interceptor/impl/script.js @@ -0,0 +1,23 @@ +module.exports = function createInterceptor (context) { + const { log } = context + return { + responseIntercept (interceptOpt, rOptions, req, res, proxyReq, proxyRes, ssl) { + const script = ` + + ` + log.info('responseIntercept: body script', rOptions.hostname, rOptions.path) + return { + body: script + } + }, + is (interceptOpt) { + return interceptOpt.script + } + } +} diff --git a/packages/mitmproxy/src/lib/interceptor/index.js b/packages/mitmproxy/src/lib/interceptor/index.js index f072b075..72625ad9 100644 --- a/packages/mitmproxy/src/lib/interceptor/index.js +++ b/packages/mitmproxy/src/lib/interceptor/index.js @@ -1,8 +1,9 @@ const proxy = require('./impl/proxy') const redirect = require('./impl/redirect') const abort = require('./impl/abort') +const script = require('./impl/script') const log = require('../../utils/util.log') const context = { log } -const modules = [proxy(context), redirect(context), abort(context)] +const modules = [proxy(context), redirect(context), abort(context), script(context)] module.exports = modules diff --git a/packages/mitmproxy/src/lib/monkey/grants.js b/packages/mitmproxy/src/lib/monkey/grants.js new file mode 100644 index 00000000..2678a759 --- /dev/null +++ b/packages/mitmproxy/src/lib/monkey/grants.js @@ -0,0 +1,8 @@ +const Monkey_Grants = { + GM_registerMenuCommand: () => {}, + GM_unregisterMenuCommand: () => {}, + GM_openInTab: () => {}, + GM_getValue: () => {}, + GM_setValue: () => {}, + GM_notification: () => {} +} diff --git a/packages/mitmproxy/src/lib/monkey/index.js b/packages/mitmproxy/src/lib/monkey/index.js new file mode 100644 index 00000000..50a062e3 --- /dev/null +++ b/packages/mitmproxy/src/lib/monkey/index.js @@ -0,0 +1,67 @@ +const fs = require('fs') +const path = require('path') +let scripts = [] + +function buildScript (sc, content) { + const grant = sc.grant + const pre = '(function () { \r\n' + let grantSc = '' + for (const item of grant) { + grantSc += 'const ' + item + ' = Monkey_Grants[\'' + item + '\']\r\n' + } + const tail = content + '\r\n' + + '})()' + return pre + grantSc + tail +} + +function loadScript (content) { + // @grant GM_registerMenuCommand + // @grant GM_unregisterMenuCommand + // @grant GM_openInTab + // @grant GM_getValue + // @grant GM_setValue + // @grant GM_notification + const annoFlag = '// ==/UserScript==' + const arr = content.split(annoFlag) + const start = 0 + + console.log('arr', arr.length) + const confStr = arr[start] + const confItemArr = confStr.split('\n') + const sc = { + grant: [], + match: [], + content: '' + } + for (const string of confItemArr) { + const reg = new RegExp('.*@([^\\s]+)\\s(.+)') + const ret = string.match(reg) + if (ret) { + const key = ret[1].trim() + const value = ret[2].trim() + if (key === 'grant') { + sc.grant.push(value) + } else if (key === 'match') { + sc.match.push(value) + } else { + sc[key] = value + } + } + } + const script = arr[start + 1].trim() + + sc.script = buildScript(sc, script) + return sc +} + +module.exports = { + get () { + return scripts + }, + load () { + const github = loadScript(fs.readFileSync(path.join(__dirname, './scripts/github.script')).toString()) + scripts = [] + scripts.push(github) + return scripts + } +} diff --git a/packages/mitmproxy/src/lib/monkey/scripts/github.script b/packages/mitmproxy/src/lib/monkey/scripts/github.script new file mode 100644 index 00000000..cd80e23f --- /dev/null +++ b/packages/mitmproxy/src/lib/monkey/scripts/github.script @@ -0,0 +1,287 @@ +// ==UserScript== +// @name Github 增强 - 高速下载 +// @version 1.2.4 +// @author X.I.U +// @description 高速下载 Clone、Release、Raw、Code(ZIP) 等文件、项目列表单文件快捷下载 (☁) +// @match https://github.com/*/* +// @match https://github.com/*/*/releases +// @match https://github.com/*/*/releases/* +// @icon https://github.githubassets.com/favicon.ico +// @require https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js +// @grant GM_registerMenuCommand +// @grant GM_unregisterMenuCommand +// @grant GM_openInTab +// @grant GM_getValue +// @grant GM_setValue +// @grant GM_notification +// @license GPL-3.0 License +// @run-at document-end +// @namespace https://greasyfork.org/scripts/412245 +// ==/UserScript== + +(function () { + var download_url = [ + 'https://gh.con.sh', + 'https://gh.api.99988866.xyz', + 'https://download.fastgit.org', + 'https://pd.zwc365.com/seturl', + 'https://g.ioiox.com', + 'https://git.yumenaka.net' + ] + var download_url_name = ['美国', '美国', '日本东京', '中国香港', '中国香港', '美国洛杉矶'] + var clone_url = [ + 'https://hub.fastgit.org', + 'https://gitclone.com', + 'https://github.com.cnpmjs.org' + ] + var raw_url = [ + 'https://raw.githubusercontent.com', + 'https://cdn.jsdelivr.net', + 'https://raw.fastgit.org' + ] + var raw_url_name = ['Github 原生', '中国国内', '中国香港', '美国洛杉矶'] + var raw_url_tip = [ + '', + '注意:该加速源存在缓存机制(24小时),所以文件可能不是最新。 注意:当前分支所有文件总文件大小超过 50MB 时,该加速源不可用。 注意:当前分支名为版本号格式时(如 v1.2.3),该高速下载链接因格式限制不可用。 ', + '注意:单个文件太大时可能会提示超时(实时获取中),请重试。 ', + '注意:经过测试,该加速源存在文件格式限制,如果无法下载说明不支持该文件格式。 ' + ] + var svg = [ + '', + '', + '' + ] + var style = ['padding:0 6px;margin-right: -1px;border-radius: 2px;background-color: #ffffff;border-color: rgba(27, 31, 35, 0.1);font-size: 11px;color: #888888;'] + + var menu_raw_fast = GM_getValue('xiu2_menu_raw_fast') + var menu_menu_raw_fast_ID; var menu_feedBack_ID + if (menu_raw_fast == null || menu_raw_fast == '中国国内') { menu_raw_fast = 1; GM_setValue('xiu2_menu_raw_fast', 1) }; // 调整上个版本的设置存储变量内容 + + registerMenuCommand() + // 注册脚本菜单 + function registerMenuCommand () { + if (menu_feedBack_ID) { // 如果反馈菜单ID不是 null,则删除所有脚本菜单 + GM_unregisterMenuCommand(menu_menu_raw_fast_ID) + GM_unregisterMenuCommand(menu_feedBack_ID) + menu_raw_fast = GM_getValue('xiu2_menu_raw_fast') + } + menu_menu_raw_fast_ID = GM_registerMenuCommand(`🔄 [ ${raw_url_name[menu_raw_fast]} ] 加速源 (☁) - 点击切换`, menu_toggle_raw_fast) + menu_feedBack_ID = GM_registerMenuCommand('💬 反馈 & 建议 [Github]', function () { window.GM_openInTab('https://github.com/XIU2/UserScript', { active: true, insert: true, setParent: true }) }) + } + + // 切换加速源 + function menu_toggle_raw_fast () { + if (menu_raw_fast >= raw_url_name.length - 1) { // 如果当前加速源位置大于等于加速源总数,则改为第一个加速源,反之递增下一个加速源 + menu_raw_fast = 0 + } else { + menu_raw_fast += 1 + } + GM_setValue('xiu2_menu_raw_fast', menu_raw_fast) + console.log(11111) + delDownLink() // 删除旧加速源 + console.log(22222) + addDownLink() // 添加新加速源 + console.log(33333) + GM_notification(`已切换加速源为:${raw_url_name[menu_raw_fast]}`) // 提示消息 + registerMenuCommand() // 重新注册脚本菜单 + }; + + addRelease() // Release 加速 + addDownloadZIP() // Source Code 加速 + addGitClone() // Download ZIP/Code(ZIP) 加速 + addRawFile() // Raw 加速 + setTimeout(addDownLink, 2000) // 添加 Raw 下载链接(☁),延迟 2 秒执行,避免被 pjax 刷掉 + + document.addEventListener('pjax:success', function () { // pjax 事件发生后 + addRelease() // Release 加速 + addDownloadZIP() // Source Code 加速 + addGitClone() // Download ZIP/Code(ZIP) 加速 + addRawFile() // 添加 Raw 加速按钮 + setTimeout(addDownLink, 2000) // 添加 Raw 下载链接(☁),延迟 2 秒执行,避免被 pjax 刷掉 + }) + + // Release + function addRelease () { + $('.Box.Box--condensed').each(function () { + $(this).find('.d-flex.Box-body>a').each(function () { + var href = $(this).attr('href') + var url = [ + download_url[0] + '/https://github.com' + href, + download_url[1] + '/https://github.com' + href, + download_url[2] + href, + download_url[3] + '/https://github.com' + href, + download_url[4] + '/https://github.com' + href, + download_url[5] + '/https://github.com' + href + ] + var html = `
+
${download_url_name[0]}
+
${download_url_name[1]}
+
${download_url_name[2]}
+
${download_url_name[3]}
+
${download_url_name[4]}
+
${download_url_name[5]}
+
` + $(this).next().after(html) + }) + // 修改[文件大小]元素样式 + document.querySelectorAll('small.pl-2.text-gray.flex-shrink-0').forEach(el => el.style.cssText = 'display: flex; justify-content: flex-end; flex-grow: 1; margin-right: 8px;') + + // Source Code + $(this).find('.d-block.Box-body>a').each(function () { + var href = $(this).attr('href') + var url = [ + download_url[0] + '/https://github.com' + href, + download_url[1] + '/https://github.com' + href, + download_url[2] + href, + download_url[3] + '/https://github.com' + href, + download_url[4] + '/https://github.com' + href, + download_url[5] + '/https://github.com' + href + ] + var html = `
+
${download_url_name[0]}
+
${download_url_name[1]}
+
${download_url_name[2]}
+
${download_url_name[3]}
+
${download_url_name[4]}
+
${download_url_name[5]}
+
` + $(this).after(html) + }) + }) + // 修改 Source code 样式,使其和加速按钮并列一排 + document.querySelectorAll('div.d-block.py-1.py-md-2.Box-body.px-2').forEach(el => el.className = 'd-flex py-1 py-md-2 Box-body px-2') + } + + // Download ZIP + function addDownloadZIP () { + $('.dropdown-menu.dropdown-menu-sw.p-0 ul li:last-child').each(function () { + var href = $(this).children('a').attr('href') + var url = [ + download_url[0] + '/https://github.com' + href, + download_url[1] + '/https://github.com' + href, + download_url[2] + href, + download_url[3] + '/https://github.com' + href, + download_url[4] + '/https://github.com' + href, + download_url[5] + '/https://github.com' + href + ] + var html = ` +
  • ${svg[0]}Download ZIP ${download_url_name[0]}
  • +
  • ${svg[0]}Download ZIP ${download_url_name[1]}
  • +
  • ${svg[0]}Download ZIP ${download_url_name[2]}
  • +
  • ${svg[0]}Download ZIP ${download_url_name[3]}
  • +
  • ${svg[0]}Download ZIP ${download_url_name[4]}
  • +
  • ${svg[0]}Download ZIP ${download_url_name[5]}
  • +` + $(this).after(html) + }) + } + + // Git Clone + function addGitClone () { + $("[role='tabpanel'] div.input-group").first().each(function () { + var href_split = location.href.split('/') + var url = [ + clone_url[0] + '/' + href_split[3] + '/' + href_split[4] + '.git', + clone_url[1] + '/github.com/' + href_split[3] + '/' + href_split[4] + '.git', + clone_url[2] + '/' + href_split[3] + '/' + href_split[4] + '.git' + ] + var html = ` +
    ${svg[1]}
    +
    ${svg[1]}
    +
    ${svg[1]}
    +` + $(this).after(html) + }) + } + + // Raw + function addRawFile () { + $('#raw-url').each(function () { + var href = location.href.replace('https://github.com', '') + var href2 = href.replace('/blob/', '/') + var url = [ + raw_url[1] + '/gh' + href.replace('/blob/', '@'), + raw_url[2] + href2, + download_url[5] + '/' + raw_url[0] + href2 + ] + var html = ` +${raw_url_name[1]} +${raw_url_name[2]} +${raw_url_name[3]} +` + $(this).after(html) + }) + } + + // 添加 Raw 下载链接(☁) + function addDownLink () { + // 如果不是项目文件页面,就返回 + var files = $('div.Box-row svg.octicon.octicon-file') + if (files.length === 0) return + var files1 = $('a.fileDownLink') + if (files1.length > 0) return + + // 鼠标指向则显示 + var mouseOverHandler = function (evt) { + var elem = evt.currentTarget + var aElm_new = elem.querySelectorAll('.fileDownLink') + var aElm_now = elem.querySelectorAll('svg.octicon.octicon-file.text-gray-light') + aElm_new.forEach(el => el.style.cssText = 'display: inline') + aElm_now.forEach(el => el.style.cssText = 'display: none') + } + + // 鼠标离开则隐藏 + var mouseOutHandler = function (evt) { + var elem = evt.currentTarget + var aElm_new = elem.querySelectorAll('.fileDownLink') + var aElm_now = elem.querySelectorAll('svg.octicon.octicon-file.text-gray-light') + aElm_new.forEach(el => el.style.cssText = 'display: none') + aElm_now.forEach(el => el.style.cssText = 'display: inline') + } + + // 循环添加 + files.each(function (i, fileElm) { + var trElm = fileElm.parentNode.parentNode + var cntElm_a = trElm.querySelector('.css-truncate.css-truncate-target.d-block.width-fit a') + var cntElm_svg = trElm.querySelector('.mr-3.flex-shrink-0 svg.octicon.octicon-file.text-gray-light') + var Name = cntElm_a.innerText + var href = cntElm_a.attributes.href.nodeValue.replace('https://github.com', '') + var href2 = href.replace('/blob/', '/'); var url; var url_name; var url_tip = '' + switch (menu_raw_fast) { + case 0: + url = raw_url[0] + href2 + url_name = raw_url_name[0] + url_tip = raw_url_tip[0] + break + case 1: + url = raw_url[1] + '/gh' + href.replace('/blob/', '@') + url_name = raw_url_name[1] + url_tip = raw_url_tip[1] + break + case 2: + url = raw_url[2] + href2 + url_name = raw_url_name[2] + url_tip = raw_url_tip[2] + break + case 3: + url = download_url[5] + '/' + raw_url[0] + href2 + url_name = download_url_name[5] + url_tip = raw_url_tip[3] + break + } + var html = ` ` + $(cntElm_svg).after(html) + // 绑定鼠标事件 + trElm.onmouseover = mouseOverHandler + trElm.onmouseout = mouseOutHandler + }) + } + + // 删除 Raw 快捷下载(☁) + function delDownLink () { + var aElm = document.querySelectorAll('.fileDownLink') + for (var num = 0; num < aElm.length; num++) { + aElm[num].remove() + }; + } +})() diff --git a/packages/mitmproxy/src/lib/proxy/middleware/FilterMiddleware.js b/packages/mitmproxy/src/lib/proxy/middleware/FilterMiddleware.js deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/mitmproxy/src/lib/proxy/middleware/HtmlMiddleware.js b/packages/mitmproxy/src/lib/proxy/middleware/HtmlMiddleware.js index 9ef8ae9e..785f4ac0 100644 --- a/packages/mitmproxy/src/lib/proxy/middleware/HtmlMiddleware.js +++ b/packages/mitmproxy/src/lib/proxy/middleware/HtmlMiddleware.js @@ -3,56 +3,46 @@ const zlib = require('zlib') // eslint-disable-next-line no-unused-vars const url = require('url') -const httpUtil = {} +var httpUtil = {} httpUtil.isGzip = function (res) { - const contentEncoding = res.headers['content-encoding'] + var contentEncoding = res.headers['content-encoding'] return !!(contentEncoding && contentEncoding.toLowerCase() === 'gzip') } httpUtil.isHtml = function (res) { - const contentType = res.headers['content-type'] + var contentType = res.headers['content-type'] return (typeof contentType !== 'undefined') && /text\/html|application\/xhtml\+xml/.test(contentType) } -// eslint-disable-next-line no-unused-vars -function injectContentIntoHtmlHead (html, content) { +function injectScriptIntoHeadHtml (html, script) { html = html.replace(/(<\/head>)/i, function (match) { - return content + match - }) - return html -} -function injectScriptIntoHtmlHead (html, content) { - return html -} -function injectContentIntoHtmlBody (html, content) { - html = html.replace(/(<\/body>)/i, function (match) { - return content + match + return script + match }) return html } -function chunkReplace (_this, chunk, enc, callback, headContent, bodyContent) { +function injectScriptIntoBodyHtml (html, script) { + html = html.replace(/(<\/body>)/i, function (match) { + return script + match + }) + return html +} + +function chunkReplace (_this, chunk, enc, callback, append) { let chunkString = chunk.toString() - if (headContent) { - chunkString = injectScriptIntoHtmlHead(chunkString, headContent) + if (append && append.head) { + chunkString = injectScriptIntoHeadHtml(chunkString, append.head) } - if (bodyContent) { - chunkString = injectContentIntoHtmlBody(chunkString, bodyContent) + if (append && append.body) { + chunkString = injectScriptIntoBodyHtml(chunkString, append.body) } - _this.push(Buffer.alloc(chunkString)) + // eslint-disable-next-line node/no-deprecated-api + _this.push(new Buffer(chunkString)) callback() } -module.exports = class InjectHtmlPlugin { - constructor ({ - head, - body - }) { - this.head = head - this.body = body - } - - responseInterceptor (req, res, proxyReq, proxyRes, ssl, next) { - if (!this.head && !this.body) { +module.exports = { + responseInterceptor (req, res, proxyReq, proxyRes, ssl, next, append) { + if (!append.head && !append.body) { next() return } @@ -66,10 +56,10 @@ module.exports = class InjectHtmlPlugin { } else { Object.keys(proxyRes.headers).forEach(function (key) { if (proxyRes.headers[key] !== undefined) { - let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => { - return match.toUpperCase() - }) - newkey = key + // let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => { + // return match.toUpperCase() + // }) + const newkey = key if (isHtml && key === 'content-length') { // do nothing } else { @@ -85,11 +75,11 @@ module.exports = class InjectHtmlPlugin { if (isGzip) { proxyRes.pipe(new zlib.Gunzip()) .pipe(through(function (chunk, enc, callback) { - chunkReplace(this, chunk, enc, callback, this.head, this.body) + chunkReplace(this, chunk, enc, callback, append) })).pipe(new zlib.Gzip()).pipe(res) } else { proxyRes.pipe(through(function (chunk, enc, callback) { - chunkReplace(this, chunk, enc, callback, this.head, this.body) + chunkReplace(this, chunk, enc, callback, append) })).pipe(res) } } diff --git a/packages/mitmproxy/src/lib/proxy/middleware/MapLocalMiddleware.js b/packages/mitmproxy/src/lib/proxy/middleware/MapLocalMiddleware.js deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/mitmproxy/src/lib/proxy/middleware/MapRemoteMiddleware.js b/packages/mitmproxy/src/lib/proxy/middleware/MapRemoteMiddleware.js deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/mitmproxy/src/lib/proxy/mitmproxy/createRequestHandler.js b/packages/mitmproxy/src/lib/proxy/mitmproxy/createRequestHandler.js index b1a25262..11f10601 100644 --- a/packages/mitmproxy/src/lib/proxy/mitmproxy/createRequestHandler.js +++ b/packages/mitmproxy/src/lib/proxy/mitmproxy/createRequestHandler.js @@ -4,8 +4,9 @@ const commonUtil = require('../common/util') // const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i const DnsUtil = require('../../dns/index') const log = require('../../../utils/util.log') +const HtmlMiddleware = require('../middleware/HtmlMiddleware') // create requestHandler function -module.exports = function createRequestHandler (requestInterceptor, responseInterceptor, middlewares, externalProxy, dnsConfig) { +module.exports = function createRequestHandler (createIntercepts, externalProxy, dnsConfig) { // return return function requestHandler (req, res, ssl) { let proxyReq @@ -18,7 +19,12 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte } else { req.socket.setKeepAlive(true, 30000) } - const context = {} + let interceptors = createIntercepts(rOptions) + if (interceptors == null) { + interceptors = [] + } + const reqIncpts = interceptors.filter(item => { return item.requestIntercept != null }) + const resIncpts = interceptors.filter(item => { return item.responseIntercept != null }) const requestInterceptorPromise = () => { return new Promise((resolve, reject) => { @@ -26,10 +32,17 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte resolve() } try { - if (typeof requestInterceptor === 'function') { - requestInterceptor(rOptions, req, res, ssl, next, context) + if (reqIncpts && reqIncpts.length > 0) { + for (const reqIncpt of reqIncpts) { + const writableEnded = reqIncpt.requestIntercept(req, res, ssl) + if (writableEnded) { + next() + return + } + } + next() } else { - resolve() + next() } } catch (e) { reject(e) @@ -39,15 +52,6 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte const proxyRequestPromise = async () => { rOptions.host = rOptions.hostname || rOptions.host || 'localhost' - // if (dnsConfig) { - // const dns = DnsUtil.hasDnsLookup(dnsConfig, rOptions.host) - // if (dns) { - // const ip = await dns.lookup(rOptions.host) - // log.info('使用自定义dns:', rOptions.host, ip, dns.dnsServer) - // rOptions.host = ip - // } - // } - return new Promise((resolve, reject) => { // use the binded socket for NTLM if (rOptions.agent && rOptions.customSocketId != null && rOptions.agent.getName) { @@ -116,7 +120,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte proxyReq.on('aborted', () => { log.error('代理请求被取消', rOptions.hostname, rOptions.path) - if (res.finished) { + if (res.writableEnded) { return } reject(new Error('代理请求被取消')) @@ -125,7 +129,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte req.on('aborted', function () { log.error('请求被取消', rOptions.hostname, rOptions.path) proxyReq.abort() - if (res.finished) { + if (res.writableEnded) { return } reject(new Error('请求被取消')) @@ -147,21 +151,39 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte (async () => { await requestInterceptorPromise() - if (res.finished) { + if (res.writableEnded) { return false } const proxyRes = await proxyRequestPromise() + // proxyRes.on('data', (chunk) => { + // // console.log('BODY: ') + // }) + proxyRes.on('error', (error) => { + log.error('proxy res error', error) + }) + const responseInterceptorPromise = new Promise((resolve, reject) => { const next = () => { resolve() } try { - if (typeof responseInterceptor === 'function') { - responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, context) + if (resIncpts && resIncpts.length > 0) { + let head = '' + let body = '' + for (const resIncpt of resIncpts) { + const append = resIncpt.responseIntercept(req, res, proxyReq, proxyRes, ssl) + if (append && append.head) { + head += append.head + } + if (append && append.body) { + body += append.body + } + } + HtmlMiddleware.responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, { head, body }) } else { - resolve() + next() } } catch (e) { reject(e) @@ -170,10 +192,6 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte await responseInterceptorPromise - if (res.finished) { - return false - } - if (!res.headersSent) { // prevent duplicate set headers Object.keys(proxyRes.headers).forEach(function (key) { if (proxyRes.headers[key] !== undefined) { @@ -194,9 +212,10 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte })().then( (flag) => { // do nothing + // console.log('res', flag) }, (e) => { - if (!res.finished) { + if (!res.writableEnded) { const status = e.status || 500 res.writeHead(status) res.write(`DevSidecar Warning:\n\n ${e.toString()}`) diff --git a/packages/mitmproxy/src/lib/proxy/mitmproxy/index.js b/packages/mitmproxy/src/lib/proxy/mitmproxy/index.js index 72125efe..5a9061d2 100644 --- a/packages/mitmproxy/src/lib/proxy/mitmproxy/index.js +++ b/packages/mitmproxy/src/lib/proxy/mitmproxy/index.js @@ -12,8 +12,7 @@ module.exports = { caCertPath, caKeyPath, sslConnectInterceptor, - requestInterceptor, - responseInterceptor, + createIntercepts, getCertSocketTimeout = 1 * 1000, middlewares = [], externalProxy, @@ -34,8 +33,7 @@ module.exports = { port = ~~port const requestHandler = createRequestHandler( - requestInterceptor, - responseInterceptor, + createIntercepts, middlewares, externalProxy, dnsConfig diff --git a/packages/mitmproxy/src/options.js b/packages/mitmproxy/src/options.js index b044879b..53850416 100644 --- a/packages/mitmproxy/src/options.js +++ b/packages/mitmproxy/src/options.js @@ -63,41 +63,41 @@ module.exports = (config) => { } return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理 }, - requestInterceptor: (rOptions, req, res, ssl, next, context) => { + createIntercepts: (rOptions) => { const hostname = rOptions.hostname const interceptOpts = matchHostname(intercepts, hostname) if (!interceptOpts) { // 该域名没有配置拦截器,直接过 - next() return } + const matchIntercepts = [] for (const regexp in interceptOpts) { // 遍历拦截配置 const interceptOpt = interceptOpts[regexp] if (regexp !== true) { - if (!isMatched(req.url, regexp)) { + if (!isMatched(rOptions.path, regexp)) { continue } } - for (const interceptImpl of interceptors) { + for (const impl of interceptors) { // 根据拦截配置挑选合适的拦截器来处理 - if (!interceptImpl.is(interceptOpt) && interceptImpl.requestInterceptor) { - continue - } - try { - const result = interceptImpl.requestInterceptor(interceptOpt, rOptions, req, res, ssl, context) - if (result) { // 拦截成功,其他拦截器就不处理了 - return + if (impl.is(interceptOpt)) { + const interceptor = {} + if (impl.requestIntercept) { + // req拦截器 + interceptor.requestIntercept = (req, res, ssl) => { + impl.requestIntercept(interceptOpt, rOptions, req, res, ssl) + } + } else if (impl.responseIntercept) { + // res拦截器 + interceptor.responseIntercept = (req, res, proxyReq, proxyRes, ssl) => { + impl.responseIntercept(interceptOpt, rOptions, req, res, proxyReq, proxyRes, ssl) + } } - } catch (err) { - // 拦截失败 - log.error('拦截器执行错误', err) + matchIntercepts.push(interceptor) } } } - next() - }, - responseInterceptor: (req, res, proxyReq, proxyRes, ssl, next, context) => { - next() + return matchIntercepts } } } diff --git a/packages/mitmproxy/test/lib/monkey/indexTest.js b/packages/mitmproxy/test/lib/monkey/indexTest.js new file mode 100644 index 00000000..a6c1cdc3 --- /dev/null +++ b/packages/mitmproxy/test/lib/monkey/indexTest.js @@ -0,0 +1,3 @@ +const monkey = require('../../../src/lib/monkey/index') +const scripts = monkey.load() +console.log(scripts[0])