From 5c41292836a94721427b56e512939895d5f7718c Mon Sep 17 00:00:00 2001 From: RPRX <63339210+RPRX@users.noreply.github.com> Date: Wed, 13 Mar 2024 22:39:24 +0000 Subject: [PATCH] Add ConnRF to make HTTPUpgrade 0-RTT https://github.com/XTLS/Xray-core/issues/3128#issuecomment-1991809113 --- transport/internet/httpupgrade/dialer.go | 36 ++++++++++++++++-------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/transport/internet/httpupgrade/dialer.go b/transport/internet/httpupgrade/dialer.go index 6b5435b5..159dcb98 100644 --- a/transport/internet/httpupgrade/dialer.go +++ b/transport/internet/httpupgrade/dialer.go @@ -15,6 +15,29 @@ import ( "github.com/xtls/xray-core/transport/internet/tls" ) +type ConnRF struct { + net.Conn + Req *http.Request + First bool +} + +func (c *ConnRF) Read(b []byte) (int, error) { + if c.First { + c.First = false + // TODO The bufio usage here is unreliable + resp, err := http.ReadResponse(bufio.NewReader(c.Conn), c.Req) // nolint:bodyclose + if err != nil { + return 0, err + } + if resp.Status != "101 Switching Protocols" || + strings.ToLower(resp.Header.Get("Upgrade")) != "websocket" || + strings.ToLower(resp.Header.Get("Connection")) != "upgrade" { + return 0, newError("unrecognized reply") + } + } + return c.Conn.Read(b) +} + func dialhttpUpgrade(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (net.Conn, error) { transportConfiguration := streamSettings.ProtocolSettings.(*Config) @@ -58,18 +81,7 @@ func dialhttpUpgrade(ctx context.Context, dest net.Destination, streamSettings * return nil, err } - // TODO The bufio usage here is unreliable - resp, err := http.ReadResponse(bufio.NewReader(conn), req) // nolint:bodyclose - if err != nil { - return nil, err - } - - if resp.Status == "101 Switching Protocols" && - strings.ToLower(resp.Header.Get("Upgrade")) == "websocket" && - strings.ToLower(resp.Header.Get("Connection")) == "upgrade" { - return conn, nil - } - return nil, newError("unrecognized reply") + return &ConnRF{Conn: conn, Req: req, First: true}, nil } func dial(ctx context.Context, dest net.Destination, streamSettings *internet.MemoryStreamConfig) (stat.Connection, error) {