1- const Version = '2026-08-10 03:09:01 ' ;
1+ const Version = '2026-08-11 14:45:22 ' ;
22let config_JSON , 缓存SOCKS5白名单 = null , 调试日志打印 = false ;
33let SOCKS5白名单 = [ '*tapecontent.net' , '*cloudatacdn.com' , '*loadshare.org' , '*cdn-centaurus.com' , 'scholar.google.com' ] ;
44const Pages静态页面 = 'https://edt-pages.github.io' ;
@@ -68,19 +68,16 @@ export default {
6868 const 反代上下文 = await 反代参数获取 ( url , userID , 默认反代IP , 默认反代兜底 ) ;
6969 log ( `[WebSocket] 命中请求: ${ url . pathname } ${ url . search } ` ) ;
7070 return await 处理WS请求 ( request , userID , url , 反代上下文 ) ;
71- } else if ( 管理员密码 && ! 访问路径 . startsWith ( 'admin/' ) && 访问路径 !== 'login' && request . method === 'POST' ) { // gRPC/XHTTP代理
71+ } else if ( 管理员密码 && ! 访问路径 . startsWith ( 'admin/' ) && 访问路径 !== 'login' && request . method === 'POST' ) { // gRPC/叉HTTP代理
7272 const 反代上下文 = await 反代参数获取 ( url , userID , 默认反代IP , 默认反代兜底 ) ;
73- const referer = request . headers . get ( 'Referer' ) || '' ;
74- const { 头 : 本机Padding头 , 键 : 本机Padding键 } = 获取XHTTPPadding标识 ( userID ) ;
75- const 命中XHTTP特征 = referer . includes ( 'x_padding' , 14 ) || referer . includes ( 'x_padding=' )
76- || ! ! request . headers . get ( 本机Padding头 )
77- || ! ! url . searchParams . get ( 本机Padding键 ) ;
78- if ( ! 命中XHTTP特征 && contentType . startsWith ( 'application/grpc' ) ) {
73+ const { 头 : 本机Padding头 , 键 : 本机Padding键 } = 获取叉HTTPPadding标识 ( userID ) ;
74+ const 命中叉HTTP特征 = ! ! request . headers . get ( 本机Padding头 ) || ! ! url . searchParams . get ( 本机Padding键 ) ;
75+ if ( ! 命中叉HTTP特征 && contentType . startsWith ( 'application/grpc' ) ) {
7976 log ( `[gRPC] 命中请求: ${ url . pathname } ${ url . search } ` ) ;
8077 return await 处理gRPC请求 ( request , userID , 反代上下文 ) ;
8178 }
82- log ( `[XHTTP ] 命中请求: ${ url . pathname } ${ url . search } ` ) ;
83- return await 处理XHTTP请求 ( request , userID , 反代上下文 ) ;
79+ log ( `[叉HTTP ] 命中请求: ${ url . pathname } ${ url . search } ` ) ;
80+ return await 处理叉HTTP请求 ( request , userID , 反代上下文 ) ;
8481 } else {
8582 if ( url . protocol === 'http:' ) return Response . redirect ( url . href . replace ( `http://${ url . hostname } ` , `https://${ url . hostname } ` ) , 301 ) ;
8683 if ( ! 管理员密码 ) return fetch ( Pages静态页面 + '/noADMIN' ) . then ( r => { const headers = new Headers ( r . headers ) ; headers . set ( 'Cache-Control' , 'no-store, no-cache, must-revalidate, proxy-revalidate' ) ; headers . set ( 'Pragma' , 'no-cache' ) ; headers . set ( 'Expires' , '0' ) ; return new Response ( r . body , { status : 404 , statusText : r . statusText , headers } ) } ) ;
@@ -530,14 +527,7 @@ export default {
530527 return new Response ( await nginx ( ) , { status : 200 , headers : { 'Content-Type' : 'text/html; charset=UTF-8' } } ) ;
531528 }
532529} ;
533- ///////////////////////////////////////////////////////////////////////XHTTP传输数据///////////////////////////////////////////////
534- // ========== XHTTP obfs padding 支持 ==========
535- // 链接生成处(获取传输协议配置)为 xhttp 节点注入:
536- // extra={"xPaddingObfsMode":true,"xPaddingMethod":"tokenish","xPaddingPlacement":"queryInHeader",
537- // "xPaddingHeader":"<UUID.slice(1,7)>","xPaddingKey":"_<UUID.slice(1,7)>"}
538- // 客户端据此把 base62 padding 以「URL 形式放进 xPaddingHeader 头」或「放进 URL query」发送;
539- // 服务端需提取并做 HPACK Huffman 字节长度校验(tokenish:100-2 <= len <= 1000+2),校验通过后 padding 直接丢弃。
540- // 以下 HPACK Huffman 码长为 RFC 7541 Appendix B 的完整 257 项(含索引 256 的 EOS 符号),取自 golang.org/x/net/http2/hpack/tables.go,
530+ ///////////////////////////////////////////////////////////////////////叉HTTP传输数据///////////////////////////////////////////////
541531const HPACKHuffman码长 = [
542532 13 , 23 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 24 , 30 , 28 , 28 , 30 , 28 , 28 ,
543533 28 , 28 , 28 , 28 , 28 , 28 , 30 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 ,
@@ -558,12 +548,10 @@ const HPACKHuffman码长 = [
558548 30
559549] ;
560550
561- // 由 UUID 推导本机 XHTTP padding 头名/键名(与链接生成处 extra 的 xPaddingHeader / xPaddingKey 完全一致)
562- function 获取XHTTPPadding标识 ( yourUUID ) {
563- return { 头 : yourUUID . slice ( 1 , 7 ) , 键 : '_' + yourUUID . slice ( 1 , 7 ) } ;
551+ function 获取叉HTTPPadding标识 ( yourUUID ) {
552+ return { 头 : yourUUID . slice ( 1 , 7 ) , 键 : '_' + yourUUID . slice ( 25 , 31 ) } ;
564553}
565554
566- // 计算字符串经 HPACK Huffman 编码后的字节长度(向上取整;与官方 hpack.HuffmanEncodeLength 等价,按 UTF-8 字节遍历)
567555function 计算HPACKHuffman字节长度 ( 字符串 ) {
568556 const 字节 = new TextEncoder ( ) . encode ( 字符串 ) ;
569557 let 总位数 = 0 ;
@@ -573,10 +561,7 @@ function 计算HPACKHuffman字节长度(字符串) {
573561 return Math . ceil ( 总位数 / 8 ) ;
574562}
575563
576- // 提取 XHTTP obfs padding 值(对应官方 ExtractXPaddingFromRequest,obfs 模式;本项目客户端使用 queryInHeader,不启用 cookie)
577- // 优先级:① Header xPaddingHeader(值为 URL 形式时取其中 query 参数 xPaddingKey,取不到则回退用头值本身)② URL query 参数 xPaddingKey
578- // 返回 '' 表示请求未携带 padding
579- function 提取XHTTPPadding值 ( request , 本机Padding头 , 本机Padding键 ) {
564+ function 提取叉HTTPPadding值 ( request , 本机Padding头 , 本机Padding键 ) {
580565 const 头值 = request . headers . get ( 本机Padding头 ) ;
581566 if ( 头值 ) {
582567 try {
@@ -590,35 +575,29 @@ function 提取XHTTPPadding值(request, 本机Padding头, 本机Padding键) {
590575 return 请求URL . searchParams . get ( 本机Padding键 ) || '' ;
591576}
592577
593- // 校验 XHTTP obfs padding(对应官方 IsPaddingValid,tokenish 方法)
594- // @returns {boolean } true=校验通过或请求未携带 padding(放行);false=携带 padding 但校验失败(应返回 400)
595- function 校验XHTTPPadding ( request , 本机Padding头 , 本机Padding键 ) {
596- const padding值 = 提取XHTTPPadding值 ( request , 本机Padding头 , 本机Padding键 ) ;
597- if ( ! padding值 ) return true ; // 无 padding:兼容旧客户端/非 padding 请求,直接放行
578+ function 校验叉HTTPPadding ( request , 本机Padding头 , 本机Padding键 ) {
579+ const padding值 = 提取叉HTTPPadding值 ( request , 本机Padding头 , 本机Padding键 ) ;
580+ if ( ! padding值 ) return true ;
598581 const huffman长度 = 计算HPACKHuffman字节长度 ( padding值 ) ;
599- // tokenish:huffman 编码字节长度须在 [100-2, 1000+2] 容差范围内
600582 return huffman长度 >= 98 && huffman长度 <= 1002 ;
601583}
602584
603- // 生成随机 base62 padding 串(用于响应端 padding,官方 GeneratePadding tokenish 的简化版;客户端不校验响应 padding)
604- const XHTTPBase62字符集 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' ;
605- function 生成XHTTPPadding串 ( 长度 ) {
606- const 字符集长度 = XHTTPBase62字符集 . length ;
585+ const 叉HTTPBase62字符集 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' ;
586+ function 生成叉HTTPPadding串 ( 长度 ) {
587+ const 字符集长度 = 叉HTTPBase62字符集 . length ;
607588 let 结果 = '' ;
608589 for ( let i = 0 ; i < 长度 ; i ++ ) {
609- 结果 += XHTTPBase62字符集 [ Math . floor ( Math . random ( ) * 字符集长度 ) ] ;
590+ 结果 += 叉HTTPBase62字符集 [ Math . floor ( Math . random ( ) * 字符集长度 ) ] ;
610591 }
611592 return 结果 ;
612593}
613594
614- async function 处理XHTTP请求 ( request , yourUUID , 反代上下文 = { } ) {
595+ async function 处理叉HTTP请求 ( request , yourUUID , 反代上下文 = { } ) {
615596 if ( ! request . body ) return new Response ( 'Bad Request' , { status : 400 } ) ;
616- // XHTTP obfs padding 提取与校验(官方 ExtractXPaddingFromRequest + IsPaddingValid)
617- // 校验通过或请求未携带 padding → 放行;携带 padding 但校验失败 → 400(padding 数据不解码、直接丢弃,不影响首包解析)
618- const { 头 : 本机Padding头 , 键 : 本机Padding键 } = 获取XHTTPPadding标识 ( yourUUID ) ;
619- if ( ! 校验XHTTPPadding ( request , 本机Padding头 , 本机Padding键 ) ) return new Response ( 'Bad Request' , { status : 400 } ) ;
597+ const { 头 : 本机Padding头 , 键 : 本机Padding键 } = 获取叉HTTPPadding标识 ( yourUUID ) ;
598+ if ( ! 校验叉HTTPPadding ( request , 本机Padding头 , 本机Padding键 ) ) return new Response ( 'Bad Request' , { status : 400 } ) ;
620599 const reader = request . body . getReader ( ) ;
621- const 首包 = await 读取XHTTP首包 ( reader , yourUUID ) ;
600+ const 首包 = await 读取叉HTTP首包 ( reader , yourUUID ) ;
622601 if ( ! 首包 ) {
623602 try { reader . releaseLock ( ) } catch ( e ) { }
624603 return new Response ( 'Invalid request' , { status : 400 } ) ;
@@ -644,18 +623,15 @@ async function 处理XHTTP请求(request, yourUUID, 反代上下文 = {}) {
644623 'X-Accel-Buffering' : 'no' ,
645624 'Cache-Control' : 'no-store'
646625 } ) ;
647- // 响应端 padding(官方 ApplyXPaddingToResponse 对应,obfs queryInHeader:头名=本机Padding头,值为含 query 的 URL 形式)
648- // 客户端不校验响应 padding,仅作响应特征混淆;随机长度 100~1000
626+
649627 try {
650628 const 响应URL = new URL ( 'https://x.invalid/' ) ;
651- 响应URL . searchParams . set ( 本机Padding键 , 生成XHTTPPadding串 ( 100 + Math . floor ( Math . random ( ) * 901 ) ) ) ;
629+ 响应URL . searchParams . set ( 本机Padding键 , 生成叉HTTPPadding串 ( 100 + Math . floor ( Math . random ( ) * 901 ) ) ) ;
652630 responseHeaders . set ( 本机Padding头 , 响应URL . toString ( ) ) ;
653631 } catch ( e ) { }
654632
655- // UDP 分支:拆到独立函数(保留原逻辑)
656- if ( 首包 . isUDP ) return 处理XHTTPUDP请求 ( 首包 , reader , request , 反代上下文 , responseHeaders ) ;
633+ if ( 首包 . isUDP ) return 处理叉HTTPUDP请求 ( 首包 , reader , request , 反代上下文 , responseHeaders ) ;
657634
658- // ================= TCP 分支:pipe 对接 =================
659635 try { reader . releaseLock ( ) } catch ( e ) { }
660636
661637 const remoteConnWrapper = { socket : null , connectingPromise : null , retryConnect : null , downlinkDrain : Promise . resolve ( ) } ;
@@ -665,18 +641,16 @@ async function 处理XHTTP请求(request, yourUUID, 反代上下文 = {}) {
665641 if ( 已清理 ) return ;
666642 已清理 = true ;
667643 try { abortController . abort ( reason ) } catch ( e ) { }
668- 失效TCP连接世代 ( remoteConnWrapper ) ; // 关闭 socket + 世代 +1
644+ 失效TCP连接世代 ( remoteConnWrapper ) ;
669645 } ;
670646
671- // ⚠️ 关键:ws 参数必须传占位对象(新版 forwardataTCP 2370 行会访问 ws.readyState,传 null 会 TypeError 崩掉)
672- // closeSocketQuietly 对占位对象安全(无 close 方法 → TypeError 被内部 catch 吞掉)
673647 const 占位WS = { readyState : WebSocket . OPEN } ;
674648
675649 let socket ;
676650 try {
677651 socket = await forwardataTCP ( 首包 . hostname , 首包 . port , 首包 . rawData , 占位WS , 首包 . respHeader , remoteConnWrapper , yourUUID , request , 反代上下文 , 首包 . 协议 === 'trojan' , 首包 . 原始数据 , true ) ;
678652 } catch ( err ) {
679- log ( `[XHTTP -Pipe] 连接失败: ${ err ?. message || err } ` ) ;
653+ log ( `[叉HTTP -Pipe] 连接失败: ${ err ?. message || err } ` ) ;
680654 清理 ( err ) ;
681655 return new Response ( 'bad gateway' , { status : 502 } ) ;
682656 }
@@ -685,12 +659,32 @@ async function 处理XHTTP请求(request, yourUUID, 反代上下文 = {}) {
685659 return new Response ( 'bad gateway' , { status : 502 } ) ;
686660 }
687661
688- // 上行:请求体直接 pipe 进 socket(首包残余数据已由 forwardataTCP 写入)
689662 const 上行Promise = ( async ( ) => {
690- await request . body . pipeTo ( socket . writable , { signal : abortController . signal } ) ;
663+ const 上行合包器 = 创建上行Grain合包流 ( ) ;
664+ const 搬运Promise = 上行合包器 . readable . pipeTo ( socket . writable , { signal : abortController . signal } ) ;
665+ void 搬运Promise . catch ( 清理 ) ;
666+ const 上行reader = request . body . getReader ( ) ;
667+ const 取消上行reader = ( ) => {
668+ try { 上行reader . cancel ( abortController . signal . reason ) . catch ( ( ) => { } ) ; } catch ( e ) { }
669+ } ;
670+ abortController . signal . addEventListener ( 'abort' , 取消上行reader , { once : true } ) ;
671+ try {
672+ try {
673+ while ( true ) {
674+ const { done, value } = await 上行reader . read ( ) ;
675+ if ( done ) break ;
676+ if ( value ?. byteLength ) await 上行合包器 . 写入 ( value ) ;
677+ }
678+ } finally {
679+ abortController . signal . removeEventListener ( 'abort' , 取消上行reader ) ;
680+ try { 上行reader . releaseLock ( ) } catch ( e ) { }
681+ }
682+ } finally {
683+ try { await 上行合包器 . 结束 ( ) } catch ( e ) { }
684+ }
685+ await 搬运Promise ;
691686 } ) ( ) ;
692687
693- // 下行:优先使用 IdentityTransformStream(若运行时不支持则回退到 TransformStream)
694688 const 响应流 = typeof IdentityTransformStream !== 'undefined'
695689 ? new IdentityTransformStream ( )
696690 : new TransformStream ( ) ;
@@ -714,13 +708,13 @@ async function 处理XHTTP请求(request, yourUUID, 反代上下文 = {}) {
714708 return new Response ( 响应流 . readable , { status : 200 , headers : responseHeaders } ) ;
715709}
716710
717- function 处理XHTTPUDP请求 ( 首包 , reader , request , 反代上下文 , responseHeaders ) {
711+ function 处理叉HTTPUDP请求 ( 首包 , reader , request , 反代上下文 , responseHeaders ) {
718712 const 木马UDP上下文 = { 缓存 : new Uint8Array ( 0 ) , 反代地址 : 反代上下文 . 木马反代地址 } ;
719713 return new Response ( new ReadableStream ( {
720714 async start ( controller ) {
721715 let 已关闭 = false ;
722716 let udpRespHeader = 首包 . respHeader ;
723- const xhttpBridge = {
717+ const 叉桥 = {
724718 readyState : WebSocket . OPEN ,
725719 send ( data ) {
726720 if ( 已关闭 ) return ;
@@ -750,30 +744,30 @@ function 处理XHTTPUDP请求(首包, reader, request, 反代上下文, response
750744 if ( 首包 . 协议 === 'trojan' ) {
751745 木马UDP上下文 . 目标主机 = 首包 . hostname ;
752746 木马UDP上下文 . 目标端口 = 首包 . port ;
753- if ( 木马UDP上下文 . 反代地址 ) await 转发木马UDP数据 ( 首包 . 原始数据 , xhttpBridge , 木马UDP上下文 , request ) ;
747+ if ( 木马UDP上下文 . 反代地址 ) await 转发木马UDP数据 ( 首包 . 原始数据 , 叉桥 , 木马UDP上下文 , request ) ;
754748 }
755749 if ( ! ( 首包 . 协议 === 'trojan' && 木马UDP上下文 . 反代地址 ) && 首包 . rawData ?. byteLength ) {
756- if ( 首包 . 协议 === 'trojan' ) await 转发木马UDP数据 ( 首包 . rawData , xhttpBridge , 木马UDP上下文 , request ) ;
757- else await forwardataudp ( 首包 . rawData , xhttpBridge , udpRespHeader , request ) ;
750+ if ( 首包 . 协议 === 'trojan' ) await 转发木马UDP数据 ( 首包 . rawData , 叉桥 , 木马UDP上下文 , request ) ;
751+ else await forwardataudp ( 首包 . rawData , 叉桥 , udpRespHeader , request ) ;
758752 udpRespHeader = null ;
759753 }
760754 while ( true ) {
761755 const { done, value } = await reader . read ( ) ;
762756 if ( done ) break ;
763757 if ( ! value || value . byteLength === 0 ) continue ;
764- if ( 首包 . 协议 === 'trojan' ) await 转发木马UDP数据 ( value , xhttpBridge , 木马UDP上下文 , request ) ;
765- else await forwardataudp ( value , xhttpBridge , udpRespHeader , request ) ;
758+ if ( 首包 . 协议 === 'trojan' ) await 转发木马UDP数据 ( value , 叉桥 , 木马UDP上下文 , request ) ;
759+ else await forwardataudp ( value , 叉桥 , udpRespHeader , request ) ;
766760 udpRespHeader = null ;
767761 }
768762 } catch ( err ) {
769763 转发失败 = true ;
770- log ( `[XHTTP转发 ] 处理失败: ${ err ?. message || err } ` ) ;
771- closeSocketQuietly ( xhttpBridge ) ;
764+ log ( `[叉HTTP转发 ] 处理失败: ${ err ?. message || err } ` ) ;
765+ closeSocketQuietly ( 叉桥 ) ;
772766 } finally {
773767 const 保持木马UDP反代下行 = ! 转发失败 && 首包 . 协议 === 'trojan' && 木马UDP上下文 . 反代地址 && 木马UDP上下文 . 反代Socket ;
774768 if ( ! 保持木马UDP反代下行 ) {
775769 try { 木马UDP上下文 . 反代Socket ?. close ( ) } catch ( e ) { }
776- closeSocketQuietly ( xhttpBridge ) ;
770+ closeSocketQuietly ( 叉桥 ) ;
777771 }
778772 try { reader . releaseLock ( ) } catch ( e ) { }
779773 }
@@ -821,7 +815,7 @@ function 开始TCP连接世代(remoteConnWrapper) {
821815 return { generation, downlinkDrain } ;
822816}
823817
824- async function 读取XHTTP首包 ( reader , token ) {
818+ async function 读取叉HTTP首包 ( reader , token ) {
825819 const decoder = VLESS文本解码器 ;
826820
827821 const 尝试解析魏烈思首包 = ( data ) => {
@@ -2604,6 +2598,87 @@ function 创建Grain收纳器(容量, 复制合包结果 = false) {
26042598 } ;
26052599}
26062600
2601+ function 创建上行Grain合包流 ( 目标字节 = 上行合包目标字节 ) {
2602+ const identity = typeof IdentityTransformStream !== 'undefined'
2603+ ? new IdentityTransformStream ( )
2604+ : new TransformStream ( ) ;
2605+ const writer = identity . writable . getWriter ( ) ;
2606+ const 缓冲 = new Uint8Array ( 目标字节 ) ;
2607+ let 缓冲长度 = 0 ;
2608+ let 定时器 = null ;
2609+ let 在途写 = null ;
2610+ let 冲刷链 = Promise . resolve ( ) ;
2611+
2612+ const 清理定时器 = ( ) => {
2613+ if ( 定时器 ) {
2614+ clearTimeout ( 定时器 ) ;
2615+ 定时器 = null ;
2616+ }
2617+ } ;
2618+
2619+ const 串行写 = async ( chunk ) => {
2620+ if ( 在途写 ) await 在途写 ;
2621+ 在途写 = writer . write ( chunk ) ;
2622+ try { await 在途写 } finally { 在途写 = null ; }
2623+ } ;
2624+
2625+ const 冲刷 = async ( ) => {
2626+ if ( 缓冲长度 ) {
2627+ const chunk = 缓冲 . slice ( 0 , 缓冲长度 ) ;
2628+ 缓冲长度 = 0 ;
2629+ await 串行写 ( chunk ) ;
2630+ }
2631+ } ;
2632+
2633+ const 排队冲刷 = ( ) => {
2634+ 冲刷链 = 冲刷链 . then ( ( ) => 冲刷 ( ) ) . catch ( ( ) => { } ) ;
2635+ } ;
2636+
2637+ const 启动定时器 = ( ) => {
2638+ if ( 定时器 ) return ;
2639+ 定时器 = setTimeout ( ( ) => {
2640+ 定时器 = null ;
2641+ 排队冲刷 ( ) ;
2642+ } , 1 ) ;
2643+ } ;
2644+
2645+ return {
2646+ readable : identity . readable ,
2647+ 写入 : async ( chunk ) => {
2648+ const data = 数据转Uint8Array ( chunk ) ;
2649+ if ( ! data . byteLength ) return ;
2650+ if ( data . byteLength >= 目标字节 ) {
2651+ 清理定时器 ( ) ;
2652+ if ( 缓冲长度 ) await 冲刷 ( ) ;
2653+ await 串行写 ( data ) ;
2654+ return ;
2655+ }
2656+ if ( 缓冲长度 + data . byteLength >= 目标字节 ) {
2657+ const output = new Uint8Array ( 缓冲长度 + data . byteLength ) ;
2658+ output . set ( 缓冲 . subarray ( 0 , 缓冲长度 ) , 0 ) ;
2659+ output . set ( data , 缓冲长度 ) ;
2660+ 缓冲长度 = 0 ;
2661+ 清理定时器 ( ) ;
2662+ await 串行写 ( output ) ;
2663+ } else {
2664+ 缓冲 . set ( data , 缓冲长度 ) ;
2665+ 缓冲长度 += data . byteLength ;
2666+ 启动定时器 ( ) ;
2667+ }
2668+ } ,
2669+ 结束 : async ( ) => {
2670+ 清理定时器 ( ) ;
2671+ try {
2672+ await 冲刷链 ;
2673+ await 冲刷 ( ) ;
2674+ await writer . close ( ) ;
2675+ } finally {
2676+ try { writer . releaseLock ( ) } catch ( e ) { }
2677+ }
2678+ }
2679+ } ;
2680+ }
2681+
26072682function 创建上行写入队列 ( { 获取写入器, 获取连接任务 = null , 释放写入器, 重试连接, 关闭连接, 名称 = '上行队列' } ) {
26082683 const grain = 创建Grain收纳器 ( 上行合包目标字节 ) ;
26092684 let draining = false ;
@@ -4707,9 +4782,16 @@ function base64SecretDecode(encoded, secret) {
47074782
47084783function 获取传输协议配置 ( 配置 = { } ) {
47094784 const 是gRPC = 配置 . 传输协议 === 'grpc' ;
4710- const { 头 : 本机Padding头 , 键 : 本机Padding键 } = 获取XHTTPPadding标识 ( 配置 . UUID ) ;
4785+ const { 头 : 本机Padding头 , 键 : 本机Padding键 } = 获取叉HTTPPadding标识 ( 配置 . UUID ) ;
4786+ const 叉混淆JSON = {
4787+ "xPaddingObfsMode" : true ,
4788+ "xPaddingMethod" : "tokenish" ,
4789+ "xPaddingPlacement" : "queryInHeader" ,
4790+ "xPaddingHeader" : 本机Padding头 ,
4791+ "xPaddingKey" : 本机Padding键
4792+ } ;
47114793 return {
4712- type : 是gRPC ? ( 配置 . gRPC模式 === 'multi' ? 'grpc&mode=multi' : 'grpc&mode=gun' ) : ( 配置 . 传输协议 === 'xhttp' ? `xhttp&mode=stream-one&extra=%7B%22xPaddingObfsMode%22%3Atrue%2C%22xPaddingMethod%22%3A%22tokenish%22%2C%22xPaddingPlacement%22%3A%22queryInHeader%22%2C%22xPaddingHeader%22%3A%22 ${ 本机Padding头 } %22%2C%22xPaddingKey%22%3A%22 ${ 本机Padding键 } %22%7D ` : 'ws' ) ,
4794+ type : 是gRPC ? ( 配置 . gRPC模式 === 'multi' ? 'grpc&mode=multi' : 'grpc&mode=gun' ) : ( 配置 . 传输协议 === 'xhttp' ? `xhttp&mode=stream-one&extra=${ encodeURIComponent ( JSON . stringify ( 叉混淆JSON ) ) } ` : 'ws' ) ,
47134795 路径字段名 : 是gRPC ? 'serviceName' : 'path' ,
47144796 域名字段名 : 是gRPC ? 'authority' : 'host'
47154797 } ;
0 commit comments