From e5eb237114772880f37c2f4a952d19c1608d0f02 Mon Sep 17 00:00:00 2001 From: mhsanaei Date: Tue, 18 Jun 2024 13:38:26 +0200 Subject: [PATCH 1/4] new - splithttp inbound outbound --- sub/subJsonService.go | 3 +- sub/subService.go | 66 ++++++++++-- web/assets/js/model/outbound.js | 34 +++++- web/assets/js/model/xray.js | 100 +++++++++++++++--- web/html/xui/form/outbound.html | 33 +++--- web/html/xui/form/stream/stream_settings.html | 6 ++ .../xui/form/stream/stream_splithttp.html | 29 +++++ web/html/xui/inbound_info_modal.html | 2 +- 8 files changed, 231 insertions(+), 42 deletions(-) create mode 100644 web/html/xui/form/stream/stream_splithttp.html diff --git a/sub/subJsonService.go b/sub/subJsonService.go index 057c1e81..c4fe2202 100644 --- a/sub/subJsonService.go +++ b/sub/subJsonService.go @@ -223,8 +223,9 @@ func (s *SubJsonService) streamData(stream string) map[string]interface{} { streamSettings["wsSettings"] = s.removeAcceptProxy(streamSettings["wsSettings"]) case "httpupgrade": streamSettings["httpupgradeSettings"] = s.removeAcceptProxy(streamSettings["httpupgradeSettings"]) + case "splithttp": + streamSettings["splithttpSettings"] = s.removeAcceptProxy(streamSettings["splithttpSettings"]) } - return streamSettings } diff --git a/sub/subService.go b/sub/subService.go index 72728f8d..b73980dd 100644 --- a/sub/subService.go +++ b/sub/subService.go @@ -221,7 +221,21 @@ func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string { case "httpupgrade": httpupgrade, _ := stream["httpupgradeSettings"].(map[string]interface{}) obj["path"] = httpupgrade["path"].(string) - obj["host"] = httpupgrade["host"].(string) + if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 { + obj["host"] = host + } else { + headers, _ := httpupgrade["headers"].(map[string]interface{}) + obj["host"] = searchHost(headers) + } + case "splithttp": + splithttp, _ := stream["splithttpSettings"].(map[string]interface{}) + obj["path"] = splithttp["path"].(string) + if host, ok := splithttp["host"].(string); ok && len(host) > 0 { + obj["host"] = host + } else { + headers, _ := splithttp["headers"].(map[string]interface{}) + obj["host"] = searchHost(headers) + } } security, _ := stream["security"].(string) @@ -364,9 +378,22 @@ func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string { case "httpupgrade": httpupgrade, _ := stream["httpupgradeSettings"].(map[string]interface{}) params["path"] = httpupgrade["path"].(string) - params["host"] = httpupgrade["host"].(string) + if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 { + params["host"] = host + } else { + headers, _ := httpupgrade["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + } + case "splithttp": + splithttp, _ := stream["splithttpSettings"].(map[string]interface{}) + params["path"] = splithttp["path"].(string) + if host, ok := splithttp["host"].(string); ok && len(host) > 0 { + params["host"] = host + } else { + headers, _ := splithttp["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + } } - security, _ := stream["security"].(string) if security == "tls" { params["security"] = "tls" @@ -554,9 +581,22 @@ func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string case "httpupgrade": httpupgrade, _ := stream["httpupgradeSettings"].(map[string]interface{}) params["path"] = httpupgrade["path"].(string) - params["host"] = httpupgrade["host"].(string) + if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 { + params["host"] = host + } else { + headers, _ := httpupgrade["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + } + case "splithttp": + splithttp, _ := stream["splithttpSettings"].(map[string]interface{}) + params["path"] = splithttp["path"].(string) + if host, ok := splithttp["host"].(string); ok && len(host) > 0 { + params["host"] = host + } else { + headers, _ := splithttp["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + } } - security, _ := stream["security"].(string) if security == "tls" { params["security"] = "tls" @@ -740,7 +780,21 @@ func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) st case "httpupgrade": httpupgrade, _ := stream["httpupgradeSettings"].(map[string]interface{}) params["path"] = httpupgrade["path"].(string) - params["host"] = httpupgrade["host"].(string) + if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 { + params["host"] = host + } else { + headers, _ := httpupgrade["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + } + case "splithttp": + splithttp, _ := stream["splithttpSettings"].(map[string]interface{}) + params["path"] = splithttp["path"].(string) + if host, ok := splithttp["host"].(string); ok && len(host) > 0 { + params["host"] = host + } else { + headers, _ := splithttp["headers"].(map[string]interface{}) + params["host"] = searchHost(headers) + } } security, _ := stream["security"].(string) diff --git a/web/assets/js/model/outbound.js b/web/assets/js/model/outbound.js index 79a5dd92..c37d2130 100644 --- a/web/assets/js/model/outbound.js +++ b/web/assets/js/model/outbound.js @@ -299,6 +299,28 @@ class HttpUpgradeStreamSettings extends CommonClass { } } +class SplitHTTPStreamSettings extends CommonClass { + constructor(path='/', host='') { + super(); + this.path = path; + this.host = host; + } + + static fromJson(json={}) { + return new SplitHTTPStreamSettings( + json.path, + json.host, + ); + } + + toJson() { + return { + path: this.path, + host: this.host, + }; + } +} + class TlsStreamSettings extends CommonClass { constructor(serverName='', alpn=[], @@ -357,7 +379,7 @@ class RealityStreamSettings extends CommonClass { spiderX: this.spiderX, }; } -} +}; class SockoptStreamSettings extends CommonClass { constructor(dialerProxy = "", tcpFastOpen = false, tcpKeepAliveInterval = 0, tcpNoDelay = false) { @@ -400,6 +422,7 @@ class StreamSettings extends CommonClass { quicSettings=new QuicStreamSettings(), grpcSettings=new GrpcStreamSettings(), httpupgradeSettings=new HttpUpgradeStreamSettings(), + splithttpSettings=new SplitHTTPStreamSettings(), sockopt = undefined, ) { super(); @@ -414,6 +437,7 @@ class StreamSettings extends CommonClass { this.quic = quicSettings; this.grpc = grpcSettings; this.httpupgrade = httpupgradeSettings; + this.splithttp = splithttpSettings; this.sockopt = sockopt; } @@ -446,6 +470,7 @@ class StreamSettings extends CommonClass { QuicStreamSettings.fromJson(json.quicSettings), GrpcStreamSettings.fromJson(json.grpcSettings), HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings), + SplitHTTPStreamSettings.fromJson(json.splithttpSettings), SockoptStreamSettings.fromJson(json.sockopt), ); } @@ -464,6 +489,7 @@ class StreamSettings extends CommonClass { quicSettings: network === 'quic' ? this.quic.toJson() : undefined, grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined, httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined, + splithttpSettings: network === 'splithttp' ? this.splithttp.toJson() : undefined, sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined, }; } @@ -528,7 +554,7 @@ class Outbound extends CommonClass { canEnableTls() { if (![Protocols.VMess, Protocols.VLESS, Protocols.Trojan, Protocols.Shadowsocks].includes(this.protocol)) return false; - return ["tcp", "ws", "http", "quic", "grpc", "httpupgrade"].includes(this.stream.network); + return ["tcp", "ws", "http", "quic", "grpc", "httpupgrade" , "splithttp"].includes(this.stream.network); } //this is used for xtls-rprx-vision @@ -649,6 +675,8 @@ class Outbound extends CommonClass { stream.grpc = new GrpcStreamSettings(json.path, json.authority, json.type == 'multi'); } else if (network === 'httpupgrade') { stream.httpupgrade = new HttpUpgradeStreamSettings(json.path,json.host); + } else if (network === 'splithttp') { + stream.splithttp = new SplitHTTPStreamSettings(json.path,json.host); } if(json.tls && json.tls == 'tls'){ @@ -696,6 +724,8 @@ class Outbound extends CommonClass { url.searchParams.get('mode') == 'multi'); } else if (type === 'httpupgrade') { stream.httpupgrade = new HttpUpgradeStreamSettings(path,host); + } else if (type === 'splithttp') { + stream.splithttp = new SplitHTTPStreamSettings(path,host); } if(security == 'tls'){ diff --git a/web/assets/js/model/xray.js b/web/assets/js/model/xray.js index 3a8998ef..20c01cf1 100644 --- a/web/assets/js/model/xray.js +++ b/web/assets/js/model/xray.js @@ -84,6 +84,7 @@ Object.freeze(SSMethods); Object.freeze(TLS_FLOW_CONTROL); Object.freeze(TLS_VERSION_OPTION); Object.freeze(TLS_CIPHER_OPTION); +Object.freeze(UTLS_FINGERPRINT); Object.freeze(ALPN_OPTION); Object.freeze(SNIFFING_OPTION); @@ -475,6 +476,44 @@ class HttpUpgradeStreamSettings extends XrayCommonClass { }; } } +class SplitHTTPStreamSettings extends XrayCommonClass { + constructor(path='/', host='', headers=[] , maxUploadSize= 1, maxConcurrentUploads= 10) { + super(); + this.path = path; + this.host = host; + this.headers = headers; + this.maxUploadSize = maxUploadSize; + this.maxConcurrentUploads = maxConcurrentUploads; + } + + addHeader(name, value) { + this.headers.push({ name: name, value: value }); + } + + removeHeader(index) { + this.headers.splice(index, 1); + } + + static fromJson(json={}) { + return new SplitHTTPStreamSettings( + json.path, + json.host, + XrayCommonClass.toHeaders(json.headers), + json.maxUploadSize, + json.maxConcurrentUploads, + ); + } + + toJson() { + return { + path: this.path, + host: this.host, + headers: XrayCommonClass.toV2Headers(this.headers, false), + maxUploadSize: this.maxUploadSize, + maxConcurrentUploads: this.maxConcurrentUploads, + }; + } +} class TlsStreamSettings extends XrayCommonClass { constructor(serverName='', @@ -729,6 +768,7 @@ class StreamSettings extends XrayCommonClass { quicSettings=new QuicStreamSettings(), grpcSettings=new GrpcStreamSettings(), httpupgradeSettings=new HttpUpgradeStreamSettings(), + splithttpSettings=new SplitHTTPStreamSettings(), sockopt = undefined, ) { super(); @@ -744,6 +784,7 @@ class StreamSettings extends XrayCommonClass { this.quic = quicSettings; this.grpc = grpcSettings; this.httpupgrade = httpupgradeSettings; + this.splithttp = splithttpSettings; this.sockopt = sockopt; } @@ -793,6 +834,7 @@ class StreamSettings extends XrayCommonClass { QuicStreamSettings.fromJson(json.quicSettings), GrpcStreamSettings.fromJson(json.grpcSettings), HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings), + SplitHTTPStreamSettings.fromJson(json.splithttpSettings), SockoptStreamSettings.fromJson(json.sockopt), ); } @@ -812,6 +854,7 @@ class StreamSettings extends XrayCommonClass { quicSettings: network === 'quic' ? this.quic.toJson() : undefined, grpcSettings: network === 'grpc' ? this.grpc.toJson() : undefined, httpupgradeSettings: network === 'httpupgrade' ? this.httpupgrade.toJson() : undefined, + splithttpSettings: network === 'splithttp' ? this.splithttp.toJson() : undefined, sockopt: this.sockopt != undefined ? this.sockopt.toJson() : undefined, }; } @@ -927,6 +970,10 @@ class Inbound extends XrayCommonClass { get isHttpupgrade() { return this.network === "httpupgrade"; } + + get isSplithttp() { + return this.network === "splithttp"; + } // Shadowsocks get method() { @@ -967,7 +1014,9 @@ class Inbound extends XrayCommonClass { } else if (this.isWs) { return this.stream.ws.host?.length>0 ? this.stream.ws.host : this.getHeader(this.stream.ws, 'host'); } else if (this.isHttpupgrade) { - return this.stream.httpupgrade.host; + return this.stream.httpupgrade.host?.length>0 ? this.stream.httpupgrade.host : this.getHeader(this.stream.httpupgrade, 'host'); + } else if (this.isSplithttp) { + return this.stream.splithttp.host?.length>0 ? this.stream.splithttp.host : this.getHeader(this.stream.splithttp, 'host'); } return null; } @@ -981,6 +1030,8 @@ class Inbound extends XrayCommonClass { return this.stream.http.path; } else if (this.isHttpupgrade) { return this.stream.httpupgrade.path; + } else if (this.isSplithttp) { + return this.stream.splithttp.path; } return null; } @@ -1016,7 +1067,7 @@ class Inbound extends XrayCommonClass { canEnableTls() { if(![Protocols.VMESS, Protocols.VLESS, Protocols.TROJAN, Protocols.SHADOWSOCKS].includes(this.protocol)) return false; - return ["tcp", "ws", "http", "quic", "grpc", "httpupgrade"].includes(this.network); + return ["tcp", "ws", "http", "quic", "grpc", "httpupgrade" , "splithttp"].includes(this.network); } //this is used for xtls-rprx-vision @@ -1096,7 +1147,11 @@ class Inbound extends XrayCommonClass { } else if (network === 'httpupgrade') { const httpupgrade = this.stream.httpupgrade; obj.path = httpupgrade.path; - obj.host = httpupgrade.host; + obj.host = httpupgrade.host?.length>0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host'); + } else if (network === 'splithttp') { + const splithttp = this.stream.splithttp; + obj.path = splithttp.path; + obj.host = splithttp.host?.length>0 ? splithttp.host : this.getHeader(splithttp, 'host'); } if (security === 'tls') { @@ -1167,10 +1222,15 @@ class Inbound extends XrayCommonClass { } break; case "httpupgrade": - const httpupgrade = this.stream.httpupgrade; - params.set("path", httpupgrade.path); - params.set("host", httpupgrade.host); - break; + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host?.length>0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); + break; + case "splithttp": + const splithttp = this.stream.splithttp; + params.set("path", splithttp.path); + params.set("host", splithttp.host?.length>0 ? splithttp.host : this.getHeader(splithttp, 'host')); + break; } if (security === 'tls') { @@ -1271,10 +1331,15 @@ class Inbound extends XrayCommonClass { } break; case "httpupgrade": - const httpupgrade = this.stream.httpupgrade; - params.set("path", httpupgrade.path); - params.set("host", httpupgrade.host); - break; + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host?.length>0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); + break; + case "splithttp": + const splithttp = this.stream.splithttp; + params.set("path", splithttp.path); + params.set("host", splithttp.host?.length>0 ? splithttp.host : this.getHeader(splithttp, 'host')); + break; } if (security === 'tls') { @@ -1354,10 +1419,15 @@ class Inbound extends XrayCommonClass { } break; case "httpupgrade": - const httpupgrade = this.stream.httpupgrade; - params.set("path", httpupgrade.path); - params.set("host", httpupgrade.host); - break; + const httpupgrade = this.stream.httpupgrade; + params.set("path", httpupgrade.path); + params.set("host", httpupgrade.host?.length>0 ? httpupgrade.host : this.getHeader(httpupgrade, 'host')); + break; + case "splithttp": + const splithttp = this.stream.splithttp; + params.set("path", splithttp.path); + params.set("host", splithttp.host?.length>0 ? splithttp.host : this.getHeader(splithttp, 'host')); + break; } if (security === 'tls') { diff --git a/web/html/xui/form/outbound.html b/web/html/xui/form/outbound.html index 1d5abdc6..7b0fb2ce 100644 --- a/web/html/xui/form/outbound.html +++ b/web/html/xui/form/outbound.html @@ -82,20 +82,9 @@ - - + - + @@ -108,7 +97,7 @@ - + @@ -154,7 +143,7 @@ - + @@ -226,8 +215,8 @@ HTTP/2 QUIC gRPC - HttpUpgrade - + HTTPUpgrade + SplitHTTP + + + diff --git a/web/html/xui/form/stream/stream_settings.html b/web/html/xui/form/stream/stream_settings.html index b559b649..17634bbd 100644 --- a/web/html/xui/form/stream/stream_settings.html +++ b/web/html/xui/form/stream/stream_settings.html @@ -11,6 +11,7 @@ QUIC gRPC HttpUpgrade + SplitHTTP @@ -50,6 +51,11 @@ {{template "form/streamHTTPUPGRADE"}} + + +