mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-15 01:09:20 +02:00
SplitHTTP: Replace responseOkPadding with xPaddingBytes (#3643)
This commit is contained in:
parent
f650d87083
commit
a3b306aaa4
|
@ -233,7 +233,7 @@ type SplitHTTPConfig struct {
|
||||||
ScMaxEachPostBytes *Int32Range `json:"scMaxEachPostBytes"`
|
ScMaxEachPostBytes *Int32Range `json:"scMaxEachPostBytes"`
|
||||||
ScMinPostsIntervalMs *Int32Range `json:"scMinPostsIntervalMs"`
|
ScMinPostsIntervalMs *Int32Range `json:"scMinPostsIntervalMs"`
|
||||||
NoSSEHeader bool `json:"noSSEHeader"`
|
NoSSEHeader bool `json:"noSSEHeader"`
|
||||||
ResponseOkPadding *Int32Range `json:"responseOkPadding"`
|
XPaddingBytes *Int32Range `json:"xPaddingBytes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func splithttpNewRandRangeConfig(input *Int32Range) *splithttp.RandRangeConfig {
|
func splithttpNewRandRangeConfig(input *Int32Range) *splithttp.RandRangeConfig {
|
||||||
|
@ -265,7 +265,7 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
|
||||||
ScMaxEachPostBytes: splithttpNewRandRangeConfig(c.ScMaxEachPostBytes),
|
ScMaxEachPostBytes: splithttpNewRandRangeConfig(c.ScMaxEachPostBytes),
|
||||||
ScMinPostsIntervalMs: splithttpNewRandRangeConfig(c.ScMinPostsIntervalMs),
|
ScMinPostsIntervalMs: splithttpNewRandRangeConfig(c.ScMinPostsIntervalMs),
|
||||||
NoSSEHeader: c.NoSSEHeader,
|
NoSSEHeader: c.NoSSEHeader,
|
||||||
ResponseOkPadding: splithttpNewRandRangeConfig(c.ResponseOkPadding),
|
XPaddingBytes: splithttpNewRandRangeConfig(c.XPaddingBytes),
|
||||||
}
|
}
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,22 +10,39 @@ import (
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) GetNormalizedPath(addPath string, addQuery bool) string {
|
func (c *Config) GetNormalizedPath() string {
|
||||||
pathAndQuery := strings.SplitN(c.Path, "?", 2)
|
pathAndQuery := strings.SplitN(c.Path, "?", 2)
|
||||||
path := pathAndQuery[0]
|
path := pathAndQuery[0]
|
||||||
query := ""
|
|
||||||
if len(pathAndQuery) > 1 && addQuery {
|
|
||||||
query = "?" + pathAndQuery[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if path == "" || path[0] != '/' {
|
if path == "" || path[0] != '/' {
|
||||||
path = "/" + path
|
path = "/" + path
|
||||||
}
|
}
|
||||||
|
|
||||||
if path[len(path)-1] != '/' {
|
if path[len(path)-1] != '/' {
|
||||||
path = path + "/"
|
path = path + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
return path + addPath + query
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) GetNormalizedQuery() string {
|
||||||
|
pathAndQuery := strings.SplitN(c.Path, "?", 2)
|
||||||
|
query := ""
|
||||||
|
|
||||||
|
if len(pathAndQuery) > 1 {
|
||||||
|
query = pathAndQuery[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if query != "" {
|
||||||
|
query += "&"
|
||||||
|
}
|
||||||
|
|
||||||
|
paddingLen := c.GetNormalizedXPaddingBytes().roll()
|
||||||
|
if paddingLen > 0 {
|
||||||
|
query += "x_padding=" + strings.Repeat("0", int(paddingLen))
|
||||||
|
}
|
||||||
|
|
||||||
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) GetRequestHeader() http.Header {
|
func (c *Config) GetRequestHeader() http.Header {
|
||||||
|
@ -33,9 +50,17 @@ func (c *Config) GetRequestHeader() http.Header {
|
||||||
for k, v := range c.Header {
|
for k, v := range c.Header {
|
||||||
header.Add(k, v)
|
header.Add(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
return header
|
return header
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) WriteResponseHeader(writer http.ResponseWriter) {
|
||||||
|
paddingLen := c.GetNormalizedXPaddingBytes().roll()
|
||||||
|
if paddingLen > 0 {
|
||||||
|
writer.Header().Set("X-Padding", strings.Repeat("0", int(paddingLen)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) GetNormalizedScMaxConcurrentPosts() RandRangeConfig {
|
func (c *Config) GetNormalizedScMaxConcurrentPosts() RandRangeConfig {
|
||||||
if c.ScMaxConcurrentPosts == nil || c.ScMaxConcurrentPosts.To == 0 {
|
if c.ScMaxConcurrentPosts == nil || c.ScMaxConcurrentPosts.To == 0 {
|
||||||
return RandRangeConfig{
|
return RandRangeConfig{
|
||||||
|
@ -69,15 +94,15 @@ func (c *Config) GetNormalizedScMinPostsIntervalMs() RandRangeConfig {
|
||||||
return *c.ScMinPostsIntervalMs
|
return *c.ScMinPostsIntervalMs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) GetNormalizedResponseOkPadding() RandRangeConfig {
|
func (c *Config) GetNormalizedXPaddingBytes() RandRangeConfig {
|
||||||
if c.ResponseOkPadding == nil || c.ResponseOkPadding.To == 0 {
|
if c.XPaddingBytes == nil || c.XPaddingBytes.To == 0 {
|
||||||
return RandRangeConfig{
|
return RandRangeConfig{
|
||||||
From: 100,
|
From: 100,
|
||||||
To: 1000,
|
To: 1000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *c.ResponseOkPadding
|
return *c.XPaddingBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -32,7 +32,7 @@ type Config struct {
|
||||||
ScMaxEachPostBytes *RandRangeConfig `protobuf:"bytes,5,opt,name=scMaxEachPostBytes,proto3" json:"scMaxEachPostBytes,omitempty"`
|
ScMaxEachPostBytes *RandRangeConfig `protobuf:"bytes,5,opt,name=scMaxEachPostBytes,proto3" json:"scMaxEachPostBytes,omitempty"`
|
||||||
ScMinPostsIntervalMs *RandRangeConfig `protobuf:"bytes,6,opt,name=scMinPostsIntervalMs,proto3" json:"scMinPostsIntervalMs,omitempty"`
|
ScMinPostsIntervalMs *RandRangeConfig `protobuf:"bytes,6,opt,name=scMinPostsIntervalMs,proto3" json:"scMinPostsIntervalMs,omitempty"`
|
||||||
NoSSEHeader bool `protobuf:"varint,7,opt,name=noSSEHeader,proto3" json:"noSSEHeader,omitempty"`
|
NoSSEHeader bool `protobuf:"varint,7,opt,name=noSSEHeader,proto3" json:"noSSEHeader,omitempty"`
|
||||||
ResponseOkPadding *RandRangeConfig `protobuf:"bytes,8,opt,name=responseOkPadding,proto3" json:"responseOkPadding,omitempty"`
|
XPaddingBytes *RandRangeConfig `protobuf:"bytes,8,opt,name=xPaddingBytes,proto3" json:"xPaddingBytes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
|
@ -116,9 +116,9 @@ func (x *Config) GetNoSSEHeader() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) GetResponseOkPadding() *RandRangeConfig {
|
func (x *Config) GetXPaddingBytes() *RandRangeConfig {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ResponseOkPadding
|
return x.XPaddingBytes
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,7 @@ var file_transport_internet_splithttp_config_proto_rawDesc = []byte{
|
||||||
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x63,
|
0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x63,
|
||||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x78, 0x72, 0x61,
|
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x21, 0x78, 0x72, 0x61,
|
||||||
0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
|
0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
|
||||||
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x22, 0xf6,
|
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x22, 0xec,
|
||||||
0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73,
|
0x04, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73,
|
||||||
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a,
|
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a,
|
||||||
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
|
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
|
||||||
|
@ -215,29 +215,29 @@ var file_transport_internet_splithttp_config_proto_rawDesc = []byte{
|
||||||
0x73, 0x63, 0x4d, 0x69, 0x6e, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76,
|
0x73, 0x63, 0x4d, 0x69, 0x6e, 0x50, 0x6f, 0x73, 0x74, 0x73, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76,
|
||||||
0x61, 0x6c, 0x4d, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x6f, 0x53, 0x53, 0x45, 0x48, 0x65, 0x61,
|
0x61, 0x6c, 0x4d, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x6f, 0x53, 0x53, 0x45, 0x48, 0x65, 0x61,
|
||||||
0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x53, 0x53, 0x45,
|
0x64, 0x65, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x53, 0x53, 0x45,
|
||||||
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x64, 0x0a, 0x13, 0x67, 0x65, 0x74, 0x48, 0x61, 0x6e,
|
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x5a, 0x0a, 0x0e, 0x78, 0x50, 0x61, 0x64, 0x64, 0x69,
|
||||||
0x64, 0x73, 0x68, 0x61, 0x6b, 0x65, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20,
|
0x6e, 0x67, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32,
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73,
|
0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e,
|
||||||
0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70,
|
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74,
|
||||||
0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x52, 0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e, 0x67,
|
0x74, 0x70, 0x2e, 0x52, 0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66,
|
||||||
0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x13, 0x67, 0x65, 0x74, 0x48, 0x61, 0x6e, 0x64,
|
0x69, 0x67, 0x52, 0x0e, 0x78, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x61, 0x64,
|
||||||
0x73, 0x68, 0x61, 0x6b, 0x65, 0x50, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x1a, 0x39, 0x0a, 0x0b,
|
0x65, 0x72, 0x1a, 0x39, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72,
|
||||||
0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b,
|
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
||||||
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a,
|
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||||
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61,
|
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x35, 0x0a,
|
||||||
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x35, 0x0a, 0x0f, 0x52, 0x61, 0x6e, 0x64, 0x52,
|
0x0f, 0x52, 0x61, 0x6e, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
0x61, 0x6e, 0x67, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72,
|
0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04,
|
||||||
0x6f, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e,
|
0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
|
||||||
0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x02, 0x74, 0x6f, 0x42, 0x85,
|
0x52, 0x02, 0x74, 0x6f, 0x42, 0x85, 0x01, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61,
|
||||||
0x01, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e,
|
0x79, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65,
|
||||||
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73,
|
0x72, 0x6e, 0x65, 0x74, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01,
|
||||||
0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0x50, 0x01, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68,
|
0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c,
|
||||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79,
|
0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e,
|
||||||
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f,
|
0x73, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73,
|
||||||
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2f, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x68, 0x74,
|
0x70, 0x6c, 0x69, 0x74, 0x68, 0x74, 0x74, 0x70, 0xaa, 0x02, 0x21, 0x58, 0x72, 0x61, 0x79, 0x2e,
|
||||||
0x74, 0x70, 0xaa, 0x02, 0x21, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70,
|
0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
|
||||||
0x6f, 0x72, 0x74, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2e, 0x53, 0x70, 0x6c,
|
0x65, 0x74, 0x2e, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x48, 0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72,
|
||||||
0x69, 0x74, 0x48, 0x74, 0x74, 0x70, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -263,7 +263,7 @@ var file_transport_internet_splithttp_config_proto_depIdxs = []int32{
|
||||||
1, // 1: xray.transport.internet.splithttp.Config.scMaxConcurrentPosts:type_name -> xray.transport.internet.splithttp.RandRangeConfig
|
1, // 1: xray.transport.internet.splithttp.Config.scMaxConcurrentPosts:type_name -> xray.transport.internet.splithttp.RandRangeConfig
|
||||||
1, // 2: xray.transport.internet.splithttp.Config.scMaxEachPostBytes:type_name -> xray.transport.internet.splithttp.RandRangeConfig
|
1, // 2: xray.transport.internet.splithttp.Config.scMaxEachPostBytes:type_name -> xray.transport.internet.splithttp.RandRangeConfig
|
||||||
1, // 3: xray.transport.internet.splithttp.Config.scMinPostsIntervalMs:type_name -> xray.transport.internet.splithttp.RandRangeConfig
|
1, // 3: xray.transport.internet.splithttp.Config.scMinPostsIntervalMs:type_name -> xray.transport.internet.splithttp.RandRangeConfig
|
||||||
1, // 4: xray.transport.internet.splithttp.Config.responseOkPadding:type_name -> xray.transport.internet.splithttp.RandRangeConfig
|
1, // 4: xray.transport.internet.splithttp.Config.xPaddingBytes:type_name -> xray.transport.internet.splithttp.RandRangeConfig
|
||||||
5, // [5:5] is the sub-list for method output_type
|
5, // [5:5] is the sub-list for method output_type
|
||||||
5, // [5:5] is the sub-list for method input_type
|
5, // [5:5] is the sub-list for method input_type
|
||||||
5, // [5:5] is the sub-list for extension type_name
|
5, // [5:5] is the sub-list for extension type_name
|
||||||
|
|
|
@ -14,7 +14,7 @@ message Config {
|
||||||
RandRangeConfig scMaxEachPostBytes = 5;
|
RandRangeConfig scMaxEachPostBytes = 5;
|
||||||
RandRangeConfig scMinPostsIntervalMs = 6;
|
RandRangeConfig scMinPostsIntervalMs = 6;
|
||||||
bool noSSEHeader = 7;
|
bool noSSEHeader = 7;
|
||||||
RandRangeConfig responseOkPadding = 8;
|
RandRangeConfig xPaddingBytes = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RandRangeConfig {
|
message RandRangeConfig {
|
||||||
|
|
|
@ -11,41 +11,8 @@ func Test_GetNormalizedPath(t *testing.T) {
|
||||||
Path: "/?world",
|
Path: "/?world",
|
||||||
}
|
}
|
||||||
|
|
||||||
path := c.GetNormalizedPath("hello", true)
|
path := c.GetNormalizedPath()
|
||||||
if path != "/hello?world" {
|
if path != "/" {
|
||||||
t.Error("Unexpected: ", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_GetNormalizedPath2(t *testing.T) {
|
|
||||||
c := Config{
|
|
||||||
Path: "?world",
|
|
||||||
}
|
|
||||||
|
|
||||||
path := c.GetNormalizedPath("hello", true)
|
|
||||||
if path != "/hello?world" {
|
|
||||||
t.Error("Unexpected: ", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_GetNormalizedPath3(t *testing.T) {
|
|
||||||
c := Config{
|
|
||||||
Path: "hello?world",
|
|
||||||
}
|
|
||||||
|
|
||||||
path := c.GetNormalizedPath("", true)
|
|
||||||
if path != "/hello/?world" {
|
|
||||||
t.Error("Unexpected: ", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_GetNormalizedPath4(t *testing.T) {
|
|
||||||
c := Config{
|
|
||||||
Path: "hello?world",
|
|
||||||
}
|
|
||||||
|
|
||||||
path := c.GetNormalizedPath("", false)
|
|
||||||
if path != "/hello/" {
|
|
||||||
t.Error("Unexpected: ", path)
|
t.Error("Unexpected: ", path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package splithttp
|
package splithttp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
gotls "crypto/tls"
|
gotls "crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
|
@ -217,8 +218,8 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionIdUuid := uuid.New()
|
sessionIdUuid := uuid.New()
|
||||||
requestURL.Path = transportConfiguration.GetNormalizedPath(sessionIdUuid.String(), true)
|
requestURL.Path = transportConfiguration.GetNormalizedPath() + sessionIdUuid.String()
|
||||||
baseURL := requestURL.String()
|
requestURL.RawQuery = transportConfiguration.GetNormalizedQuery()
|
||||||
|
|
||||||
httpClient := getHTTPClient(ctx, dest, streamSettings)
|
httpClient := getHTTPClient(ctx, dest, streamSettings)
|
||||||
|
|
||||||
|
@ -247,9 +248,16 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
||||||
go func() {
|
go func() {
|
||||||
defer requestsLimiter.Signal()
|
defer requestsLimiter.Signal()
|
||||||
|
|
||||||
|
// this intentionally makes a shallow-copy of the struct so we
|
||||||
|
// can reassign Path (potentially concurrently)
|
||||||
|
url := requestURL
|
||||||
|
url.Path += "/" + strconv.FormatInt(seq, 10)
|
||||||
|
// reassign query to get different padding
|
||||||
|
url.RawQuery = transportConfiguration.GetNormalizedQuery()
|
||||||
|
|
||||||
err := httpClient.SendUploadRequest(
|
err := httpClient.SendUploadRequest(
|
||||||
context.WithoutCancel(ctx),
|
context.WithoutCancel(ctx),
|
||||||
baseURL+"/"+strconv.FormatInt(seq, 10),
|
url.String(),
|
||||||
&buf.MultiBufferContainer{MultiBuffer: chunk},
|
&buf.MultiBufferContainer{MultiBuffer: chunk},
|
||||||
int64(chunk.Len()),
|
int64(chunk.Len()),
|
||||||
)
|
)
|
||||||
|
@ -271,26 +279,38 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazyRawDownload, remoteAddr, localAddr, err := httpClient.OpenDownload(context.WithoutCancel(ctx), baseURL)
|
lazyRawDownload, remoteAddr, localAddr, err := httpClient.OpenDownload(context.WithoutCancel(ctx), requestURL.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
lazyDownload := &LazyReader{
|
lazyDownload := &LazyReader{
|
||||||
CreateReader: func() (io.ReadCloser, error) {
|
CreateReader: func() (io.ReadCloser, error) {
|
||||||
// skip "ooooooooook" response
|
// skip "ok" response
|
||||||
trashHeader := []byte{0}
|
trashHeader := []byte{0, 0}
|
||||||
for {
|
_, err := io.ReadFull(lazyRawDownload, trashHeader)
|
||||||
_, err := io.ReadFull(lazyRawDownload, trashHeader)
|
if err != nil {
|
||||||
if err != nil {
|
return nil, errors.New("failed to read initial response").Base(err)
|
||||||
return nil, errors.New("failed to read initial response").Base(err)
|
|
||||||
}
|
|
||||||
if trashHeader[0] == 'k' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return lazyRawDownload, nil
|
if bytes.Equal(trashHeader, []byte("ok")) {
|
||||||
|
return lazyRawDownload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// we read some garbage byte that may not have been "ok" at
|
||||||
|
// all. return a reader that replays what we have read so far
|
||||||
|
reader := io.MultiReader(
|
||||||
|
bytes.NewReader(trashHeader),
|
||||||
|
lazyRawDownload,
|
||||||
|
)
|
||||||
|
readCloser := struct {
|
||||||
|
io.Reader
|
||||||
|
io.Closer
|
||||||
|
}{
|
||||||
|
Reader: reader,
|
||||||
|
Closer: lazyRawDownload,
|
||||||
|
}
|
||||||
|
return readCloser, nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,6 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||||
|
|
||||||
currentSession := h.upsertSession(sessionId)
|
currentSession := h.upsertSession(sessionId)
|
||||||
scMaxEachPostBytes := int(h.ln.config.GetNormalizedScMaxEachPostBytes().To)
|
scMaxEachPostBytes := int(h.ln.config.GetNormalizedScMaxEachPostBytes().To)
|
||||||
responseOkPadding := h.ln.config.GetNormalizedResponseOkPadding()
|
|
||||||
|
|
||||||
if request.Method == "POST" {
|
if request.Method == "POST" {
|
||||||
seq := ""
|
seq := ""
|
||||||
|
@ -170,6 +169,7 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.config.WriteResponseHeader(writer)
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
} else if request.Method == "GET" {
|
} else if request.Method == "GET" {
|
||||||
responseFlusher, ok := writer.(http.Flusher)
|
responseFlusher, ok := writer.(http.Flusher)
|
||||||
|
@ -189,14 +189,14 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
|
||||||
writer.Header().Set("Content-Type", "text/event-stream")
|
writer.Header().Set("Content-Type", "text/event-stream")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.config.WriteResponseHeader(writer)
|
||||||
|
|
||||||
writer.WriteHeader(http.StatusOK)
|
writer.WriteHeader(http.StatusOK)
|
||||||
// send a chunk immediately to enable CDN streaming.
|
// in earlier versions, this initial body data was used to immediately
|
||||||
// many CDN buffer the response headers until the origin starts sending
|
// start a 200 OK on all CDN. but xray client since 1.8.16 does not
|
||||||
// the body, with no way to turn it off.
|
// actually require an immediate 200 OK, but now requires these
|
||||||
padding := int(responseOkPadding.roll())
|
// additional bytes "ok". xray client 1.8.24+ doesn't require "ok"
|
||||||
for i := 0; i < padding; i++ {
|
// anymore, and so this line should be removed in later versions.
|
||||||
writer.Write([]byte("o"))
|
|
||||||
}
|
|
||||||
writer.Write([]byte("ok"))
|
writer.Write([]byte("ok"))
|
||||||
responseFlusher.Flush()
|
responseFlusher.Flush()
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ func ListenSH(ctx context.Context, address net.Address, port net.Port, streamSet
|
||||||
handler := &requestHandler{
|
handler := &requestHandler{
|
||||||
config: shSettings,
|
config: shSettings,
|
||||||
host: shSettings.Host,
|
host: shSettings.Host,
|
||||||
path: shSettings.GetNormalizedPath("", false),
|
path: shSettings.GetNormalizedPath(),
|
||||||
ln: l,
|
ln: l,
|
||||||
sessionMu: &sync.Mutex{},
|
sessionMu: &sync.Mutex{},
|
||||||
sessions: sync.Map{},
|
sessions: sync.Map{},
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
gotls "crypto/tls"
|
gotls "crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
gonet "net"
|
gonet "net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -60,7 +61,7 @@ func Test_listenSHAndDial(t *testing.T) {
|
||||||
|
|
||||||
var b [1024]byte
|
var b [1024]byte
|
||||||
fmt.Println("test2")
|
fmt.Println("test2")
|
||||||
n, _ := conn.Read(b[:])
|
n, _ := io.ReadFull(conn, b[:])
|
||||||
fmt.Println("string is", n)
|
fmt.Println("string is", n)
|
||||||
if string(b[:n]) != "Response" {
|
if string(b[:n]) != "Response" {
|
||||||
t.Error("response: ", string(b[:n]))
|
t.Error("response: ", string(b[:n]))
|
||||||
|
@ -72,7 +73,7 @@ func Test_listenSHAndDial(t *testing.T) {
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
_, err = conn.Write([]byte("Test connection 2"))
|
_, err = conn.Write([]byte("Test connection 2"))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
n, _ = conn.Read(b[:])
|
n, _ = io.ReadFull(conn, b[:])
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if string(b[:n]) != "Response" {
|
if string(b[:n]) != "Response" {
|
||||||
t.Error("response: ", string(b[:n]))
|
t.Error("response: ", string(b[:n]))
|
||||||
|
@ -116,7 +117,7 @@ func TestDialWithRemoteAddr(t *testing.T) {
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
var b [1024]byte
|
var b [1024]byte
|
||||||
n, _ := conn.Read(b[:])
|
n, _ := io.ReadFull(conn, b[:])
|
||||||
if string(b[:n]) != "1.1.1.1:0" {
|
if string(b[:n]) != "1.1.1.1:0" {
|
||||||
t.Error("response: ", string(b[:n]))
|
t.Error("response: ", string(b[:n]))
|
||||||
}
|
}
|
||||||
|
@ -168,7 +169,7 @@ func Test_listenSHAndDial_TLS(t *testing.T) {
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
|
|
||||||
var b [1024]byte
|
var b [1024]byte
|
||||||
n, _ := conn.Read(b[:])
|
n, _ := io.ReadFull(conn, b[:])
|
||||||
if string(b[:n]) != "Response" {
|
if string(b[:n]) != "Response" {
|
||||||
t.Error("response: ", string(b[:n]))
|
t.Error("response: ", string(b[:n]))
|
||||||
}
|
}
|
||||||
|
@ -339,7 +340,7 @@ func Test_listenSHAndDial_Unix(t *testing.T) {
|
||||||
|
|
||||||
var b [1024]byte
|
var b [1024]byte
|
||||||
fmt.Println("test2")
|
fmt.Println("test2")
|
||||||
n, _ := conn.Read(b[:])
|
n, _ := io.ReadFull(conn, b[:])
|
||||||
fmt.Println("string is", n)
|
fmt.Println("string is", n)
|
||||||
if string(b[:n]) != "Response" {
|
if string(b[:n]) != "Response" {
|
||||||
t.Error("response: ", string(b[:n]))
|
t.Error("response: ", string(b[:n]))
|
||||||
|
@ -351,7 +352,7 @@ func Test_listenSHAndDial_Unix(t *testing.T) {
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
_, err = conn.Write([]byte("Test connection 2"))
|
_, err = conn.Write([]byte("Test connection 2"))
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
n, _ = conn.Read(b[:])
|
n, _ = io.ReadFull(conn, b[:])
|
||||||
common.Must(err)
|
common.Must(err)
|
||||||
if string(b[:n]) != "Response" {
|
if string(b[:n]) != "Response" {
|
||||||
t.Error("response: ", string(b[:n]))
|
t.Error("response: ", string(b[:n]))
|
||||||
|
@ -397,7 +398,7 @@ func Test_queryString(t *testing.T) {
|
||||||
|
|
||||||
var b [1024]byte
|
var b [1024]byte
|
||||||
fmt.Println("test2")
|
fmt.Println("test2")
|
||||||
n, _ := conn.Read(b[:])
|
n, _ := io.ReadFull(conn, b[:])
|
||||||
fmt.Println("string is", n)
|
fmt.Println("string is", n)
|
||||||
if string(b[:n]) != "Response" {
|
if string(b[:n]) != "Response" {
|
||||||
t.Error("response: ", string(b[:n]))
|
t.Error("response: ", string(b[:n]))
|
||||||
|
|
Loading…
Reference in New Issue