From dd06c6964bec727f0c07c70e1920847319a9ad0d Mon Sep 17 00:00:00 2001 From: Ivan Zuev Date: Mon, 18 Aug 2025 22:34:08 +0300 Subject: [PATCH 1/2] fix: avoid data race when closing body --- response.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/response.go b/response.go index 94c29a0..ee608c3 100644 --- a/response.go +++ b/response.go @@ -741,6 +741,7 @@ type lenReadSeeker interface { type dummyReadCloser struct { orig any // string or []byte body lenReadSeeker // instanciated on demand from orig + mu sync.Mutex } // copy returns a new instance resetting d.body to nil. @@ -771,6 +772,9 @@ func (d *dummyReadCloser) Read(p []byte) (n int, err error) { } func (d *dummyReadCloser) Close() error { + d.mu.Lock() + defer d.mu.Unlock() + d.setup() d.body.Seek(0, io.SeekEnd) //nolint: errcheck return nil From 1ab99279e0faea747e3fd51834731cacad9b1b1b Mon Sep 17 00:00:00 2001 From: Ivan Zuev Date: Mon, 18 Aug 2025 23:19:13 +0300 Subject: [PATCH 2/2] fix: protect all body-related methods with mutext --- response.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/response.go b/response.go index ee608c3..f3b6c80 100644 --- a/response.go +++ b/response.go @@ -740,8 +740,8 @@ type lenReadSeeker interface { type dummyReadCloser struct { orig any // string or []byte + mu sync.Mutex // protects operations over body body lenReadSeeker // instanciated on demand from orig - mu sync.Mutex } // copy returns a new instance resetting d.body to nil. @@ -767,6 +767,9 @@ func (d *dummyReadCloser) setup() { } func (d *dummyReadCloser) Read(p []byte) (n int, err error) { + d.mu.Lock() + defer d.mu.Unlock() + d.setup() return d.body.Read(p) } @@ -781,6 +784,9 @@ func (d *dummyReadCloser) Close() error { } func (d *dummyReadCloser) Len() int { + d.mu.Lock() + defer d.mu.Unlock() + d.setup() return d.body.Len() }