Skip to content

Commit

Permalink
Transport: Remove HTTP
Browse files Browse the repository at this point in the history
Migrated to XHTTP "stream-one" mode.
  • Loading branch information
RPRX committed Dec 2, 2024
1 parent 98a72b6 commit ae62a0f
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 1,216 deletions.
135 changes: 40 additions & 95 deletions infra/conf/transport_internet.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import (
"github.com/xtls/xray-core/common/platform/filesystem"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/transport/internet"
httpheader "github.com/xtls/xray-core/transport/internet/headers/http"
"github.com/xtls/xray-core/transport/internet/http"
"github.com/xtls/xray-core/transport/internet/httpupgrade"
"github.com/xtls/xray-core/transport/internet/kcp"
"github.com/xtls/xray-core/transport/internet/reality"
Expand Down Expand Up @@ -344,51 +342,6 @@ func (c *SplitHTTPConfig) Build() (proto.Message, error) {
return config, nil
}

type HTTPConfig struct {
Host *StringList `json:"host"`
Path string `json:"path"`
ReadIdleTimeout int32 `json:"read_idle_timeout"`
HealthCheckTimeout int32 `json:"health_check_timeout"`
Method string `json:"method"`
Headers map[string]*StringList `json:"headers"`
}

// Build implements Buildable.
func (c *HTTPConfig) Build() (proto.Message, error) {
if c.ReadIdleTimeout <= 0 {
c.ReadIdleTimeout = 0
}
if c.HealthCheckTimeout <= 0 {
c.HealthCheckTimeout = 0
}
config := &http.Config{
Path: c.Path,
IdleTimeout: c.ReadIdleTimeout,
HealthCheckTimeout: c.HealthCheckTimeout,
}
if c.Host != nil {
config.Host = []string(*c.Host)
}
if c.Method != "" {
config.Method = c.Method
}
if len(c.Headers) > 0 {
config.Header = make([]*httpheader.Header, 0, len(c.Headers))
headerNames := sortMapKeys(c.Headers)
for _, key := range headerNames {
value := c.Headers[key]
if value == nil {
return nil, errors.New("empty HTTP header value: " + key).AtError()
}
config.Header = append(config.Header, &httpheader.Header{
Name: key,
Value: append([]string(nil), (*value)...),
})
}
}
return config, nil
}

func readFileOrString(f string, s []string) ([]byte, error) {
if len(f) > 0 {
return filesystem.ReadFile(f)
Expand Down Expand Up @@ -709,20 +662,23 @@ func (p TransportProtocol) Build() (string, error) {
switch strings.ToLower(string(p)) {
case "raw", "tcp":
return "tcp", nil
case "xhttp", "splithttp":
return "splithttp", nil
case "kcp", "mkcp":
return "mkcp", nil
case "ws", "websocket":
return "websocket", nil
case "h2", "h3", "http":
errors.PrintDeprecatedFeatureWarning("HTTP transport", "XHTTP transport")
return "http", nil
case "grpc":
errors.PrintMigrateFeatureInfo("gRPC transport", "XHTTP transport")
errors.PrintDeprecatedFeatureWarning("gRPC transport (with unnecessary costs, etc.)", "XHTTP stream-up H2")
return "grpc", nil
case "ws", "websocket":
errors.PrintDeprecatedFeatureWarning("WebSocket transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
return "websocket", nil
case "httpupgrade":
errors.PrintDeprecatedFeatureWarning("HTTPUpgrade transport (with ALPN http/1.1, etc.)", "XHTTP H2 & H3")
return "httpupgrade", nil
case "xhttp", "splithttp":
return "splithttp", nil
case "h2", "h3", "http":
return "", errors.PrintRemovedFeatureError("HTTP transport (without header padding, etc.)", "XHTTP stream-one H2 & H3")
case "quic":
return "", errors.PrintRemovedFeatureError("QUIC transport (without web service, etc.)", "XHTTP stream-one H3")
default:
return "", errors.New("Config: unknown transport protocol: ", p)
}
Expand Down Expand Up @@ -852,14 +808,13 @@ type StreamConfig struct {
REALITYSettings *REALITYConfig `json:"realitySettings"`
RAWSettings *TCPConfig `json:"rawSettings"`
TCPSettings *TCPConfig `json:"tcpSettings"`
XHTTPSettings *SplitHTTPConfig `json:"xhttpSettings"`
SplitHTTPSettings *SplitHTTPConfig `json:"splithttpSettings"`
KCPSettings *KCPConfig `json:"kcpSettings"`
GRPCSettings *GRPCConfig `json:"grpcSettings"`
WSSettings *WebSocketConfig `json:"wsSettings"`
HTTPSettings *HTTPConfig `json:"httpSettings"`
SocketSettings *SocketConfig `json:"sockopt"`
GRPCConfig *GRPCConfig `json:"grpcSettings"`
HTTPUPGRADESettings *HttpUpgradeConfig `json:"httpupgradeSettings"`
XHTTPSettings *SplitHTTPConfig `json:"xhttpSettings"`
SplitHTTPSettings *SplitHTTPConfig `json:"splithttpSettings"`
SocketSettings *SocketConfig `json:"sockopt"`
}

// Build implements Buildable.
Expand Down Expand Up @@ -893,8 +848,8 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
config.SecuritySettings = append(config.SecuritySettings, tm)
config.SecurityType = tm.Type
case "reality":
if config.ProtocolName != "tcp" && config.ProtocolName != "http" && config.ProtocolName != "grpc" && config.ProtocolName != "splithttp" {
return nil, errors.New("REALITY only supports RAW, H2, gRPC and XHTTP for now.")
if config.ProtocolName != "tcp" && config.ProtocolName != "splithttp" && config.ProtocolName != "grpc" {
return nil, errors.New("REALITY only supports RAW, XHTTP and gRPC for now.")
}
if c.REALITYSettings == nil {
return nil, errors.New(`REALITY: Empty "realitySettings".`)
Expand Down Expand Up @@ -924,38 +879,31 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
Settings: serial.ToTypedMessage(ts),
})
}
if c.KCPSettings != nil {
ts, err := c.KCPSettings.Build()
if err != nil {
return nil, errors.New("Failed to build mKCP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "mkcp",
Settings: serial.ToTypedMessage(ts),
})
if c.XHTTPSettings != nil {
c.SplitHTTPSettings = c.XHTTPSettings
}
if c.WSSettings != nil {
ts, err := c.WSSettings.Build()
if c.SplitHTTPSettings != nil {
hs, err := c.SplitHTTPSettings.Build()
if err != nil {
return nil, errors.New("Failed to build WebSocket config.").Base(err)
return nil, errors.New("Failed to build XHTTP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "websocket",
Settings: serial.ToTypedMessage(ts),
ProtocolName: "splithttp",
Settings: serial.ToTypedMessage(hs),
})
}
if c.HTTPSettings != nil {
ts, err := c.HTTPSettings.Build()
if c.KCPSettings != nil {
ts, err := c.KCPSettings.Build()
if err != nil {
return nil, errors.New("Failed to build HTTP config.").Base(err)
return nil, errors.New("Failed to build mKCP config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "http",
ProtocolName: "mkcp",
Settings: serial.ToTypedMessage(ts),
})
}
if c.GRPCConfig != nil {
gs, err := c.GRPCConfig.Build()
if c.GRPCSettings != nil {
gs, err := c.GRPCSettings.Build()
if err != nil {
return nil, errors.New("Failed to build gRPC config.").Base(err)
}
Expand All @@ -964,33 +912,30 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
Settings: serial.ToTypedMessage(gs),
})
}
if c.HTTPUPGRADESettings != nil {
hs, err := c.HTTPUPGRADESettings.Build()
if c.WSSettings != nil {
ts, err := c.WSSettings.Build()
if err != nil {
return nil, errors.New("Failed to build HttpUpgrade config.").Base(err)
return nil, errors.New("Failed to build WebSocket config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "httpupgrade",
Settings: serial.ToTypedMessage(hs),
ProtocolName: "websocket",
Settings: serial.ToTypedMessage(ts),
})
}
if c.XHTTPSettings != nil {
c.SplitHTTPSettings = c.XHTTPSettings
}
if c.SplitHTTPSettings != nil {
hs, err := c.SplitHTTPSettings.Build()
if c.HTTPUPGRADESettings != nil {
hs, err := c.HTTPUPGRADESettings.Build()
if err != nil {
return nil, errors.New("Failed to build XHTTP config.").Base(err)
return nil, errors.New("Failed to build HTTPUpgrade config.").Base(err)
}
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
ProtocolName: "splithttp",
ProtocolName: "httpupgrade",
Settings: serial.ToTypedMessage(hs),
})
}
if c.SocketSettings != nil {
ss, err := c.SocketSettings.Build()
if err != nil {
return nil, errors.New("Failed to build sockopt").Base(err)
return nil, errors.New("Failed to build sockopt.").Base(err)
}
config.SocketSettings = ss
}
Expand Down
1 change: 0 additions & 1 deletion main/distro/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ import (

// Transports
_ "github.com/xtls/xray-core/transport/internet/grpc"
_ "github.com/xtls/xray-core/transport/internet/http"
_ "github.com/xtls/xray-core/transport/internet/httpupgrade"
_ "github.com/xtls/xray-core/transport/internet/kcp"
_ "github.com/xtls/xray-core/transport/internet/reality"
Expand Down
123 changes: 0 additions & 123 deletions testing/scenarios/tls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/xtls/xray-core/testing/servers/udp"
"github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/grpc"
"github.com/xtls/xray-core/transport/internet/http"
"github.com/xtls/xray-core/transport/internet/tls"
"github.com/xtls/xray-core/transport/internet/websocket"
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -458,128 +457,6 @@ func TestTLSOverWebSocket(t *testing.T) {
}
}

func TestHTTP2(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
}
dest, err := tcpServer.Start()
common.Must(err)
defer tcpServer.Close()

userID := protocol.NewID(uuid.New())
serverPort := tcp.PickPort()
serverConfig := &core.Config{
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
StreamSettings: &internet.StreamConfig{
ProtocolName: "http",
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "http",
Settings: serial.ToTypedMessage(&http.Config{
Host: []string{"example.com"},
Path: "/testpath",
}),
},
},
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil))},
}),
},
},
}),
ProxySettings: serial.ToTypedMessage(&inbound.Config{
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
},
},
}

clientPort := tcp.PickPort()
clientConfig := &core.Config{
Inbound: []*core.InboundHandlerConfig{
{
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(clientPort)}},
Listen: net.NewIPOrDomain(net.LocalHostIP),
}),
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
Address: net.NewIPOrDomain(dest.Address),
Port: uint32(dest.Port),
Networks: []net.Network{net.Network_TCP},
}),
},
},
Outbound: []*core.OutboundHandlerConfig{
{
ProxySettings: serial.ToTypedMessage(&outbound.Config{
Receiver: []*protocol.ServerEndpoint{
{
Address: net.NewIPOrDomain(net.LocalHostIP),
Port: uint32(serverPort),
User: []*protocol.User{
{
Account: serial.ToTypedMessage(&vmess.Account{
Id: userID.String(),
}),
},
},
},
},
}),
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
StreamSettings: &internet.StreamConfig{
ProtocolName: "http",
TransportSettings: []*internet.TransportConfig{
{
ProtocolName: "http",
Settings: serial.ToTypedMessage(&http.Config{
Host: []string{"example.com"},
Path: "/testpath",
}),
},
},
SecurityType: serial.GetMessageType(&tls.Config{}),
SecuritySettings: []*serial.TypedMessage{
serial.ToTypedMessage(&tls.Config{
AllowInsecure: true,
}),
},
},
}),
},
},
}

servers, err := InitializeServerConfigs(serverConfig, clientConfig)
common.Must(err)
defer CloseAllServers(servers)

var errg errgroup.Group
for i := 0; i < 10; i++ {
errg.Go(testTCPConn(clientPort, 1024*1024, time.Second*40))
}
if err := errg.Wait(); err != nil {
t.Error(err)
}
}

func TestGRPC(t *testing.T) {
tcpServer := tcp.Server{
MsgProcessor: xor,
Expand Down
Loading

3 comments on commit ae62a0f

@lxhao61
Copy link

@lxhao61 lxhao61 commented on ae62a0f Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

大神,HTTP 传输删除,按照介绍由 XHTTP 传输 stream-one 模式兼容,但按照如下转换不成功,不知那里有错?
服务端 HTTP 传输方式:

      "streamSettings": {
        "network": "http",
        "httpSettings": {
          "path": "/H2test"
        }
      },

服务端 XHTTP 传输方式:

      "streamSettings": {
        "network": "xhttp",
        "xhttpSettings": {
          "mode": "stream-one",
          "path": "/H2test",
          "xPaddingBytes": "-1"
        }
      },

@RPRX
Copy link
Member Author

@RPRX RPRX commented on ae62a0f Dec 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lxhao61 xPaddingBytes 设为数字 -1 试试

@RPRX
Copy link
Member Author

@RPRX RPRX commented on ae62a0f Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lxhao61 xPaddingBytes 设为数字 -1 试试

不是这个问题,看了下代码对 "-1" 的解析正常,但是 XHTTP 会把 /yourpath 解析成 /yourpath/,所以 HTTP 的 path 需要以 / 结尾

然后我测试了一下是可以兼容的,并且我想了很久,最终决定不修改 XHTTP 的上述行为,而是在 #4071 #4113 中补充说明

Please sign in to comment.