mirror of
https://github.com/XTLS/Xray-core.git
synced 2025-05-15 05:54:13 +08:00

* Add H2C support to server * update comment * Make http1.1 ALPN work on SplitHTTP client Users that encounter protocol version issues will likely try to set the ALPN explicitly. In that case we should simply grant their wish, because the intent is obvious.
206 lines
5.1 KiB
Go
206 lines
5.1 KiB
Go
package splithttp_test
|
|
|
|
import (
|
|
"context"
|
|
gotls "crypto/tls"
|
|
"fmt"
|
|
gonet "net"
|
|
"net/http"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/xtls/xray-core/common"
|
|
"github.com/xtls/xray-core/common/net"
|
|
"github.com/xtls/xray-core/common/protocol/tls/cert"
|
|
"github.com/xtls/xray-core/testing/servers/tcp"
|
|
"github.com/xtls/xray-core/transport/internet"
|
|
. "github.com/xtls/xray-core/transport/internet/splithttp"
|
|
"github.com/xtls/xray-core/transport/internet/stat"
|
|
"github.com/xtls/xray-core/transport/internet/tls"
|
|
"golang.org/x/net/http2"
|
|
)
|
|
|
|
func Test_listenSHAndDial(t *testing.T) {
|
|
listenPort := tcp.PickPort()
|
|
listen, err := ListenSH(context.Background(), net.LocalHostIP, listenPort, &internet.MemoryStreamConfig{
|
|
ProtocolName: "splithttp",
|
|
ProtocolSettings: &Config{
|
|
Path: "/sh",
|
|
},
|
|
}, func(conn stat.Connection) {
|
|
go func(c stat.Connection) {
|
|
defer c.Close()
|
|
|
|
var b [1024]byte
|
|
_, err := c.Read(b[:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
common.Must2(c.Write([]byte("Response")))
|
|
}(conn)
|
|
})
|
|
common.Must(err)
|
|
ctx := context.Background()
|
|
streamSettings := &internet.MemoryStreamConfig{
|
|
ProtocolName: "splithttp",
|
|
ProtocolSettings: &Config{Path: "sh"},
|
|
}
|
|
conn, err := Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), listenPort), streamSettings)
|
|
|
|
common.Must(err)
|
|
_, err = conn.Write([]byte("Test connection 1"))
|
|
common.Must(err)
|
|
|
|
var b [1024]byte
|
|
fmt.Println("test2")
|
|
n, _ := conn.Read(b[:])
|
|
fmt.Println("string is", n)
|
|
if string(b[:n]) != "Response" {
|
|
t.Error("response: ", string(b[:n]))
|
|
}
|
|
|
|
common.Must(conn.Close())
|
|
<-time.After(time.Second * 5)
|
|
conn, err = Dial(ctx, net.TCPDestination(net.DomainAddress("localhost"), listenPort), streamSettings)
|
|
common.Must(err)
|
|
_, err = conn.Write([]byte("Test connection 2"))
|
|
common.Must(err)
|
|
n, _ = conn.Read(b[:])
|
|
common.Must(err)
|
|
if string(b[:n]) != "Response" {
|
|
t.Error("response: ", string(b[:n]))
|
|
}
|
|
common.Must(conn.Close())
|
|
|
|
common.Must(listen.Close())
|
|
}
|
|
|
|
func TestDialWithRemoteAddr(t *testing.T) {
|
|
listenPort := tcp.PickPort()
|
|
listen, err := ListenSH(context.Background(), net.LocalHostIP, listenPort, &internet.MemoryStreamConfig{
|
|
ProtocolName: "splithttp",
|
|
ProtocolSettings: &Config{
|
|
Path: "sh",
|
|
},
|
|
}, func(conn stat.Connection) {
|
|
go func(c stat.Connection) {
|
|
defer c.Close()
|
|
|
|
var b [1024]byte
|
|
_, err := c.Read(b[:])
|
|
// common.Must(err)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
_, err = c.Write([]byte("Response"))
|
|
common.Must(err)
|
|
}(conn)
|
|
})
|
|
common.Must(err)
|
|
|
|
conn, err := Dial(context.Background(), net.TCPDestination(net.DomainAddress("localhost"), listenPort), &internet.MemoryStreamConfig{
|
|
ProtocolName: "splithttp",
|
|
ProtocolSettings: &Config{Path: "sh", Header: map[string]string{"X-Forwarded-For": "1.1.1.1"}},
|
|
})
|
|
|
|
common.Must(err)
|
|
_, err = conn.Write([]byte("Test connection 1"))
|
|
common.Must(err)
|
|
|
|
var b [1024]byte
|
|
n, _ := conn.Read(b[:])
|
|
if string(b[:n]) != "Response" {
|
|
t.Error("response: ", string(b[:n]))
|
|
}
|
|
|
|
common.Must(listen.Close())
|
|
}
|
|
|
|
func Test_listenSHAndDial_TLS(t *testing.T) {
|
|
if runtime.GOARCH == "arm64" {
|
|
return
|
|
}
|
|
|
|
listenPort := tcp.PickPort()
|
|
|
|
start := time.Now()
|
|
|
|
streamSettings := &internet.MemoryStreamConfig{
|
|
ProtocolName: "splithttp",
|
|
ProtocolSettings: &Config{
|
|
Path: "shs",
|
|
},
|
|
SecurityType: "tls",
|
|
SecuritySettings: &tls.Config{
|
|
AllowInsecure: true,
|
|
Certificate: []*tls.Certificate{tls.ParseCertificate(cert.MustGenerate(nil, cert.CommonName("localhost")))},
|
|
},
|
|
}
|
|
listen, err := ListenSH(context.Background(), net.LocalHostIP, listenPort, streamSettings, func(conn stat.Connection) {
|
|
go func() {
|
|
_ = conn.Close()
|
|
}()
|
|
})
|
|
common.Must(err)
|
|
defer listen.Close()
|
|
|
|
conn, err := Dial(context.Background(), net.TCPDestination(net.DomainAddress("localhost"), listenPort), streamSettings)
|
|
common.Must(err)
|
|
_ = conn.Close()
|
|
|
|
end := time.Now()
|
|
if !end.Before(start.Add(time.Second * 5)) {
|
|
t.Error("end: ", end, " start: ", start)
|
|
}
|
|
}
|
|
|
|
func Test_listenSHAndDial_H2C(t *testing.T) {
|
|
if runtime.GOARCH == "arm64" {
|
|
return
|
|
}
|
|
|
|
listenPort := tcp.PickPort()
|
|
|
|
streamSettings := &internet.MemoryStreamConfig{
|
|
ProtocolName: "splithttp",
|
|
ProtocolSettings: &Config{
|
|
Path: "shs",
|
|
},
|
|
}
|
|
listen, err := ListenSH(context.Background(), net.LocalHostIP, listenPort, streamSettings, func(conn stat.Connection) {
|
|
go func() {
|
|
_ = conn.Close()
|
|
}()
|
|
})
|
|
common.Must(err)
|
|
defer listen.Close()
|
|
|
|
client := http.Client{
|
|
Transport: &http2.Transport{
|
|
// So http2.Transport doesn't complain the URL scheme isn't 'https'
|
|
AllowHTTP: true,
|
|
// even with AllowHTTP, http2.Transport will attempt to establish
|
|
// the connection using DialTLSContext. Disable TLS with custom
|
|
// dial context.
|
|
DialTLSContext: func(ctx context.Context, network, addr string, cfg *gotls.Config) (gonet.Conn, error) {
|
|
var d gonet.Dialer
|
|
return d.DialContext(ctx, network, addr)
|
|
},
|
|
},
|
|
}
|
|
|
|
resp, err := client.Get("http://" + net.LocalHostIP.String() + ":" + listenPort.String())
|
|
common.Must(err)
|
|
|
|
if resp.StatusCode != 404 {
|
|
t.Error("Expected 404 but got:", resp.StatusCode)
|
|
}
|
|
|
|
if resp.ProtoMajor != 2 {
|
|
t.Error("Expected h2 but got:", resp.ProtoMajor)
|
|
}
|
|
}
|