Skip to content

Commit 59f6685

Browse files
authored
SplitHTTP: More range options, change defaults, enforce maxUploadSize, fix querystring behavior (#3603)
* maxUploadSize and maxConcurrentUploads can now be ranges on the client * maxUploadSize is now enforced on the server * the default of maxUploadSize is 2MB on the server, and 1MB on the client * the default of maxConcurrentUploads is 200 on the server, and 100 on the client * ranges on the server are treated as a single number. if server is configured as `"1-2"`, server will enforce `2` * querystrings in `path` are now handled correctly
1 parent 4cb2a12 commit 59f6685

File tree

8 files changed

+223
-82
lines changed

8 files changed

+223
-82
lines changed

infra/conf/transport_internet.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,8 @@ type SplitHTTPConfig struct {
229229
Host string `json:"host"`
230230
Path string `json:"path"`
231231
Headers map[string]string `json:"headers"`
232-
MaxConcurrentUploads int32 `json:"maxConcurrentUploads"`
233-
MaxUploadSize int32 `json:"maxUploadSize"`
232+
MaxConcurrentUploads Int32Range `json:"maxConcurrentUploads"`
233+
MaxUploadSize Int32Range `json:"maxUploadSize"`
234234
MinUploadIntervalMs Int32Range `json:"minUploadIntervalMs"`
235235
}
236236

@@ -245,11 +245,17 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
245245
c.Host = c.Headers["Host"]
246246
}
247247
config := &splithttp.Config{
248-
Path: c.Path,
249-
Host: c.Host,
250-
Header: c.Headers,
251-
MaxConcurrentUploads: c.MaxConcurrentUploads,
252-
MaxUploadSize: c.MaxUploadSize,
248+
Path: c.Path,
249+
Host: c.Host,
250+
Header: c.Headers,
251+
MaxConcurrentUploads: &splithttp.RandRangeConfig{
252+
From: c.MaxConcurrentUploads.From,
253+
To: c.MaxConcurrentUploads.To,
254+
},
255+
MaxUploadSize: &splithttp.RandRangeConfig{
256+
From: c.MaxUploadSize.From,
257+
To: c.MaxUploadSize.To,
258+
},
253259
MinUploadIntervalMs: &splithttp.RandRangeConfig{
254260
From: c.MinUploadIntervalMs.From,
255261
To: c.MinUploadIntervalMs.To,

transport/internet/splithttp/config.go

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,28 @@ import (
44
"crypto/rand"
55
"math/big"
66
"net/http"
7+
"strings"
78

89
"github.com/xtls/xray-core/common"
910
"github.com/xtls/xray-core/transport/internet"
1011
)
1112

12-
func (c *Config) GetNormalizedPath() string {
13-
path := c.Path
14-
if path == "" {
15-
path = "/"
13+
func (c *Config) GetNormalizedPath(addPath string, addQuery bool) string {
14+
pathAndQuery := strings.SplitN(c.Path, "?", 2)
15+
path := pathAndQuery[0]
16+
query := ""
17+
if len(pathAndQuery) > 1 && addQuery {
18+
query = "?" + pathAndQuery[1]
1619
}
17-
if path[0] != '/' {
20+
21+
if path == "" || path[0] != '/' {
1822
path = "/" + path
1923
}
2024
if path[len(path)-1] != '/' {
2125
path = path + "/"
2226
}
23-
return path
27+
28+
return path + addPath + query
2429
}
2530

2631
func (c *Config) GetRequestHeader() http.Header {
@@ -31,33 +36,51 @@ func (c *Config) GetRequestHeader() http.Header {
3136
return header
3237
}
3338

34-
func (c *Config) GetNormalizedMaxConcurrentUploads() int32 {
35-
if c.MaxConcurrentUploads == 0 {
36-
return 10
39+
func (c *Config) GetNormalizedMaxConcurrentUploads(isServer bool) RandRangeConfig {
40+
if c.MaxConcurrentUploads == nil {
41+
if isServer {
42+
return RandRangeConfig{
43+
From: 200,
44+
To: 200,
45+
}
46+
} else {
47+
return RandRangeConfig{
48+
From: 100,
49+
To: 100,
50+
}
51+
}
3752
}
3853

39-
return c.MaxConcurrentUploads
54+
return *c.MaxConcurrentUploads
4055
}
4156

42-
func (c *Config) GetNormalizedMaxUploadSize() int32 {
43-
if c.MaxUploadSize == 0 {
44-
return 1000000
57+
func (c *Config) GetNormalizedMaxUploadSize(isServer bool) RandRangeConfig {
58+
if c.MaxUploadSize == nil {
59+
if isServer {
60+
return RandRangeConfig{
61+
From: 2000000,
62+
To: 2000000,
63+
}
64+
} else {
65+
return RandRangeConfig{
66+
From: 1000000,
67+
To: 1000000,
68+
}
69+
}
4570
}
4671

47-
return c.MaxUploadSize
72+
return *c.MaxUploadSize
4873
}
4974

5075
func (c *Config) GetNormalizedMinUploadInterval() RandRangeConfig {
51-
r := c.MinUploadIntervalMs
52-
53-
if r == nil {
54-
r = &RandRangeConfig{
76+
if c.MinUploadIntervalMs == nil {
77+
return RandRangeConfig{
5578
From: 30,
5679
To: 30,
5780
}
5881
}
5982

60-
return *r
83+
return *c.MinUploadIntervalMs
6184
}
6285

6386
func init() {

transport/internet/splithttp/config.pb.go

Lines changed: 51 additions & 43 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

transport/internet/splithttp/config.proto

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ message Config {
1010
string host = 1;
1111
string path = 2;
1212
map<string, string> header = 3;
13-
int32 maxConcurrentUploads = 4;
14-
int32 maxUploadSize = 5;
13+
RandRangeConfig maxConcurrentUploads = 4;
14+
RandRangeConfig maxUploadSize = 5;
1515
RandRangeConfig minUploadIntervalMs = 6;
1616
}
1717

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package splithttp_test
2+
3+
import (
4+
"testing"
5+
6+
. "github.com/xtls/xray-core/transport/internet/splithttp"
7+
)
8+
9+
func Test_GetNormalizedPath(t *testing.T) {
10+
c := Config{
11+
Path: "/?world",
12+
}
13+
14+
path := c.GetNormalizedPath("hello", true)
15+
if path != "/hello?world" {
16+
t.Error("Unexpected: ", path)
17+
}
18+
}
19+
20+
func Test_GetNormalizedPath2(t *testing.T) {
21+
c := Config{
22+
Path: "?world",
23+
}
24+
25+
path := c.GetNormalizedPath("hello", true)
26+
if path != "/hello?world" {
27+
t.Error("Unexpected: ", path)
28+
}
29+
}
30+
31+
func Test_GetNormalizedPath3(t *testing.T) {
32+
c := Config{
33+
Path: "hello?world",
34+
}
35+
36+
path := c.GetNormalizedPath("", true)
37+
if path != "/hello/?world" {
38+
t.Error("Unexpected: ", path)
39+
}
40+
}
41+
42+
func Test_GetNormalizedPath4(t *testing.T) {
43+
c := Config{
44+
Path: "hello?world",
45+
}
46+
47+
path := c.GetNormalizedPath("", false)
48+
if path != "/hello/" {
49+
t.Error("Unexpected: ", path)
50+
}
51+
}

transport/internet/splithttp/dialer.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,8 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
181181
transportConfiguration := streamSettings.ProtocolSettings.(*Config)
182182
tlsConfig := tls.ConfigFromStreamSettings(streamSettings)
183183

184-
maxConcurrentUploads := transportConfiguration.GetNormalizedMaxConcurrentUploads()
185-
maxUploadSize := transportConfiguration.GetNormalizedMaxUploadSize()
184+
maxConcurrentUploads := transportConfiguration.GetNormalizedMaxConcurrentUploads(false)
185+
maxUploadSize := transportConfiguration.GetNormalizedMaxUploadSize(false)
186186
minUploadInterval := transportConfiguration.GetNormalizedMinUploadInterval()
187187

188188
if tlsConfig != nil {
@@ -194,18 +194,17 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
194194
if requestURL.Host == "" {
195195
requestURL.Host = dest.NetAddr()
196196
}
197-
requestURL.Path = transportConfiguration.GetNormalizedPath()
198-
199-
httpClient := getHTTPClient(ctx, dest, streamSettings)
200197

201198
sessionIdUuid := uuid.New()
202-
sessionId := sessionIdUuid.String()
203-
baseURL := requestURL.String() + sessionId
199+
requestURL.Path = transportConfiguration.GetNormalizedPath(sessionIdUuid.String(), true)
200+
baseURL := requestURL.String()
201+
202+
httpClient := getHTTPClient(ctx, dest, streamSettings)
204203

205-
uploadPipeReader, uploadPipeWriter := pipe.New(pipe.WithSizeLimit(maxUploadSize))
204+
uploadPipeReader, uploadPipeWriter := pipe.New(pipe.WithSizeLimit(maxUploadSize.roll()))
206205

207206
go func() {
208-
requestsLimiter := semaphore.New(int(maxConcurrentUploads))
207+
requestsLimiter := semaphore.New(int(maxConcurrentUploads.roll()))
209208
var requestCounter int64
210209

211210
lastWrite := time.Now()

0 commit comments

Comments
 (0)