@@ -228,6 +228,19 @@ type SplitHTTPConfig struct {
228228 Mode string `json:"mode"`
229229 Headers map [string ]string `json:"headers"`
230230 XPaddingBytes Int32Range `json:"xPaddingBytes"`
231+ XPaddingObfsMode bool `json:"xPaddingObfsMode"`
232+ XPaddingKey string `json:"xPaddingKey"`
233+ XPaddingHeader string `json:"xPaddingHeader"`
234+ XPaddingPlacement string `json:"xPaddingPlacement"`
235+ XPaddingMethod string `json:"xPaddingMethod"`
236+ UplinkHTTPMethod string `json:"uplinkHTTPMethod"`
237+ SessionPlacement string `json:"sessionPlacement"`
238+ SessionKey string `json:"sessionKey"`
239+ SeqPlacement string `json:"seqPlacement"`
240+ SeqKey string `json:"seqKey"`
241+ UplinkDataPlacement string `json:"uplinkDataPlacement"`
242+ UplinkDataKey string `json:"uplinkDataKey"`
243+ UplinkChunkSize uint32 `json:"uplinkChunkSize"`
231244 NoGRPCHeader bool `json:"noGRPCHeader"`
232245 NoSSEHeader bool `json:"noSSEHeader"`
233246 ScMaxEachPostBytes Int32Range `json:"scMaxEachPostBytes"`
@@ -287,6 +300,107 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
287300 return nil , errors .New ("xPaddingBytes cannot be disabled" )
288301 }
289302
303+ if c .XPaddingKey == "" {
304+ c .XPaddingKey = "x_padding"
305+ }
306+
307+ if c .XPaddingHeader == "" {
308+ c .XPaddingHeader = "X-Padding"
309+ }
310+
311+ switch c .XPaddingPlacement {
312+ case "" :
313+ c .XPaddingPlacement = "queryInHeader"
314+ case "cookie" , "header" , "query" , "queryInHeader" :
315+ default :
316+ return nil , errors .New ("unsupported padding placement: " + c .XPaddingPlacement )
317+ }
318+
319+ switch c .XPaddingMethod {
320+ case "" :
321+ c .XPaddingMethod = "repeat-x"
322+ case "repeat-x" , "tokenish" :
323+ default :
324+ return nil , errors .New ("unsupported padding method: " + c .XPaddingMethod )
325+ }
326+
327+ switch c .UplinkDataPlacement {
328+ case "" :
329+ c .UplinkDataPlacement = "body"
330+ case "cookie" , "header" :
331+ if c .Mode != "packet-up" {
332+ return nil , errors .New ("UplinkDataPlacement can be " + c .UplinkDataPlacement + " only in packet-up mode" )
333+ }
334+ default :
335+ return nil , errors .New ("unsupported uplink data placement: " + c .UplinkDataPlacement )
336+ }
337+
338+ if c .UplinkHTTPMethod == "" {
339+ c .UplinkHTTPMethod = "POST"
340+ }
341+ c .UplinkHTTPMethod = strings .ToUpper (c .UplinkHTTPMethod )
342+
343+ if c .UplinkHTTPMethod == "GET" && c .Mode != "packet-up" {
344+ return nil , errors .New ("uplinkHTTPMethod can be GET only in packet-up mode" )
345+ }
346+
347+ switch c .SessionPlacement {
348+ case "" :
349+ c .SessionPlacement = "path"
350+ case "cookie" , "header" , "query" :
351+ default :
352+ return nil , errors .New ("unsupported session placement: " + c .SessionPlacement )
353+ }
354+
355+ switch c .SeqPlacement {
356+ case "" :
357+ c .SeqPlacement = "path"
358+ case "cookie" , "header" , "query" :
359+ if c .SessionPlacement == "path" {
360+ return nil , errors .New ("SeqPlacement must be path when SessionPlacement is path" )
361+ }
362+ default :
363+ return nil , errors .New ("unsupported seq placement: " + c .SeqPlacement )
364+ }
365+
366+ if c .SessionPlacement != "path" && c .SessionKey == "" {
367+ switch c .SessionPlacement {
368+ case "cookie" , "query" :
369+ c .SessionKey = "x_session"
370+ case "header" :
371+ c .SessionKey = "X-Session"
372+ }
373+ }
374+
375+ if c .SeqPlacement != "path" && c .SeqKey == "" {
376+ switch c .SeqPlacement {
377+ case "cookie" , "query" :
378+ c .SeqKey = "x_seq"
379+ case "header" :
380+ c .SeqKey = "X-Seq"
381+ }
382+ }
383+
384+ if c .UplinkDataPlacement != "body" && c .UplinkDataKey == "" {
385+ switch c .UplinkDataPlacement {
386+ case "cookie" :
387+ c .UplinkDataKey = "x_data"
388+ case "header" :
389+ c .UplinkDataKey = "X-Data"
390+ }
391+ }
392+
393+ if c .UplinkChunkSize == 0 {
394+ switch c .UplinkDataPlacement {
395+ case "cookie" :
396+ c .UplinkChunkSize = 3 * 1024 // 3KB
397+ case "header" :
398+ c .UplinkChunkSize = 4 * 1024 // 4KB
399+ }
400+ } else if c .UplinkChunkSize < 64 {
401+ c .UplinkChunkSize = 64
402+ }
403+
290404 if c .Xmux .MaxConnections .To > 0 && c .Xmux .MaxConcurrency .To > 0 {
291405 return nil , errors .New ("maxConnections cannot be specified together with maxConcurrency" )
292406 }
@@ -305,6 +419,19 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
305419 Mode : c .Mode ,
306420 Headers : c .Headers ,
307421 XPaddingBytes : newRangeConfig (c .XPaddingBytes ),
422+ XPaddingObfsMode : c .XPaddingObfsMode ,
423+ XPaddingKey : c .XPaddingKey ,
424+ XPaddingHeader : c .XPaddingHeader ,
425+ XPaddingPlacement : c .XPaddingPlacement ,
426+ XPaddingMethod : c .XPaddingMethod ,
427+ UplinkHTTPMethod : c .UplinkHTTPMethod ,
428+ SessionPlacement : c .SessionPlacement ,
429+ SeqPlacement : c .SeqPlacement ,
430+ SessionKey : c .SessionKey ,
431+ SeqKey : c .SeqKey ,
432+ UplinkDataPlacement : c .UplinkDataPlacement ,
433+ UplinkDataKey : c .UplinkDataKey ,
434+ UplinkChunkSize : c .UplinkChunkSize ,
308435 NoGRPCHeader : c .NoGRPCHeader ,
309436 NoSSEHeader : c .NoSSEHeader ,
310437 ScMaxEachPostBytes : newRangeConfig (c .ScMaxEachPostBytes ),
0 commit comments