From 77f98eba0978cbcb425e2f8ec3cec86bd5aa8444 Mon Sep 17 00:00:00 2001 From: ivolfram <45515661+dudkin-2005@users.noreply.github.com> Date: Wed, 26 Aug 2026 22:19:41 +0300 Subject: [PATCH] XHTTP client: Fix a race condition and a data race (#6665) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/XTLS/Xray-core/pull/6665#issuecomment-5429028477 --------- Co-authored-by: 风扇滑翔翼 --- transport/internet/splithttp/client.go | 11 ++++++----- transport/internet/splithttp/dialer.go | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/transport/internet/splithttp/client.go b/transport/internet/splithttp/client.go index 0e3a73f2e..a46c2b8ca 100644 --- a/transport/internet/splithttp/client.go +++ b/transport/internet/splithttp/client.go @@ -8,6 +8,7 @@ import ( "net/http" "net/http/httptrace" "sync" + "sync/atomic" "github.com/apernet/quic-go/http3" "github.com/xtls/xray-core/common" @@ -32,7 +33,7 @@ type DialerClient interface { type DefaultDialerClient struct { transportConfig *Config client *http.Client - closed bool + closed atomic.Bool httpVersion string // pool of net.Conn, created using dialUploadConn uploadRawPool *sync.Pool @@ -40,7 +41,7 @@ type DefaultDialerClient struct { } func (c *DefaultDialerClient) IsClosed() bool { - return c.closed + return c.closed.Load() } func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, sessionId string, body io.Reader, uploadOnly bool) (wrc io.ReadCloser, remoteAddr, localAddr net.Addr, err error) { @@ -72,7 +73,7 @@ func (c *DefaultDialerClient) OpenStream(ctx context.Context, url string, sessio resp, err := c.client.Do(req) if err != nil { if !uploadOnly { // stream-down is enough - c.closed = true + c.closed.Store(true) errors.LogInfoInner(ctx, err, "failed to "+method+" "+url) } gotConn.Close() @@ -108,7 +109,7 @@ func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, sessio if c.httpVersion != "1.1" { resp, err := c.client.Do(req) if err != nil { - c.closed = true + c.closed.Store(true) return err } @@ -148,7 +149,7 @@ func (c *DefaultDialerClient) PostPacket(ctx context.Context, url string, sessio if h1UploadConn.UnreadedResponsesCount > 0 { resp, err := http.ReadResponse(h1UploadConn.RespBufReader, req) if err != nil { - c.closed = true + c.closed.Store(true) return fmt.Errorf("error while reading response: %s", err.Error()) } io.Copy(io.Discard, resp.Body) diff --git a/transport/internet/splithttp/dialer.go b/transport/internet/splithttp/dialer.go index 817d93552..d2908aa1b 100644 --- a/transport/internet/splithttp/dialer.go +++ b/transport/internet/splithttp/dialer.go @@ -595,11 +595,12 @@ func (w uploadWriter) Write(b []byte) (int, error) { var writed int for _, buff := range buffer.MultiBuffer { + n := int(buff.Len()) err := w.WriteMultiBuffer(buf.MultiBuffer{buff}) if err != nil { return writed, err } - writed += int(buff.Len()) + writed += n } return writed, nil }