From 5341365bb80f24e199888ec836dc2d41445479dd Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 13 Apr 2024 12:21:01 +0800 Subject: [PATCH] Add v2ray httpupgrade fast open support --- option/v2ray_transport.go | 7 +-- transport/v2rayhttpupgrade/client.go | 67 +++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/option/v2ray_transport.go b/option/v2ray_transport.go index fcd81f94..99d0328b 100644 --- a/option/v2ray_transport.go +++ b/option/v2ray_transport.go @@ -92,7 +92,8 @@ type V2RayGRPCOptions struct { } type V2RayHTTPUpgradeOptions struct { - Host string `json:"host,omitempty"` - Path string `json:"path,omitempty"` - Headers HTTPHeader `json:"headers,omitempty"` + Host string `json:"host,omitempty"` + Path string `json:"path,omitempty"` + Headers HTTPHeader `json:"headers,omitempty"` + FastOpen bool `json:"fast_open,omitempty"` } diff --git a/transport/v2rayhttpupgrade/client.go b/transport/v2rayhttpupgrade/client.go index c10e1b8f..87354ca6 100644 --- a/transport/v2rayhttpupgrade/client.go +++ b/transport/v2rayhttpupgrade/client.go @@ -6,11 +6,15 @@ import ( "net" "net/http" "net/url" + "os" "strings" + "sync" + "time" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/option" + "github.com/sagernet/sing/common/atomic" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" E "github.com/sagernet/sing/common/exceptions" @@ -28,6 +32,7 @@ type Client struct { requestURL url.URL headers http.Header host string + fastOpen bool } func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, options option.V2RayHTTPUpgradeOptions, tlsConfig tls.Config) (*Client, error) { @@ -70,6 +75,7 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt requestURL: requestURL, headers: headers, host: host, + fastOpen: options.FastOpen, }, nil } @@ -96,8 +102,17 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { if err != nil { return nil, err } + if c.fastOpen { + return &EarlyHTTPUpgradeConn{ + Conn: conn, + }, nil + } + return readResponse(conn) +} + +func readResponse(conn net.Conn) (net.Conn, error) { bufReader := std_bufio.NewReader(conn) - response, err := http.ReadResponse(bufReader, request) + response, err := http.ReadResponse(bufReader, nil) if err != nil { return nil, err } @@ -116,3 +131,53 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) { } return conn, nil } + +type EarlyHTTPUpgradeConn struct { + net.Conn + once sync.Once + err error + created atomic.Bool +} + +func (c *EarlyHTTPUpgradeConn) Read(b []byte) (int, error) { + c.once.Do(func() { + var newConn net.Conn + newConn, c.err = readResponse(c.Conn) + if c.err == nil { + c.Conn = newConn + c.created.Store(true) + } + }) + if c.err != nil { + return 0, c.err + } + return c.Conn.Read(b) +} + +func (c *EarlyHTTPUpgradeConn) Upstream() any { + return c.Conn +} + +func (c *EarlyHTTPUpgradeConn) ReaderReplaceable() bool { + return c.created.Load() +} + +func (c *EarlyHTTPUpgradeConn) WriterReplaceable() bool { + return true +} + +func (c *EarlyHTTPUpgradeConn) SetDeadline(time.Time) error { + return os.ErrInvalid +} + +func (c *EarlyHTTPUpgradeConn) SetReadDeadline(time.Time) error { + return os.ErrInvalid +} + +func (c *EarlyHTTPUpgradeConn) SetWriteDeadline(time.Time) error { + return os.ErrInvalid +} + +func (c *EarlyHTTPUpgradeConn) NeedAdditionalReadDeadline() bool { + return true +}