Skip to content

Commit 67b817b

Browse files
committed
feat: Beta 版实验性支持 Loon 一个 Request Header 类型的 Rewrite 设置修改多个值; 修复 Surge 的 Header Rewrite; 支持 Loon 的 Response Header 类型复写
1 parent 31ead7e commit 67b817b

File tree

1 file changed

+185
-47
lines changed

1 file changed

+185
-47
lines changed

Rewrite-Parser.beta.js

Lines changed: 185 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ const urlArg = url.split(/\/_end_\//)[1]
3737
const queryObject = parseQueryString(urlArg)
3838
//$.log("参数:" + $.toStr(queryObject));
3939

40+
// 来源
41+
const fromType = queryObject.type
4042
//目标app
4143
const targetApp = queryObject.target
4244
const app = targetApp.split('-')[0]
@@ -270,7 +272,7 @@ const panelRegex = /\s*[=,]\s*(?:title|content|style|script-name|update-interval
270272

271273
const policyRegex = /^(direct|reject-?(img|video|dict|array|drop|200|tinygif)?(-no-drop)?|\{\{\{[^,]+\}\}\})$/i
272274

273-
const mockRegex = /\s+(?:data-type|status-code|header|data)\s*=/
275+
const mockRegex = /\s+(?:data-type|status-code|header|data|data-path|mock-data-is-base64)\s*=/
274276

275277
//查询js binarymode相关
276278
let binaryInfo = $.getval('Parser_binary_info')
@@ -445,11 +447,55 @@ if (binaryInfo != null && binaryInfo.length > 0) {
445447
}
446448

447449
//header rewrite 解析
448-
if (/\sheader-(?:del|add|replace|replace-regex)\s/.test(x)) {
450+
if (/\s(response-)?header-(?:del|add|replace|replace-regex)\s/.test(x)) {
449451
mark = getMark(y, body)
450452
noteK = isNoteK(x)
451453
x = x.replace(/^#/, '')
452-
rwhdBox.push({ mark, noteK, x })
454+
if (fromType === 'loon-plugin') {
455+
let [_, __, prefix, isResponseHeaderRewrite, action, suffix] = x.match(
456+
/^((.*?\s)(response-)?(header-(?:del|add|replace|replace-regex)\s))\s*(.*?)\s*$/
457+
)
458+
prefix = `${isResponseHeaderRewrite ? 'http-response' : 'http-request'} ${prefix}${action}`
459+
const suffixArray = suffix.split(/\s+/)
460+
const newSuffixArray = []
461+
if (/\s(response-)?header-del\s/.test(prefix)) {
462+
for (let index = 0; index < suffixArray.length; index++) {
463+
const key = suffixArray[index]
464+
newSuffixArray.push(`${/\\x20/.test(key) ? `"${key.replace(/\\x20/g, ' ')}"` : key}`)
465+
}
466+
} else if (/\s(response-)?header-replace-regex\s/.test(prefix)) {
467+
for (let index = 0; index < suffixArray.length; index += 3) {
468+
const key = suffixArray[index]
469+
const value = `${
470+
/\\x20/.test(suffixArray[index + 1])
471+
? `"${suffixArray[index + 1].replace(/\\x20/g, ' ')}"`
472+
: suffixArray[index + 1]
473+
} ${
474+
/\\x20/.test(suffixArray[index + 2])
475+
? `"${suffixArray[index + 2].replace(/\\x20/g, ' ')}"`
476+
: suffixArray[index + 2]
477+
}`
478+
if (value != null) {
479+
newSuffixArray.push(`${key} ${value}`)
480+
}
481+
}
482+
} else {
483+
for (let index = 0; index < suffixArray.length; index += 2) {
484+
const key = suffixArray[index]
485+
const value = suffixArray[index + 1]
486+
if (value != null) {
487+
newSuffixArray.push(`${key} ${/\\x20/.test(value) ? `"${value.replace(/\\x20/g, ' ')}"` : value}`)
488+
}
489+
}
490+
}
491+
// console.log({ mark, noteK, x })
492+
for (let index = 0; index < newSuffixArray.length; index++) {
493+
let i = newSuffixArray[index]
494+
rwhdBox.push({ mark, noteK, x: `${prefix}${i}` })
495+
}
496+
} else {
497+
rwhdBox.push({ mark, noteK, x })
498+
}
453499
}
454500

455501
//(request|response)-(header|body) 解析
@@ -976,13 +1022,17 @@ if (binaryInfo != null && binaryInfo.length > 0) {
9761022
noteK = rwhdBox[i].noteK ? '#' : ''
9771023
mark = rwhdBox[i].mark ? rwhdBox[i].mark : ''
9781024
x = rwhdBox[i].x
1025+
const isResponseHeaderRewrite = /^http-response\s/.test(x)
9791026
switch (targetApp) {
9801027
case 'surge-module':
9811028
HeaderRewrite.push(mark + noteK + x)
9821029
break
9831030

9841031
case 'loon-plugin':
9851032
x = x.replace(/^http-(request|response)\s+/, '')
1033+
if (isResponseHeaderRewrite) {
1034+
x = x.replace(/\sheader-/, ' response-header-')
1035+
}
9861036
URLRewrite.push(mark + noteK + x)
9871037
break
9881038

@@ -1000,7 +1050,7 @@ if (binaryInfo != null && binaryInfo.length > 0) {
10001050
noteK4 = '# '
10011051
noteK2 = '# '
10021052
}
1003-
let hdtype = /^http-response\s/.test(x) ? ' response-' : ' request-'
1053+
let hdtype = isResponseHeaderRewrite ? ' response-' : ' request-'
10041054
x = x.replace(/^http-(?:request|response)\s+/, '').replace(/\s+header-/, hdtype)
10051055
HeaderRewrite.push(mark + `${noteK4}- >-${noteKn6}` + x)
10061056
break
@@ -1043,11 +1093,23 @@ if (binaryInfo != null && binaryInfo.length > 0) {
10431093
switch (targetApp) {
10441094
case 'surge-module':
10451095
mockheader =
1046-
keepHeader == true && mockBox[i].mockheader && !/&contentType=/.test(mockBox[i].mockheader)
1096+
mockBox[i].mockheader && !/&contentType=/.test(mockBox[i].mockheader)
10471097
? ' header="' + mockBox[i].mockheader + '"'
10481098
: ''
10491099
MapLocal.push(mark + noteK + mockptn + mocktype + mockurl + mockstatus + mockheader)
10501100
break
1101+
case 'loon-plugin':
1102+
MapLocal.push(
1103+
mark +
1104+
noteK +
1105+
mockptn +
1106+
' mock-response-body' +
1107+
mocktype +
1108+
(mockBox[i].datapath ? ` data-path=${mockBox[i].datapath}` : ` data="${mockBox[i].data}"`) +
1109+
mockstatus +
1110+
(mockBox[i].mockbase64 ? ' mock-data-is-base64=true' : '')
1111+
)
1112+
break
10511113
} //switch
10521114
} //Mock输出for
10531115

@@ -1623,7 +1685,7 @@ function getJsInfo(x, regex, parserRegex) {
16231685
? panelRegex
16241686
: /script-path\s*=/.test(x)
16251687
? jsRegex
1626-
: /\s(data-type|data)\s*=/.test(x)
1688+
: /\s(data-type|data|data-path)\s*=/.test(x)
16271689
? mockRegex
16281690
: ''
16291691
if (regex.test(x)) {
@@ -1720,7 +1782,7 @@ async function isBinaryMode(url, name) {
17201782
//获取mock参数
17211783
function getMockInfo(x, mark, y) {
17221784
let noteK = isNoteK(x)
1723-
let mockptn, mockurl, mockheader, mocktype, mockstatus
1785+
let mockptn, mockurl, mockheader, mocktype, mockstatus, oritype, datapath, data, mockbase64
17241786
if (/url\s+echo-response\s/.test(x)) {
17251787
mockptn = x.split(/\s+url\s+/)[0]
17261788
mockurl = x.split(/\s+echo-response\s+/)[2]
@@ -1733,17 +1795,78 @@ function getMockInfo(x, mark, y) {
17331795
.split(/\s+/)[0]
17341796
.replace(/^#/g, '')
17351797
.replace(/^"(.+)"$/, '$1')
1736-
mockurl = getJsInfo(x, /\s+data\s*=\s*/).replace(/^"(.*)"$/, '$1')
1798+
datapath = getJsInfo(x, /\s+data-path\s*=\s*/).replace(/^"(.*)"$/, '$1')
1799+
data = getJsInfo(x, /\s+data\s*=\s*/).replace(/^"(.*)"$/, '$1')
1800+
mockurl = data || datapath
1801+
mockbase64 = getJsInfo(x, /\s+mock-data-is-base64\s*=\s*/)
17371802
mocktype = getJsInfo(x, /\s+data-type\s*=\s*/) || 'file'
1803+
oritype = mocktype
17381804
mockstatus = getJsInfo(x, /\s+status-code\s*=\s*/)
17391805
mockheader = getJsInfo(x, /\s+header\s*=\s*/).replace(/^"(.+)"$/, '$1')
1806+
if (/\smock-response-body\s/.test(x)) {
1807+
// Loon data-type: body的类型,json,text,css,html,javascript,plain,png,gif,jpeg,tiff,svg,mp4,form-data 应该设置对应的 Content-Type
1808+
switch (mocktype) {
1809+
case 'css':
1810+
mocktype = 'file'
1811+
mockheader = 'Content-Type:text/css'
1812+
break
1813+
case 'html':
1814+
mocktype = 'file'
1815+
mockheader = 'Content-Type:text/html'
1816+
break
1817+
case 'javascript':
1818+
mocktype = 'file'
1819+
mockheader = 'Content-Type:text/javascript'
1820+
break
1821+
case 'plain':
1822+
mocktype = 'file'
1823+
mockheader = 'Content-Type:text/plain'
1824+
break
1825+
case 'png':
1826+
mocktype = 'file'
1827+
mockheader = 'Content-Type:image/png'
1828+
break
1829+
case 'gif':
1830+
mocktype = 'file'
1831+
mockheader = 'Content-Type:image/gif'
1832+
break
1833+
case 'jpeg':
1834+
mocktype = 'file'
1835+
mockheader = 'Content-Type:image/jpeg'
1836+
break
1837+
case 'tiff':
1838+
mocktype = 'file'
1839+
mockheader = 'Content-Type:image/tiff'
1840+
break
1841+
case 'svg':
1842+
mocktype = 'file'
1843+
mockheader = 'Content-Type:image/svg+xml'
1844+
break
1845+
case 'mp4':
1846+
mocktype = 'file'
1847+
mockheader = 'Content-Type:video/mp4'
1848+
break
1849+
case 'form-data':
1850+
mocktype = 'file'
1851+
mockheader = 'Content-Type:application/x-www-form-urlencoded'
1852+
break
1853+
default:
1854+
mocktype = 'file'
1855+
break
1856+
}
1857+
if (mockbase64) {
1858+
mocktype = 'base64'
1859+
}
1860+
}
1861+
if (oritype === 'base64') {
1862+
mockbase64 = true
1863+
}
1864+
console.log({ mockbase64 })
17401865
}
1741-
17421866
switch (targetApp) {
17431867
case 'surge-module':
17441868
mockBox.push({ mark, noteK, mockptn, mockurl, mockheader, mockstatus, mocktype, ori: x, mocknum: y })
17451869
break
1746-
17471870
case 'shadowrocket-module':
17481871
case 'loon-plugin':
17491872
case 'stash-stoverride':
@@ -1754,50 +1877,65 @@ function getMockInfo(x, mark, y) {
17541877
else if (/200|blank|^[\s\S]?$/i.test(mfile)) m2rType = 'reject-200'
17551878
else if (/img|tinygif/i.test(mfile) || mocktype == 'tiny-gif') m2rType = 'reject-img'
17561879
else m2rType = null
1757-
17581880
let jsname =
17591881
mocktype == 'file' ? mockurl.substring(mockurl.lastIndexOf('/') + 1, mockurl.lastIndexOf('.')) : 'echoResponse'
17601882
m2rType != null && rwBox.push({ mark, noteK, rwptn: mockptn, rwvalue: '-', rwtype: m2rType })
1761-
let proto
1762-
if (m2rType == null && mocktype == 'file') {
1763-
proto = isStashiOS ? 'true' : ''
1764-
mockheader =
1765-
mockheader != '' && !/&contentType=/.test(mockheader)
1766-
? '&header=' + encodeURIComponent(mockheader)
1767-
: mockheader != '' && /&contentType=/.test(mockheader)
1768-
? mockheader
1769-
: ''
1770-
if (keepHeader == false) mockheader = ''
1771-
1772-
mockurl = `http://script.hub/convert/_start_/${mockurl}/_end_/${mfile}?type=mock&target-app=${targetApp}${mockheader}${sufkeepHeader}${sufjsDelivr}`
1773-
jsBox.push({
1774-
mark,
1775-
noteK,
1776-
jsname,
1777-
jstype: 'http-request',
1778-
jsptn: mockptn,
1779-
jsurl: mockurl,
1780-
proto,
1781-
timeout: '60',
1782-
ori: x,
1783-
num: y,
1784-
})
1785-
} else if (m2rType == null && mocktype != 'file') {
1786-
jsurl = 'https://raw.githubusercontent.com/Script-Hub-Org/Script-Hub/main/scripts/echo-response.js'
1787-
mockstatus = mockstatus ? '&status-code=' + mockstatus : ''
1788-
jsarg = `${mocktype}=` + encodeURIComponent(mockurl) + mockstatus
1789-
jsBox.push({
1883+
if (targetApp === 'loon-plugin') {
1884+
mockBox.push({
17901885
mark,
17911886
noteK,
1792-
jsname,
1793-
jstype: 'http-request',
1794-
jsptn: mockptn,
1795-
jsurl,
1796-
jsarg,
1797-
timeout: '60',
1887+
mockptn,
1888+
data,
1889+
datapath,
1890+
mockurl,
1891+
mockstatus,
1892+
mocktype: oritype,
1893+
mockbase64,
17981894
ori: x,
1799-
num: y,
1895+
mocknum: y,
18001896
})
1897+
} else {
1898+
let proto
1899+
if (m2rType == null && mocktype == 'file') {
1900+
proto = isStashiOS ? 'true' : ''
1901+
mockheader =
1902+
mockheader != '' && !/&contentType=/.test(mockheader)
1903+
? '&header=' + encodeURIComponent(mockheader)
1904+
: mockheader != '' && /&contentType=/.test(mockheader)
1905+
? mockheader
1906+
: ''
1907+
if (keepHeader == false) mockheader = ''
1908+
1909+
mockurl = `http://script.hub/convert/_start_/${mockurl}/_end_/${mfile}?type=mock&target-app=${targetApp}${mockheader}${sufkeepHeader}${sufjsDelivr}`
1910+
jsBox.push({
1911+
mark,
1912+
noteK,
1913+
jsname,
1914+
jstype: 'http-request',
1915+
jsptn: mockptn,
1916+
jsurl: mockurl,
1917+
proto,
1918+
timeout: '60',
1919+
ori: x,
1920+
num: y,
1921+
})
1922+
} else if (m2rType == null && mocktype != 'file') {
1923+
jsurl = 'https://raw.githubusercontent.com/Script-Hub-Org/Script-Hub/main/scripts/echo-response.js'
1924+
mockstatus = mockstatus ? '&status-code=' + mockstatus : ''
1925+
jsarg = `${mocktype}=` + encodeURIComponent(mockurl) + mockstatus
1926+
jsBox.push({
1927+
mark,
1928+
noteK,
1929+
jsname,
1930+
jstype: 'http-request',
1931+
jsptn: mockptn,
1932+
jsurl,
1933+
jsarg,
1934+
timeout: '60',
1935+
ori: x,
1936+
num: y,
1937+
})
1938+
}
18011939
}
18021940
break
18031941
} //switch

0 commit comments

Comments
 (0)