mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-04-22 23:27:15 +08:00
chore: let xhttp server passing stream-one and stream-up mode test under http1
This commit is contained in:
+167
-160
@@ -378,40 +378,43 @@ func TestInboundVless_XHTTP(t *testing.T) {
|
||||
}
|
||||
return inboundOptions, outboundOptions
|
||||
}
|
||||
|
||||
t.Run("nosplit", func(t *testing.T) {
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVlessTLS(t, inboundOptions, withXHTTPReuse(outboundOptions), false)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("split", func(t *testing.T) {
|
||||
if testCase.mode == "stream-one" { // stream-one not supported download settings
|
||||
return
|
||||
}
|
||||
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVlessTLS(t, inboundOptions, withXHTTPReuse(outboundOptions), false)
|
||||
})
|
||||
})
|
||||
testInboundVless_XHTTP(t, getConfig, testCase.mode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testInboundVless_XHTTP(t *testing.T, getConfig func() (inbound.VlessOption, outbound.VlessOption), mode string) {
|
||||
t.Run("nosplit", func(t *testing.T) {
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVlessTLS(t, inboundOptions, withXHTTPReuse(outboundOptions), false)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("split", func(t *testing.T) {
|
||||
if mode == "stream-one" { // stream-one not supported download settings
|
||||
return
|
||||
}
|
||||
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVlessTLS(t, inboundOptions, withXHTTPReuse(outboundOptions), false)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundVless_XHTTP_Reality(t *testing.T) {
|
||||
testCases := []struct {
|
||||
mode string
|
||||
@@ -455,40 +458,43 @@ func TestInboundVless_XHTTP_Reality(t *testing.T) {
|
||||
}
|
||||
return inboundOptions, outboundOptions
|
||||
}
|
||||
|
||||
t.Run("nosplit", func(t *testing.T) {
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, withXHTTPReuse(outboundOptions))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("split", func(t *testing.T) {
|
||||
if testCase.mode == "stream-one" { // stream-one not supported download settings
|
||||
return
|
||||
}
|
||||
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVless(t, inboundOptions, withXHTTPReuse(outboundOptions))
|
||||
})
|
||||
})
|
||||
testInboundVless_XHTTP_Reality(t, getConfig, testCase.mode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testInboundVless_XHTTP_Reality(t *testing.T, getConfig func() (inbound.VlessOption, outbound.VlessOption), mode string) {
|
||||
t.Run("nosplit", func(t *testing.T) {
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, withXHTTPReuse(outboundOptions))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("split", func(t *testing.T) {
|
||||
if mode == "stream-one" { // stream-one not supported download settings
|
||||
return
|
||||
}
|
||||
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVless(t, inboundOptions, withXHTTPReuse(outboundOptions))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundVless_XHTTP_Encryption(t *testing.T) {
|
||||
privateKeyBase64, passwordBase64, _, err := encryption.GenX25519("")
|
||||
if err != nil {
|
||||
@@ -526,123 +532,124 @@ func TestInboundVless_XHTTP_Encryption(t *testing.T) {
|
||||
}
|
||||
return inboundOptions, outboundOptions
|
||||
}
|
||||
|
||||
t.Run("nosplit", func(t *testing.T) {
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, withXHTTPReuse(outboundOptions))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("split", func(t *testing.T) {
|
||||
if testCase.mode == "stream-one" { // stream-one not supported download settings
|
||||
return
|
||||
}
|
||||
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVless(t, inboundOptions, withXHTTPReuse(outboundOptions))
|
||||
})
|
||||
})
|
||||
testInboundVless_XHTTP_Encryption(t, getConfig, testCase.mode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInboundVless_XHTTP_PacketUp_H1(t *testing.T) {
|
||||
getConfig := func() (inbound.VlessOption, outbound.VlessOption) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
XHTTPConfig: inbound.XHTTPConfig{
|
||||
Path: "/vless-xhttp",
|
||||
Host: "example.com",
|
||||
Mode: "packet-up",
|
||||
},
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
TLS: true,
|
||||
Fingerprint: tlsFingerprint,
|
||||
Network: "xhttp",
|
||||
ALPN: []string{"http/1.1"},
|
||||
XHTTPOpts: outbound.XHTTPOptions{
|
||||
Path: "/vless-xhttp",
|
||||
Host: "example.com",
|
||||
Mode: "packet-up",
|
||||
},
|
||||
}
|
||||
return inboundOptions, outboundOptions
|
||||
}
|
||||
func testInboundVless_XHTTP_Encryption(t *testing.T, getConfig func() (inbound.VlessOption, outbound.VlessOption), mode string) {
|
||||
t.Run("nosplit", func(t *testing.T) {
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
|
||||
t.Run("default", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVlessTLS(t, inboundOptions, outboundOptions, false)
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, withXHTTPReuse(outboundOptions))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVlessTLS(t, inboundOptions, withXHTTPReuse(outboundOptions), false)
|
||||
t.Run("split", func(t *testing.T) {
|
||||
if mode == "stream-one" { // stream-one not supported download settings
|
||||
return
|
||||
}
|
||||
|
||||
t.Run("single", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
outboundOptions.XHTTPOpts.DownloadSettings = &outbound.XHTTPDownloadSettings{}
|
||||
testInboundVless(t, inboundOptions, withXHTTPReuse(outboundOptions))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestInboundVless_XHTTP_PacketUp_H1_Encryption(t *testing.T) {
|
||||
func TestInboundVless_XHTTP_H1(t *testing.T) {
|
||||
testCases := []struct {
|
||||
mode string
|
||||
}{
|
||||
{mode: "auto"},
|
||||
{mode: "stream-one"},
|
||||
{mode: "stream-up"},
|
||||
{mode: "packet-up"},
|
||||
}
|
||||
for _, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(testCase.mode, func(t *testing.T) {
|
||||
getConfig := func() (inbound.VlessOption, outbound.VlessOption) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Certificate: tlsCertificate,
|
||||
PrivateKey: tlsPrivateKey,
|
||||
XHTTPConfig: inbound.XHTTPConfig{
|
||||
Path: "/vless-xhttp",
|
||||
Host: "example.com",
|
||||
Mode: testCase.mode,
|
||||
},
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
TLS: true,
|
||||
Fingerprint: tlsFingerprint,
|
||||
Network: "xhttp",
|
||||
ALPN: []string{"http/1.1"},
|
||||
XHTTPOpts: outbound.XHTTPOptions{
|
||||
Path: "/vless-xhttp",
|
||||
Host: "example.com",
|
||||
Mode: testCase.mode,
|
||||
},
|
||||
}
|
||||
return inboundOptions, outboundOptions
|
||||
}
|
||||
testInboundVless_XHTTP(t, getConfig, testCase.mode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInboundVless_XHTTP_H1_Encryption(t *testing.T) {
|
||||
privateKeyBase64, passwordBase64, _, err := encryption.GenX25519("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
getConfig := func() (inbound.VlessOption, outbound.VlessOption) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Decryption: "mlkem768x25519plus.native.600s." + privateKeyBase64,
|
||||
XHTTPConfig: inbound.XHTTPConfig{
|
||||
Path: "/vless-xhttp",
|
||||
Host: "example.com",
|
||||
Mode: "packet-up",
|
||||
},
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
Encryption: "mlkem768x25519plus.native.0rtt." + passwordBase64,
|
||||
Network: "xhttp",
|
||||
ALPN: []string{"http/1.1"},
|
||||
XHTTPOpts: outbound.XHTTPOptions{
|
||||
Path: "/vless-xhttp",
|
||||
Host: "example.com",
|
||||
Mode: "packet-up",
|
||||
},
|
||||
}
|
||||
return inboundOptions, outboundOptions
|
||||
testCases := []struct {
|
||||
mode string
|
||||
}{
|
||||
{mode: "auto"},
|
||||
{mode: "stream-one"},
|
||||
{mode: "stream-up"},
|
||||
{mode: "packet-up"},
|
||||
}
|
||||
|
||||
t.Run("default", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
outboundOptions := outboundOptions
|
||||
outboundOptions.Flow = "xtls-rprx-vision"
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
for _, testCase := range testCases {
|
||||
testCase := testCase
|
||||
t.Run(testCase.mode, func(t *testing.T) {
|
||||
getConfig := func() (inbound.VlessOption, outbound.VlessOption) {
|
||||
inboundOptions := inbound.VlessOption{
|
||||
Decryption: "mlkem768x25519plus.native.600s." + privateKeyBase64,
|
||||
XHTTPConfig: inbound.XHTTPConfig{
|
||||
Path: "/vless-xhttp",
|
||||
Host: "example.com",
|
||||
Mode: testCase.mode,
|
||||
},
|
||||
}
|
||||
outboundOptions := outbound.VlessOption{
|
||||
Encryption: "mlkem768x25519plus.native.0rtt." + passwordBase64,
|
||||
Network: "xhttp",
|
||||
ALPN: []string{"http/1.1"},
|
||||
XHTTPOpts: outbound.XHTTPOptions{
|
||||
Path: "/vless-xhttp",
|
||||
Host: "example.com",
|
||||
Mode: testCase.mode,
|
||||
},
|
||||
}
|
||||
return inboundOptions, outboundOptions
|
||||
}
|
||||
testInboundVless_XHTTP_Encryption(t, getConfig, testCase.mode)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("reuse", func(t *testing.T) {
|
||||
inboundOptions, outboundOptions := getConfig()
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
t.Run("xtls-rprx-vision", func(t *testing.T) {
|
||||
outboundOptions := outboundOptions
|
||||
outboundOptions.Flow = "xtls-rprx-vision"
|
||||
testInboundVless(t, inboundOptions, outboundOptions)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func withXHTTPReuse(out outbound.VlessOption) outbound.VlessOption {
|
||||
|
||||
@@ -28,13 +28,13 @@ type httpServerConn struct {
|
||||
mu sync.Mutex
|
||||
w http.ResponseWriter
|
||||
flusher http.Flusher
|
||||
reader io.Reader
|
||||
reader io.ReadCloser
|
||||
closed bool
|
||||
done chan struct{}
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func newHTTPServerConn(w http.ResponseWriter, r io.Reader) *httpServerConn {
|
||||
func newHTTPServerConn(w http.ResponseWriter, r io.ReadCloser) *httpServerConn {
|
||||
flusher, _ := w.(http.Flusher)
|
||||
return &httpServerConn{
|
||||
w: w,
|
||||
@@ -70,7 +70,7 @@ func (c *httpServerConn) Close() error {
|
||||
c.mu.Unlock()
|
||||
close(c.done)
|
||||
})
|
||||
return nil
|
||||
return c.reader.Close()
|
||||
}
|
||||
|
||||
func (c *httpServerConn) Wait() <-chan struct{} {
|
||||
@@ -305,6 +305,11 @@ func (h *requestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
|
||||
rc := http.NewResponseController(w)
|
||||
_ = rc.EnableFullDuplex() // http1 need to enable full duplex manually
|
||||
_ = rc.Flush() // force flush the response header
|
||||
|
||||
referrer := r.Header.Get("Referer")
|
||||
if referrer != "" && h.scStreamUpServerSecs.Max > 0 {
|
||||
go func() {
|
||||
@@ -440,9 +445,10 @@ func (h *requestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
|
||||
rc := http.NewResponseController(w)
|
||||
_ = rc.EnableFullDuplex() // http1 need to enable full duplex manually
|
||||
_ = rc.Flush() // force flush the response header
|
||||
|
||||
httpSC := newHTTPServerConn(w, r.Body)
|
||||
conn := &Conn{
|
||||
@@ -470,9 +476,10 @@ func (h *requestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Accel-Buffering", "no")
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if flusher, ok := w.(http.Flusher); ok {
|
||||
flusher.Flush()
|
||||
}
|
||||
|
||||
rc := http.NewResponseController(w)
|
||||
_ = rc.EnableFullDuplex() // http1 need to enable full duplex manually
|
||||
_ = rc.Flush() // force flush the response header
|
||||
|
||||
httpSC := newHTTPServerConn(w, r.Body)
|
||||
conn := &Conn{
|
||||
|
||||
Reference in New Issue
Block a user