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