fix: 修复插入脚本时部分字符乱码的问题

pull/180/head
xiaojunnuo 4 years ago
parent 7713bffdc0
commit 041a4b16a1

@ -29,7 +29,7 @@ module.exports = {
'/.*': {
proxy: 'github.com',
backup: [
'github.docmirror.cn/_proxy'
'gh.docmirror.top/_proxy'
]
}
},

@ -28,7 +28,7 @@ module.exports = {
const scriptTag = getScript(key, script.script)
tags += '\r\n' + scriptTag
}
log.info('responseIntercept: append script', rOptions.hostname, rOptions.path)
log.info('responseIntercept: insert script', rOptions.hostname, rOptions.path)
return {
head: tags
}

@ -4,6 +4,15 @@ const zlib = require('zlib')
const url = require('url')
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) {
var contentEncoding = res.headers['content-encoding']
return !!(contentEncoding && contentEncoding.toLowerCase() === 'gzip')
@ -12,34 +21,63 @@ httpUtil.isHtml = function (res) {
var contentType = res.headers['content-type']
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) {
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()
function chunkByteReplace (_this, chunk, enc, callback, append) {
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) {
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()
}
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 = {
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) {
if (!append.head && !append.body) {
next()
@ -52,6 +90,7 @@ module.exports = {
})()
if (!isHtml || contentLengthIsZero) {
next()
return
} else {
Object.keys(proxyRes.headers).forEach(function (key) {
if (proxyRes.headers[key] !== undefined) {
@ -88,11 +127,11 @@ module.exports = {
if (isGzip) {
proxyRes.pipe(new zlib.Gunzip())
.pipe(through(function (chunk, enc, callback) {
chunkReplace(this, chunk, enc, callback, append)
chunkByteReplace(this, chunk, enc, callback, append)
})).pipe(new zlib.Gzip()).pipe(res)
} else {
proxyRes.pipe(through(function (chunk, enc, callback) {
chunkReplace(this, chunk, enc, callback, append)
chunkByteReplace(this, chunk, enc, callback, append)
})).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 DnsUtil = require('../../dns/index')
const log = require('../../../utils/util.log')
const HtmlMiddleware = require('../middleware/HtmlMiddleware')
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
module.exports = function createRequestHandler (createIntercepts, externalProxy, dnsConfig) {
// return
@ -30,7 +31,7 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
if (interceptors == null) {
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 requestInterceptorPromise = () => {
@ -39,13 +40,7 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
resolve()
}
try {
if (ScriptMiddleware.is(rOptions)) {
if (reqIncpts == null) {
reqIncpts = []
}
reqIncpts.unshift(ScriptMiddleware)
}
reqIncpts.unshift(InsertScriptMiddleware)
if (reqIncpts && reqIncpts.length > 0) {
for (const reqIncpt of reqIncpts) {
const goNext = reqIncpt.requestIntercept(context, req, res, ssl, next)
@ -105,19 +100,20 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
if (ip !== hostname) {
callback(null, ip, 4)
} else {
rOptions.lookup(hostname, options, callback)
defaultDns.lookup(hostname, options, callback)
}
})
}
}
}
proxyReq = (rOptions.protocol === 'https:' ? https : http).request(rOptions, (proxyRes) => {
const end = new Date().getTime()
const cost = end - start
if (rOptions.protocol === 'https:') {
log.info('代理请求返回:', url, cost + 'ms')
}
if (cost > 8000) {
if (cost > MAX_SLOW_TIME) {
countSlow(isDnsIntercept)
}
resolve(proxyRes)
@ -146,7 +142,7 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
const cost = end - start
log.error('代理请求被取消', rOptions.hostname, rOptions.path, cost + 'ms')
if (cost > 8000) {
if (cost > MAX_SLOW_TIME) {
countSlow(isDnsIntercept)
}
@ -212,7 +208,7 @@ module.exports = function createRequestHandler (createIntercepts, externalProxy,
body += append.body
}
}
HtmlMiddleware.responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, { head, body })
InsertScriptMiddleware.responseInterceptor(req, res, proxyReq, proxyRes, ssl, next, { head, body })
} else {
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('^/[^/]+/[^/]+$')
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…
Cancel
Save