fix: 修复插入脚本时部分字符乱码的问题
parent
7713bffdc0
commit
041a4b16a1
|
@ -29,7 +29,7 @@ module.exports = {
|
||||||
'/.*': {
|
'/.*': {
|
||||||
proxy: 'github.com',
|
proxy: 'github.com',
|
||||||
backup: [
|
backup: [
|
||||||
'github.docmirror.cn/_proxy'
|
'gh.docmirror.top/_proxy'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,7 +28,7 @@ module.exports = {
|
||||||
const scriptTag = getScript(key, script.script)
|
const scriptTag = getScript(key, script.script)
|
||||||
tags += '\r\n' + scriptTag
|
tags += '\r\n' + scriptTag
|
||||||
}
|
}
|
||||||
log.info('responseIntercept: append script', rOptions.hostname, rOptions.path)
|
log.info('responseIntercept: insert script', rOptions.hostname, rOptions.path)
|
||||||
return {
|
return {
|
||||||
head: tags
|
head: tags
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,15 @@ const zlib = require('zlib')
|
||||||
const url = require('url')
|
const url = require('url')
|
||||||
|
|
||||||
var httpUtil = {}
|
var httpUtil = {}
|
||||||
|
httpUtil.getCharset = function (res) {
|
||||||
|
const contentType = res.getHeader('content-type')
|
||||||
|
const reg = /charset=(.*)/
|
||||||
|
const matched = contentType.match(reg)
|
||||||
|
if (matched) {
|
||||||
|
return matched[1]
|
||||||
|
}
|
||||||
|
return 'utf-8'
|
||||||
|
}
|
||||||
httpUtil.isGzip = function (res) {
|
httpUtil.isGzip = function (res) {
|
||||||
var contentEncoding = res.headers['content-encoding']
|
var contentEncoding = res.headers['content-encoding']
|
||||||
return !!(contentEncoding && contentEncoding.toLowerCase() === 'gzip')
|
return !!(contentEncoding && contentEncoding.toLowerCase() === 'gzip')
|
||||||
|
@ -12,34 +21,63 @@ httpUtil.isHtml = function (res) {
|
||||||
var 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)
|
||||||
}
|
}
|
||||||
|
const HEAD = Buffer.from('</head>')
|
||||||
|
const HEAD_UP = Buffer.from('</HEAD>')
|
||||||
|
const BODY = Buffer.from('</body>')
|
||||||
|
const BODY_UP = Buffer.from('</BODY>')
|
||||||
|
|
||||||
function injectScriptIntoHeadHtml (html, script) {
|
function chunkByteReplace (_this, chunk, enc, callback, append) {
|
||||||
html = html.replace(/(<\/head>)/i, function (match) {
|
|
||||||
return script + match
|
|
||||||
})
|
|
||||||
return html
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (append && append.head) {
|
if (append && append.head) {
|
||||||
chunkString = injectScriptIntoHeadHtml(chunkString, append.head)
|
const ret = injectScriptIntoHtml([HEAD, HEAD_UP], chunk, append.head)
|
||||||
|
if (ret != null) {
|
||||||
|
chunk = ret
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (append && append.body) {
|
if (append && append.body) {
|
||||||
chunkString = injectScriptIntoBodyHtml(chunkString, append.body)
|
const ret = injectScriptIntoHtml([BODY, BODY_UP], chunk, append.body)
|
||||||
|
if (ret != null) {
|
||||||
|
chunk = ret
|
||||||
}
|
}
|
||||||
_this.push(Buffer.from(chunkString))
|
}
|
||||||
|
_this.push(chunk)
|
||||||
callback()
|
callback()
|
||||||
}
|
}
|
||||||
|
function injectScriptIntoHtml (tags, chunk, script) {
|
||||||
|
for (const tag of tags) {
|
||||||
|
const index = chunk.indexOf(tag)
|
||||||
|
if (index < 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const scriptBuf = Buffer.from(script)
|
||||||
|
const chunkNew = Buffer.alloc(chunk.length + scriptBuf.length)
|
||||||
|
chunk.copy(chunkNew, 0, 0, index)
|
||||||
|
scriptBuf.copy(chunkNew, index, 0)
|
||||||
|
chunk.copy(chunkNew, index + scriptBuf.length, index)
|
||||||
|
return chunkNew
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const contextPath = '/____ds_script____/'
|
||||||
|
const monkey = require('../../monkey')
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
|
requestIntercept (context, req, res, ssl, next) {
|
||||||
|
const { rOptions, log } = context
|
||||||
|
if (rOptions.path.indexOf(contextPath) !== 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const urlPath = rOptions.path
|
||||||
|
const filename = urlPath.replace(contextPath, '')
|
||||||
|
|
||||||
|
const script = monkey.get()[filename]
|
||||||
|
|
||||||
|
log.info('ds_script', filename, script != null)
|
||||||
|
res.writeHead(200)
|
||||||
|
res.write(script.script)
|
||||||
|
res.end()
|
||||||
|
return true
|
||||||
|
},
|
||||||
responseInterceptor (req, res, proxyReq, proxyRes, ssl, next, append) {
|
responseInterceptor (req, res, proxyReq, proxyRes, ssl, next, append) {
|
||||||
if (!append.head && !append.body) {
|
if (!append.head && !append.body) {
|
||||||
next()
|
next()
|
||||||
|
@ -52,6 +90,7 @@ module.exports = {
|
||||||
})()
|
})()
|
||||||
if (!isHtml || contentLengthIsZero) {
|
if (!isHtml || contentLengthIsZero) {
|
||||||
next()
|
next()
|
||||||
|
return
|
||||||
} 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) {
|
||||||
|
@ -88,11 +127,11 @@ module.exports = {
|
||||||
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, append)
|
chunkByteReplace(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, append)
|
chunkByteReplace(this, chunk, enc, callback, append)
|
||||||
})).pipe(res)
|
})).pipe(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
const contextPath = '/____ds_script____/'
|
|
||||||
const monkey = require('../../monkey')
|
|
||||||
module.exports = {
|
|
||||||
requestIntercept (context, req, res, ssl, next) {
|
|
||||||
const { rOptions, log } = context
|
|
||||||
const urlPath = rOptions.path
|
|
||||||
const filename = urlPath.replace(contextPath, '')
|
|
||||||
|
|
||||||
const script = monkey.get()[filename]
|
|
||||||
|
|
||||||
log.info('ds_script', filename, script != null)
|
|
||||||
res.writeHead(200)
|
|
||||||
res.write(script.script)
|
|
||||||
res.end()
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
is (rOptions) {
|
|
||||||
if (rOptions.path.indexOf(contextPath) !== 0) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,9 +4,10 @@ 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')
|
|
||||||
const RequestCounter = require('../../choice/RequestCounter')
|
const RequestCounter = require('../../choice/RequestCounter')
|
||||||
const ScriptMiddleware = require('../middleware/ScriptMiddleware')
|
const InsertScriptMiddleware = require('../middleware/InsertScriptMiddleware')
|
||||||
|
const defaultDns = require('dns')
|
||||||
|
const MAX_SLOW_TIME = 8000 // 超过此时间 则认为太慢了
|
||||||
// create requestHandler function
|
// create requestHandler function
|
||||||
module.exports = function createRequestHandler (createIntercepts, externalProxy, dnsConfig) {
|
module.exports = function createRequestHandler (createIntercepts, externalProxy, dnsConfig) {
|
||||||
// return
|
// return
|
||||||
|
@ -30,7 +31,7 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
|
||||||
if (interceptors == null) {
|
if (interceptors == null) {
|
||||||
interceptors = []
|
interceptors = []
|
||||||
}
|
}
|
||||||
let reqIncpts = interceptors.filter(item => { return item.requestIntercept != null })
|
const reqIncpts = interceptors.filter(item => { return item.requestIntercept != null })
|
||||||
const resIncpts = interceptors.filter(item => { return item.responseIntercept != null })
|
const resIncpts = interceptors.filter(item => { return item.responseIntercept != null })
|
||||||
|
|
||||||
const requestInterceptorPromise = () => {
|
const requestInterceptorPromise = () => {
|
||||||
|
@ -39,13 +40,7 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (ScriptMiddleware.is(rOptions)) {
|
reqIncpts.unshift(InsertScriptMiddleware)
|
||||||
if (reqIncpts == null) {
|
|
||||||
reqIncpts = []
|
|
||||||
}
|
|
||||||
reqIncpts.unshift(ScriptMiddleware)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reqIncpts && reqIncpts.length > 0) {
|
if (reqIncpts && reqIncpts.length > 0) {
|
||||||
for (const reqIncpt of reqIncpts) {
|
for (const reqIncpt of reqIncpts) {
|
||||||
const goNext = reqIncpt.requestIntercept(context, req, res, ssl, next)
|
const goNext = reqIncpt.requestIntercept(context, req, res, ssl, next)
|
||||||
|
@ -105,19 +100,20 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
|
||||||
if (ip !== hostname) {
|
if (ip !== hostname) {
|
||||||
callback(null, ip, 4)
|
callback(null, ip, 4)
|
||||||
} else {
|
} else {
|
||||||
rOptions.lookup(hostname, options, callback)
|
defaultDns.lookup(hostname, options, callback)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => {
|
proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => {
|
||||||
const end = new Date().getTime()
|
const end = new Date().getTime()
|
||||||
const cost = end - start
|
const cost = end - start
|
||||||
if (rOptions.protocol === 'https:') {
|
if (rOptions.protocol === 'https:') {
|
||||||
log.info('代理请求返回:', url, cost + 'ms')
|
log.info('代理请求返回:', url, cost + 'ms')
|
||||||
}
|
}
|
||||||
if (cost > 8000) {
|
if (cost > MAX_SLOW_TIME) {
|
||||||
countSlow(isDnsIntercept)
|
countSlow(isDnsIntercept)
|
||||||
}
|
}
|
||||||
resolve(proxyRes)
|
resolve(proxyRes)
|
||||||
|
@ -146,7 +142,7 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
|
||||||
const cost = end - start
|
const cost = end - start
|
||||||
log.error('代理请求被取消', rOptions.hostname, rOptions.path, cost + 'ms')
|
log.error('代理请求被取消', rOptions.hostname, rOptions.path, cost + 'ms')
|
||||||
|
|
||||||
if (cost > 8000) {
|
if (cost > MAX_SLOW_TIME) {
|
||||||
countSlow(isDnsIntercept)
|
countSlow(isDnsIntercept)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +208,7 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
|
||||||
body += append.body
|
body += append.body
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
HtmlMiddleware.responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, { head, body })
|
InsertScriptMiddleware.responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, { head, body })
|
||||||
} else {
|
} else {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
const _ = require('lodash')
|
|
||||||
module.exports = (middlewares) => {
|
|
||||||
if (middlewares) {
|
|
||||||
if (Object.prototype.toString.call(middlewares) !== '[object Array]') {
|
|
||||||
throw new TypeError('middlewares must be a array')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// const sslConnectInterceptors = []
|
|
||||||
// const requestInterceptors = []
|
|
||||||
// const responseInterceptors = []
|
|
||||||
|
|
||||||
_.each(middlewares, (m) => {
|
|
||||||
if (m.buildIn === false || m.buildIn === 'false') {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// m.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -5,3 +5,13 @@ console.log(ret)
|
||||||
|
|
||||||
const reg = new RegExp('^/[^/]+/[^/]+$')
|
const reg = new RegExp('^/[^/]+/[^/]+$')
|
||||||
console.log('/greper/d2-crud-plus/blob/master/.eslintignore'.match(reg))
|
console.log('/greper/d2-crud-plus/blob/master/.eslintignore'.match(reg))
|
||||||
|
|
||||||
|
const chunk = Buffer.from('<head></head>')
|
||||||
|
const script = '<script>a</script>'
|
||||||
|
const index = chunk.indexOf('</head>')
|
||||||
|
const scriptBuf = Buffer.from(script)
|
||||||
|
const chunkNew = Buffer.alloc(chunk.length + scriptBuf.length)
|
||||||
|
chunk.copy(chunkNew, 0, 0, index)
|
||||||
|
scriptBuf.copy(chunkNew, index, 0)
|
||||||
|
chunk.copy(chunkNew, index + scriptBuf.length, index)
|
||||||
|
console.log(chunkNew.toString())
|
||||||
|
|
Loading…
Reference in New Issue