fix(client): avoid dst aliasing after timeout

This commit is contained in:
Erik Dubbelboer
2026-06-13 05:47:54 +02:00
parent c7e642b843
commit 3aa09fee51
2 changed files with 52 additions and 1 deletions
+2 -1
View File
@@ -1093,9 +1093,10 @@ func clientGetURLDeadline(dst []byte, url string, deadline time.Time, c clientDo
go func() {
req := AcquireRequest()
statusCodeCopy, bodyCopy, errCopy := doRequestFollowRedirectsBuffer(req, dst, url, c)
statusCodeCopy, bodyCopy, errCopy := doRequestFollowRedirectsBuffer(req, nil, url, c)
mu.Lock()
if !timedout {
bodyCopy = append(dst[:0], bodyCopy...)
ch <- clientURLResponse{
statusCode: statusCodeCopy,
body: bodyCopy,
+50
View File
@@ -2290,6 +2290,56 @@ func TestClientGetTimeoutError(t *testing.T) {
testClientGetTimeoutError(t, c, 100)
}
func TestClientGetURLDeadlineDoesNotMutateDstAfterTimeout(t *testing.T) {
t.Parallel()
d := &delayedBodyDoer{
unblock: make(chan struct{}),
done: make(chan struct{}),
body: "mutated!",
}
dst := []byte("original")
statusCode, body, err := clientGetURLDeadline(dst, "http://example.com/", time.Now().Add(time.Millisecond), d)
if err != ErrTimeout {
t.Fatalf("unexpected error: %v. Expecting %v", err, ErrTimeout)
}
if statusCode != 0 {
t.Fatalf("unexpected status code: %d. Expecting 0", statusCode)
}
if string(body) != "original" {
t.Fatalf("unexpected timeout body %q. Expecting %q", body, "original")
}
close(d.unblock)
select {
case <-d.done:
case <-time.After(time.Second):
t.Fatal("timed out waiting for background request to finish")
}
if string(dst) != "original" {
t.Fatalf("dst was mutated after timeout: %q. Expecting %q", dst, "original")
}
if string(body) != "original" {
t.Fatalf("returned body was mutated after timeout: %q. Expecting %q", body, "original")
}
}
type delayedBodyDoer struct {
unblock chan struct{}
done chan struct{}
body string
}
func (d *delayedBodyDoer) Do(req *Request, resp *Response) error {
<-d.unblock
resp.SetStatusCode(StatusOK)
resp.SetBodyString(d.body)
close(d.done)
return nil
}
func TestClientGetTimeoutErrorConcurrent(t *testing.T) {
t.Parallel()