mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-04-22 16:17:16 +08:00
feat: add http1.1 mode support for xhttp client
This commit is contained in:
+2
-3
@@ -807,7 +807,7 @@ proxies: # socks5
|
||||
udp: true
|
||||
tls: true
|
||||
network: xhttp
|
||||
alpn: [h2] # 默认为h2,如果开启h3模式需要设置alpn: [h3]
|
||||
alpn: [h2] # 默认仅支持h2,如果开启h3模式需要设置alpn: [h3],如果开启http1.1模式需要设置alpn: [http/1.1]
|
||||
# ech-opts: ...
|
||||
# reality-opts: ...
|
||||
# skip-cert-verify: false
|
||||
@@ -851,8 +851,7 @@ proxies: # socks5
|
||||
# server: server
|
||||
# port: 443
|
||||
# tls: true
|
||||
# alpn:
|
||||
# - h2
|
||||
# alpn: ...
|
||||
# ech-opts: ...
|
||||
# reality-opts: ...
|
||||
# skip-cert-verify: false
|
||||
|
||||
@@ -488,6 +488,42 @@ func TestInboundVless_XHTTP_Reality(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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()
|
||||
testInboundVlessTLS(t, inboundOptions, withXHTTPReuse(outboundOptions), false)
|
||||
})
|
||||
}
|
||||
|
||||
func withXHTTPReuse(out outbound.VlessOption) outbound.VlessOption {
|
||||
out.XHTTPOpts.ReuseSettings = &outbound.XHTTPReuseSettings{
|
||||
MaxConnections: "0",
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/metacubex/quic-go"
|
||||
"github.com/metacubex/quic-go/http3"
|
||||
"github.com/metacubex/tls"
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
type DialRawFunc func(ctx context.Context) (net.Conn, error)
|
||||
@@ -100,6 +101,16 @@ func (c *PacketUpWriter) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// h1Transport is a wrapper that forces the underlying transport to use HTTP/1.1.
|
||||
type h1Transport struct {
|
||||
http.RoundTripper
|
||||
}
|
||||
|
||||
func (c h1Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req.URL.Scheme = "http" // change the scheme to http allow we can make TLS in ourselves Transport.DialContext
|
||||
return c.RoundTripper.RoundTrip(req)
|
||||
}
|
||||
|
||||
func NewTransport(dialRaw DialRawFunc, wrapTLS WrapTLSFunc, dialQUIC DialQUICFunc, alpn []string) http.RoundTripper {
|
||||
if len(alpn) == 1 && alpn[0] == "h3" { // `alpn: [h3]` means using h3 mode
|
||||
return &http3.Transport{
|
||||
@@ -112,6 +123,28 @@ func NewTransport(dialRaw DialRawFunc, wrapTLS WrapTLSFunc, dialQUIC DialQUICFun
|
||||
},
|
||||
}
|
||||
}
|
||||
if len(alpn) == 1 && alpn[0] == "http/1.1" { // `alpn: [http/1.1]` means using http/1.1 mode
|
||||
w := semaphore.NewWeighted(20) // limit concurrent dialing to avoid WSAECONNREFUSED on Windows
|
||||
return h1Transport{&http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
if err := w.Acquire(ctx, 1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer w.Release(1)
|
||||
raw, err := dialRaw(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wrapped, err := wrapTLS(ctx, raw, false)
|
||||
if err != nil {
|
||||
_ = raw.Close()
|
||||
return nil, err
|
||||
}
|
||||
return wrapped, nil
|
||||
},
|
||||
ForceAttemptHTTP2: false, // only http/1.1
|
||||
}}
|
||||
}
|
||||
return &http.Http2Transport{
|
||||
DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) {
|
||||
raw, err := dialRaw(ctx)
|
||||
|
||||
Reference in New Issue
Block a user