feat: response拦截器
parent
278ae695ca
commit
922c8d667b
|
@ -15,7 +15,8 @@
|
||||||
### 2、 dns优选
|
### 2、 dns优选
|
||||||
根据网络状况智能解析域名ip地址,获取最佳网络速度
|
根据网络状况智能解析域名ip地址,获取最佳网络速度
|
||||||
比如:
|
比如:
|
||||||
1. 解决git push 偶尔失败需要输入账号密码的问题(fatal: TaskCanceledException encountered)
|
1. 解决git push 偶尔失败需要输入账号密码的问题(
|
||||||
|
fatal: TaskCanceledException encountered / fatal: HttpRequestException encountered)
|
||||||
2. 解决github头像加载不出来的问题
|
2. 解决github头像加载不出来的问题
|
||||||
3. 解决gist.github.com访问不到的问题
|
3. 解决gist.github.com访问不到的问题
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ module.exports = {
|
||||||
},
|
},
|
||||||
'/.*/.*/blame/': {
|
'/.*/.*/blame/': {
|
||||||
redirect: 'hub.fastgit.org'
|
redirect: 'hub.fastgit.org'
|
||||||
|
},
|
||||||
|
'/.*/[^\\/]*$': {
|
||||||
|
script: 'console.log("123123132")'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'raw.githubusercontent.com': {
|
'raw.githubusercontent.com': {
|
||||||
|
@ -101,12 +104,12 @@ module.exports = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mapping: {
|
mapping: {
|
||||||
'img.shields.io': 'aliyun',
|
'img.shields.io': 'usa',
|
||||||
'*.github.com': 'aliyun',
|
'*.github.com': 'usa',
|
||||||
'*.githubusercontent.com': 'aliyun',
|
'*.githubusercontent.com': 'usa',
|
||||||
'*.githubassets.com': 'aliyun',
|
'*.githubassets.com': 'usa',
|
||||||
// "解决push的时候需要输入密码的问题",
|
// "解决push的时候需要输入密码的问题",
|
||||||
'github.com': 'aliyun'
|
'github.com': 'usa'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
module.exports = function createIntercept (context) {
|
module.exports = function createIntercept (context) {
|
||||||
const { log } = context
|
const { log } = context
|
||||||
return {
|
return {
|
||||||
requestInterceptor (interceptOpt, rOptions, req, res, ssl) {
|
requestIntercept (interceptOpt, rOptions, req, res, ssl) {
|
||||||
log.info('abort:', rOptions.hostname, req.url)
|
log.info('abort:', rOptions.hostname, req.url)
|
||||||
res.writeHead(403)
|
res.writeHead(403)
|
||||||
res.write('DevSidecar 403: \n\n request abort, this request is matched by abort intercept.\n\n 因配置abort拦截器,本请求将取消')
|
res.write('DevSidecar 403: \n\n request abort, this request is matched by abort intercept.\n\n 因配置abort拦截器,本请求将取消')
|
||||||
res.end()
|
res.end()
|
||||||
|
return true// 是否结束
|
||||||
},
|
},
|
||||||
is (interceptOpt) {
|
is (interceptOpt) {
|
||||||
return !!interceptOpt.abort
|
return !!interceptOpt.abort
|
||||||
|
|
|
@ -2,13 +2,13 @@ const url = require('url')
|
||||||
module.exports = function createInterceptor (context) {
|
module.exports = function createInterceptor (context) {
|
||||||
const { log } = context
|
const { log } = context
|
||||||
return {
|
return {
|
||||||
requestInterceptor (interceptOpt, rOptions, req, res, ssl, next) {
|
requestIntercept (interceptOpt, rOptions, req, res, ssl, next) {
|
||||||
let proxyTarget = interceptOpt.proxy + req.url
|
let proxyTarget = interceptOpt.proxy + req.url
|
||||||
if (interceptOpt.replace) {
|
if (interceptOpt.replace) {
|
||||||
const regexp = new RegExp(interceptOpt.replace)
|
const regexp = new RegExp(interceptOpt.replace)
|
||||||
proxyTarget = req.url.replace(regexp, interceptOpt.proxy)
|
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 backup = interceptOpt.backup
|
||||||
const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : rOptions.protocol + '//' + proxyTarget
|
const proxy = proxyTarget.indexOf('http') === 0 ? proxyTarget : rOptions.protocol + '//' + proxyTarget
|
||||||
// eslint-disable-next-line node/no-deprecated-api
|
// eslint-disable-next-line node/no-deprecated-api
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module.exports = function createInterceptor (context) {
|
module.exports = function createInterceptor (context) {
|
||||||
const { log } = context
|
const { log } = context
|
||||||
return {
|
return {
|
||||||
requestInterceptor (interceptOpt, rOptions, req, res, ssl) {
|
requestIntercept (interceptOpt, rOptions, req, res, ssl) {
|
||||||
const url = req.url
|
const url = req.url
|
||||||
let redirect
|
let redirect
|
||||||
if (typeof interceptOpt.redirect === 'string') {
|
if (typeof interceptOpt.redirect === 'string') {
|
||||||
|
@ -12,7 +12,7 @@ module.exports = function createInterceptor (context) {
|
||||||
log.info('请求重定向:', rOptions.hostname, url, redirect)
|
log.info('请求重定向:', rOptions.hostname, url, redirect)
|
||||||
res.writeHead(302, { Location: redirect })
|
res.writeHead(302, { Location: redirect })
|
||||||
res.end()
|
res.end()
|
||||||
return true
|
return true// 是否结束
|
||||||
},
|
},
|
||||||
is (interceptOpt) {
|
is (interceptOpt) {
|
||||||
return interceptOpt.redirect // 如果配置中有redirect,那么这个配置是需要redirect拦截的
|
return interceptOpt.redirect // 如果配置中有redirect,那么这个配置是需要redirect拦截的
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
module.exports = function createInterceptor (context) {
|
||||||
|
const { log } = context
|
||||||
|
return {
|
||||||
|
responseIntercept (interceptOpt, rOptions, req, res, proxyReq, proxyRes, ssl) {
|
||||||
|
const script = `
|
||||||
|
<script>
|
||||||
|
try{
|
||||||
|
${interceptOpt.script}
|
||||||
|
}catch (err){
|
||||||
|
console.error('脚本执行出错:',err)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
`
|
||||||
|
log.info('responseIntercept: body script', rOptions.hostname, rOptions.path)
|
||||||
|
return {
|
||||||
|
body: script
|
||||||
|
}
|
||||||
|
},
|
||||||
|
is (interceptOpt) {
|
||||||
|
return interceptOpt.script
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
const proxy = require('./impl/proxy')
|
const proxy = require('./impl/proxy')
|
||||||
const redirect = require('./impl/redirect')
|
const redirect = require('./impl/redirect')
|
||||||
const abort = require('./impl/abort')
|
const abort = require('./impl/abort')
|
||||||
|
const script = require('./impl/script')
|
||||||
const log = require('../../utils/util.log')
|
const log = require('../../utils/util.log')
|
||||||
const context = { 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
|
module.exports = modules
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
const Monkey_Grants = {
|
||||||
|
GM_registerMenuCommand: () => {},
|
||||||
|
GM_unregisterMenuCommand: () => {},
|
||||||
|
GM_openInTab: () => {},
|
||||||
|
GM_getValue: () => {},
|
||||||
|
GM_setValue: () => {},
|
||||||
|
GM_notification: () => {}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 = [
|
||||||
|
'<svg class="octicon octicon-file-zip mr-3" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M3.5 1.75a.25.25 0 01.25-.25h3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h2.086a.25.25 0 01.177.073l2.914 2.914a.25.25 0 01.073.177v8.586a.25.25 0 01-.25.25h-.5a.75.75 0 000 1.5h.5A1.75 1.75 0 0014 13.25V4.664c0-.464-.184-.909-.513-1.237L10.573.513A1.75 1.75 0 009.336 0H3.75A1.75 1.75 0 002 1.75v11.5c0 .649.353 1.214.874 1.515a.75.75 0 10.752-1.298.25.25 0 01-.126-.217V1.75zM8.75 3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM6 5.25a.75.75 0 01.75-.75h.5a.75.75 0 010 1.5h-.5A.75.75 0 016 5.25zm2 1.5A.75.75 0 018.75 6h.5a.75.75 0 010 1.5h-.5A.75.75 0 018 6.75zm-1.25.75a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM8 9.75A.75.75 0 018.75 9h.5a.75.75 0 010 1.5h-.5A.75.75 0 018 9.75zm-.75.75a1.75 1.75 0 00-1.75 1.75v3c0 .414.336.75.75.75h2.5a.75.75 0 00.75-.75v-3a1.75 1.75 0 00-1.75-1.75h-.5zM7 12.25a.25.25 0 01.25-.25h.5a.25.25 0 01.25.25v2.25H7v-2.25z"></path></svg>',
|
||||||
|
'<svg class="octicon octicon-clippy" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path fill-rule="evenodd" d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z"></path></svg>',
|
||||||
|
'<svg class="octicon octicon-cloud-download" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M9 12h2l-3 3-3-3h2V7h2v5zm3-8c0-.44-.91-3-4.5-3C5.08 1 3 2.92 3 5 1.02 5 0 6.52 0 8c0 1.53 1 3 3 3h3V9.7H3C1.38 9.7 1.3 8.28 1.3 8c0-.17.05-1.7 1.7-1.7h1.3V5c0-1.39 1.56-2.7 3.2-2.7 2.55 0 3.13 1.55 3.2 1.8v1.2H12c.81 0 2.7.22 2.7 2.2 0 2.09-2.25 2.2-2.7 2.2h-2V11h2c2.08 0 4-1.16 4-3.5C16 5.06 14.08 4 12 4z"></path></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 = `<div style="display: flex;justify-content: flex-end;">
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[0]}" rel="noreferrer noopener nofollow">${download_url_name[0]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[1]}" rel="noreferrer noopener nofollow">${download_url_name[1]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[2]}" rel="noreferrer noopener nofollow">${download_url_name[2]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[3]}" rel="noreferrer noopener nofollow">${download_url_name[3]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[4]}" rel="noreferrer noopener nofollow">${download_url_name[4]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[5]}" rel="noreferrer noopener nofollow">${download_url_name[5]}</a></div>
|
||||||
|
</div>`
|
||||||
|
$(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 = `<div style="display: flex;justify-content: flex-end;flex-grow: 1;">
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[0]}" rel="noreferrer noopener nofollow">${download_url_name[0]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[1]}" rel="noreferrer noopener nofollow">${download_url_name[1]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[2]}" rel="noreferrer noopener nofollow">${download_url_name[2]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[3]}" rel="noreferrer noopener nofollow">${download_url_name[3]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[4]}" rel="noreferrer noopener nofollow">${download_url_name[4]}</a></div>
|
||||||
|
<div><a style="${style[0]}" class="btn" href="${url[5]}" rel="noreferrer noopener nofollow">${download_url_name[5]}</a></div>
|
||||||
|
</div>`
|
||||||
|
$(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 = `
|
||||||
|
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[0]}">${svg[0]}Download ZIP ${download_url_name[0]}</a></li>
|
||||||
|
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[1]}">${svg[0]}Download ZIP ${download_url_name[1]}</a></li>
|
||||||
|
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[2]}">${svg[0]}Download ZIP ${download_url_name[2]}</a></li>
|
||||||
|
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[3]}">${svg[0]}Download ZIP ${download_url_name[3]}</a></li>
|
||||||
|
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[4]}">${svg[0]}Download ZIP ${download_url_name[4]}</a></li>
|
||||||
|
<li class="Box-row Box-row--hover-gray p-0"><a class="d-flex flex-items-center text-gray-dark text-bold no-underline p-3" rel="noreferrer noopener nofollow" href="${url[5]}">${svg[0]}Download ZIP ${download_url_name[5]}</a></li>
|
||||||
|
`
|
||||||
|
$(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 = `
|
||||||
|
<div class="input-group" style="margin-top: 4px;"><input value="${url[0]}" aria-label="${url[0]}" type="text" class="form-control input-monospace input-sm bg-gray-light" data-autoselect="" readonly=""><div class="input-group-button"><clipboard-copy value="${url[0]}" aria-label="Copy to clipboard" class="btn btn-sm" tabindex="0" role="button">${svg[1]}</clipboard-copy></div></div>
|
||||||
|
<div class="input-group" style="margin-top: 4px;"><input value="${url[1]}" aria-label="${url[1]}" type="text" class="form-control input-monospace input-sm bg-gray-light" data-autoselect="" readonly=""><div class="input-group-button"><clipboard-copy value="${url[1]}" aria-label="Copy to clipboard" class="btn btn-sm" tabindex="0" role="button">${svg[1]}</clipboard-copy></div></div>
|
||||||
|
<div class="input-group" style="margin-top: 4px;"><input value="${url[2]}" aria-label="${url[2]}" type="text" class="form-control input-monospace input-sm bg-gray-light" data-autoselect="" readonly=""><div class="input-group-button"><clipboard-copy value="${url[2]}" aria-label="Copy to clipboard" class="btn btn-sm" tabindex="0" role="button">${svg[1]}</clipboard-copy></div></div>
|
||||||
|
`
|
||||||
|
$(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 = `
|
||||||
|
<a href="${url[0]}" title="${raw_url_tip[1]}" role="button" rel="noreferrer noopener nofollow" class="btn btn-sm BtnGroup-item">${raw_url_name[1]}</a>
|
||||||
|
<a href="${url[1]}" title="${raw_url_tip[2]}" role="button" rel="noreferrer noopener nofollow" class="btn btn-sm BtnGroup-item">${raw_url_name[2]}</a>
|
||||||
|
<a href="${url[2]}" title="${raw_url_tip[3]}" role="button" rel="noreferrer noopener nofollow" class="btn btn-sm BtnGroup-item">${raw_url_name[3]}</a>
|
||||||
|
`
|
||||||
|
$(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 = ` <a href="${url}" download="${Name}" target="_blank" rel="noreferrer noopener nofollow" class="fileDownLink" style="display: none;" title="「${url_name}」 [Alt + 左键] 或 [右键 - 另存为...] 下载文件。 注意:鼠标点击 [☁] 图标,而不是左侧的文件名! ${url_tip}提示:点击浏览器右上角 Tampermonkey 扩展图标 - [ ${raw_url_name[menu_raw_fast]} ] 加速源 (☁) 即可切换。">${svg[2]}</a>`
|
||||||
|
$(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()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})()
|
|
@ -3,56 +3,46 @@ const zlib = require('zlib')
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
const url = require('url')
|
const url = require('url')
|
||||||
|
|
||||||
const httpUtil = {}
|
var httpUtil = {}
|
||||||
httpUtil.isGzip = function (res) {
|
httpUtil.isGzip = function (res) {
|
||||||
const contentEncoding = res.headers['content-encoding']
|
var contentEncoding = res.headers['content-encoding']
|
||||||
return !!(contentEncoding && contentEncoding.toLowerCase() === 'gzip')
|
return !!(contentEncoding && contentEncoding.toLowerCase() === 'gzip')
|
||||||
}
|
}
|
||||||
httpUtil.isHtml = function (res) {
|
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)
|
return (typeof contentType !== 'undefined') && /text\/html|application\/xhtml\+xml/.test(contentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
function injectScriptIntoHeadHtml (html, script) {
|
||||||
function injectContentIntoHtmlHead (html, content) {
|
|
||||||
html = html.replace(/(<\/head>)/i, function (match) {
|
html = html.replace(/(<\/head>)/i, function (match) {
|
||||||
return content + match
|
return script + match
|
||||||
})
|
|
||||||
return html
|
|
||||||
}
|
|
||||||
function injectScriptIntoHtmlHead (html, content) {
|
|
||||||
return html
|
|
||||||
}
|
|
||||||
function injectContentIntoHtmlBody (html, content) {
|
|
||||||
html = html.replace(/(<\/body>)/i, function (match) {
|
|
||||||
return content + match
|
|
||||||
})
|
})
|
||||||
return html
|
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()
|
let chunkString = chunk.toString()
|
||||||
if (headContent) {
|
if (append && append.head) {
|
||||||
chunkString = injectScriptIntoHtmlHead(chunkString, headContent)
|
chunkString = injectScriptIntoHeadHtml(chunkString, append.head)
|
||||||
}
|
}
|
||||||
if (bodyContent) {
|
if (append && append.body) {
|
||||||
chunkString = injectContentIntoHtmlBody(chunkString, bodyContent)
|
chunkString = injectScriptIntoBodyHtml(chunkString, append.body)
|
||||||
}
|
}
|
||||||
_this.push(Buffer.alloc(chunkString))
|
// eslint-disable-next-line node/no-deprecated-api
|
||||||
|
_this.push(new Buffer(chunkString))
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = class InjectHtmlPlugin {
|
module.exports = {
|
||||||
constructor ({
|
responseInterceptor (req, res, proxyReq, proxyRes, ssl, next, append) {
|
||||||
head,
|
if (!append.head && !append.body) {
|
||||||
body
|
|
||||||
}) {
|
|
||||||
this.head = head
|
|
||||||
this.body = body
|
|
||||||
}
|
|
||||||
|
|
||||||
responseInterceptor (req, res, proxyReq, proxyRes, ssl, next) {
|
|
||||||
if (!this.head && !this.body) {
|
|
||||||
next()
|
next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -66,10 +56,10 @@ module.exports = class InjectHtmlPlugin {
|
||||||
} else {
|
} else {
|
||||||
Object.keys(proxyRes.headers).forEach(function (key) {
|
Object.keys(proxyRes.headers).forEach(function (key) {
|
||||||
if (proxyRes.headers[key] !== undefined) {
|
if (proxyRes.headers[key] !== undefined) {
|
||||||
let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => {
|
// let newkey = key.replace(/^[a-z]|-[a-z]/g, (match) => {
|
||||||
return match.toUpperCase()
|
// return match.toUpperCase()
|
||||||
})
|
// })
|
||||||
newkey = key
|
const newkey = key
|
||||||
if (isHtml && key === 'content-length') {
|
if (isHtml && key === 'content-length') {
|
||||||
// do nothing
|
// do nothing
|
||||||
} else {
|
} else {
|
||||||
|
@ -85,11 +75,11 @@ module.exports = class InjectHtmlPlugin {
|
||||||
if (isGzip) {
|
if (isGzip) {
|
||||||
proxyRes.pipe(new zlib.Gunzip())
|
proxyRes.pipe(new zlib.Gunzip())
|
||||||
.pipe(through(function (chunk, enc, callback) {
|
.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)
|
})).pipe(new zlib.Gzip()).pipe(res)
|
||||||
} else {
|
} else {
|
||||||
proxyRes.pipe(through(function (chunk, enc, callback) {
|
proxyRes.pipe(through(function (chunk, enc, callback) {
|
||||||
chunkReplace(this, chunk, enc, callback, this.head, this.body)
|
chunkReplace(this, chunk, enc, callback, append)
|
||||||
})).pipe(res)
|
})).pipe(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,9 @@ const commonUtil = require('../common/util')
|
||||||
// const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i
|
// const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i
|
||||||
const DnsUtil = require('../../dns/index')
|
const DnsUtil = require('../../dns/index')
|
||||||
const log = require('../../../utils/util.log')
|
const log = require('../../../utils/util.log')
|
||||||
|
const HtmlMiddleware = require('../middleware/HtmlMiddleware')
|
||||||
// create requestHandler function
|
// create requestHandler function
|
||||||
module.exports = function createRequestHandler (requestInterceptor, responseInterceptor, middlewares, externalProxy, dnsConfig) {
|
module.exports = function createRequestHandler (createIntercepts, externalProxy, dnsConfig) {
|
||||||
// return
|
// return
|
||||||
return function requestHandler (req, res, ssl) {
|
return function requestHandler (req, res, ssl) {
|
||||||
let proxyReq
|
let proxyReq
|
||||||
|
@ -18,7 +19,12 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
} else {
|
} else {
|
||||||
req.socket.setKeepAlive(true, 30000)
|
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 = () => {
|
const requestInterceptorPromise = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -26,10 +32,17 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (typeof requestInterceptor === 'function') {
|
if (reqIncpts && reqIncpts.length > 0) {
|
||||||
requestInterceptor(rOptions, req, res, ssl, next, context)
|
for (const reqIncpt of reqIncpts) {
|
||||||
|
const writableEnded = reqIncpt.requestIntercept(req, res, ssl)
|
||||||
|
if (writableEnded) {
|
||||||
|
next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next()
|
||||||
} else {
|
} else {
|
||||||
resolve()
|
next()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e)
|
reject(e)
|
||||||
|
@ -39,15 +52,6 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
|
|
||||||
const proxyRequestPromise = async () => {
|
const proxyRequestPromise = async () => {
|
||||||
rOptions.host = rOptions.hostname || rOptions.host || 'localhost'
|
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) => {
|
return new Promise((resolve, reject) => {
|
||||||
// use the binded socket for NTLM
|
// use the binded socket for NTLM
|
||||||
if (rOptions.agent && rOptions.customSocketId != null && rOptions.agent.getName) {
|
if (rOptions.agent && rOptions.customSocketId != null && rOptions.agent.getName) {
|
||||||
|
@ -116,7 +120,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
|
|
||||||
proxyReq.on('aborted', () => {
|
proxyReq.on('aborted', () => {
|
||||||
log.error('代理请求被取消', rOptions.hostname, rOptions.path)
|
log.error('代理请求被取消', rOptions.hostname, rOptions.path)
|
||||||
if (res.finished) {
|
if (res.writableEnded) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reject(new Error('代理请求被取消'))
|
reject(new Error('代理请求被取消'))
|
||||||
|
@ -125,7 +129,7 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
req.on('aborted', function () {
|
req.on('aborted', function () {
|
||||||
log.error('请求被取消', rOptions.hostname, rOptions.path)
|
log.error('请求被取消', rOptions.hostname, rOptions.path)
|
||||||
proxyReq.abort()
|
proxyReq.abort()
|
||||||
if (res.finished) {
|
if (res.writableEnded) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reject(new Error('请求被取消'))
|
reject(new Error('请求被取消'))
|
||||||
|
@ -147,21 +151,39 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
(async () => {
|
(async () => {
|
||||||
await requestInterceptorPromise()
|
await requestInterceptorPromise()
|
||||||
|
|
||||||
if (res.finished) {
|
if (res.writableEnded) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const proxyRes = await proxyRequestPromise()
|
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 responseInterceptorPromise = new Promise((resolve, reject) => {
|
||||||
const next = () => {
|
const next = () => {
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (typeof responseInterceptor === 'function') {
|
if (resIncpts && resIncpts.length > 0) {
|
||||||
responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, context)
|
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 {
|
} else {
|
||||||
resolve()
|
next()
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
reject(e)
|
reject(e)
|
||||||
|
@ -170,10 +192,6 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
|
|
||||||
await responseInterceptorPromise
|
await responseInterceptorPromise
|
||||||
|
|
||||||
if (res.finished) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!res.headersSent) { // prevent duplicate set headers
|
if (!res.headersSent) { // prevent duplicate set headers
|
||||||
Object.keys(proxyRes.headers).forEach(function (key) {
|
Object.keys(proxyRes.headers).forEach(function (key) {
|
||||||
if (proxyRes.headers[key] !== undefined) {
|
if (proxyRes.headers[key] !== undefined) {
|
||||||
|
@ -194,9 +212,10 @@ module.exports = function createRequestHandler (requestInterceptor, responseInte
|
||||||
})().then(
|
})().then(
|
||||||
(flag) => {
|
(flag) => {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
// console.log('res', flag)
|
||||||
},
|
},
|
||||||
(e) => {
|
(e) => {
|
||||||
if (!res.finished) {
|
if (!res.writableEnded) {
|
||||||
const status = e.status || 500
|
const status = e.status || 500
|
||||||
res.writeHead(status)
|
res.writeHead(status)
|
||||||
res.write(`DevSidecar Warning:\n\n ${e.toString()}`)
|
res.write(`DevSidecar Warning:\n\n ${e.toString()}`)
|
||||||
|
|
|
@ -12,8 +12,7 @@ module.exports = {
|
||||||
caCertPath,
|
caCertPath,
|
||||||
caKeyPath,
|
caKeyPath,
|
||||||
sslConnectInterceptor,
|
sslConnectInterceptor,
|
||||||
requestInterceptor,
|
createIntercepts,
|
||||||
responseInterceptor,
|
|
||||||
getCertSocketTimeout = 1 * 1000,
|
getCertSocketTimeout = 1 * 1000,
|
||||||
middlewares = [],
|
middlewares = [],
|
||||||
externalProxy,
|
externalProxy,
|
||||||
|
@ -34,8 +33,7 @@ module.exports = {
|
||||||
|
|
||||||
port = ~~port
|
port = ~~port
|
||||||
const requestHandler = createRequestHandler(
|
const requestHandler = createRequestHandler(
|
||||||
requestInterceptor,
|
createIntercepts,
|
||||||
responseInterceptor,
|
|
||||||
middlewares,
|
middlewares,
|
||||||
externalProxy,
|
externalProxy,
|
||||||
dnsConfig
|
dnsConfig
|
||||||
|
|
|
@ -63,41 +63,41 @@ module.exports = (config) => {
|
||||||
}
|
}
|
||||||
return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理
|
return !!matchHostname(intercepts, hostname) // 配置了拦截的域名,将会被代理
|
||||||
},
|
},
|
||||||
requestInterceptor: (rOptions, req, res, ssl, next, context) => {
|
createIntercepts: (rOptions) => {
|
||||||
const hostname = rOptions.hostname
|
const hostname = rOptions.hostname
|
||||||
const interceptOpts = matchHostname(intercepts, hostname)
|
const interceptOpts = matchHostname(intercepts, hostname)
|
||||||
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
if (!interceptOpts) { // 该域名没有配置拦截器,直接过
|
||||||
next()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const matchIntercepts = []
|
||||||
for (const regexp in interceptOpts) { // 遍历拦截配置
|
for (const regexp in interceptOpts) { // 遍历拦截配置
|
||||||
const interceptOpt = interceptOpts[regexp]
|
const interceptOpt = interceptOpts[regexp]
|
||||||
if (regexp !== true) {
|
if (regexp !== true) {
|
||||||
if (!isMatched(req.url, regexp)) {
|
if (!isMatched(rOptions.path, regexp)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const interceptImpl of interceptors) {
|
for (const impl of interceptors) {
|
||||||
// 根据拦截配置挑选合适的拦截器来处理
|
// 根据拦截配置挑选合适的拦截器来处理
|
||||||
if (!interceptImpl.is(interceptOpt) && interceptImpl.requestInterceptor) {
|
if (impl.is(interceptOpt)) {
|
||||||
continue
|
const interceptor = {}
|
||||||
}
|
if (impl.requestIntercept) {
|
||||||
try {
|
// req拦截器
|
||||||
const result = interceptImpl.requestInterceptor(interceptOpt, rOptions, req, res, ssl, context)
|
interceptor.requestIntercept = (req, res, ssl) => {
|
||||||
if (result) { // 拦截成功,其他拦截器就不处理了
|
impl.requestIntercept(interceptOpt, rOptions, req, res, ssl)
|
||||||
return
|
}
|
||||||
|
} else if (impl.responseIntercept) {
|
||||||
|
// res拦截器
|
||||||
|
interceptor.responseIntercept = (req, res, proxyReq, proxyRes, ssl) => {
|
||||||
|
impl.responseIntercept(interceptOpt, rOptions, req, res, proxyReq, proxyRes, ssl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
matchIntercepts.push(interceptor)
|
||||||
// 拦截失败
|
|
||||||
log.error('拦截器执行错误', err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next()
|
return matchIntercepts
|
||||||
},
|
|
||||||
responseInterceptor: (req, res, proxyReq, proxyRes, ssl, next, context) => {
|
|
||||||
next()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
const monkey = require('../../../src/lib/monkey/index')
|
||||||
|
const scripts = monkey.load()
|
||||||
|
console.log(scripts[0])
|
Loading…
Reference in New Issue