Skip to content

Commit d91d832

Browse files
Bryan C. Millsgopherbot
Bryan C. Mills
authored andcommitted
net/http: avoid leaking writer goroutines in tests
In TestTransportPrefersResponseOverWriteError and TestMaxBytesHandler, the server may respond to an incoming request without ever reading the request body. The client's Do method will return as soon as the server's response headers are read, but the Transport will remain active until it notices that the server has closed the connection, which may be arbitrarily later. When the server has closed the connection, it will call the Close method on the request body (if it has such a method). So we can use that method to find out when the Transport is close enough to done for the test to complete without interfering too much with other tests. For #57612. For #59526. Change-Id: Iddc7a3b7b09429113ad76ccc1c090ebc9e1835a1 Reviewed-on: https://go-review.googlesource.com/c/go/+/483895 Run-TryBot: Bryan Mills <[email protected]> Commit-Queue: Bryan Mills <[email protected]> Auto-Submit: Bryan Mills <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent b7428b7 commit d91d832

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

src/net/http/serve_test.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6546,9 +6546,30 @@ func testMaxBytesHandler(t *testing.T, mode testMode, maxSize, requestSize int64
65466546
defer ts.Close()
65476547

65486548
c := ts.Client()
6549+
6550+
body := strings.Repeat("a", int(requestSize))
6551+
var wg sync.WaitGroup
6552+
defer wg.Wait()
6553+
getBody := func() (io.ReadCloser, error) {
6554+
wg.Add(1)
6555+
body := &wgReadCloser{
6556+
Reader: strings.NewReader(body),
6557+
wg: &wg,
6558+
}
6559+
return body, nil
6560+
}
6561+
reqBody, _ := getBody()
6562+
req, err := NewRequest("POST", ts.URL, reqBody)
6563+
if err != nil {
6564+
reqBody.Close()
6565+
t.Fatal(err)
6566+
}
6567+
req.ContentLength = int64(len(body))
6568+
req.GetBody = getBody
6569+
req.Header.Set("Content-Type", "text/plain")
6570+
65496571
var buf strings.Builder
6550-
body := strings.NewReader(strings.Repeat("a", int(requestSize)))
6551-
res, err := c.Post(ts.URL, "text/plain", body)
6572+
res, err := c.Do(req)
65526573
if err != nil {
65536574
t.Errorf("unexpected connection error: %v", err)
65546575
} else {

src/net/http/transport_test.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4250,6 +4250,21 @@ func testTransportFlushesRequestHeader(t *testing.T, mode testMode) {
42504250
<-gotRes
42514251
}
42524252

4253+
type wgReadCloser struct {
4254+
io.Reader
4255+
wg *sync.WaitGroup
4256+
closed bool
4257+
}
4258+
4259+
func (c *wgReadCloser) Close() error {
4260+
if c.closed {
4261+
return net.ErrClosed
4262+
}
4263+
c.closed = true
4264+
c.wg.Done()
4265+
return nil
4266+
}
4267+
42534268
// Issue 11745.
42544269
func TestTransportPrefersResponseOverWriteError(t *testing.T) {
42554270
run(t, testTransportPrefersResponseOverWriteError)
@@ -4271,12 +4286,29 @@ func testTransportPrefersResponseOverWriteError(t *testing.T, mode testMode) {
42714286

42724287
fail := 0
42734288
count := 100
4289+
42744290
bigBody := strings.Repeat("a", contentLengthLimit*2)
4291+
var wg sync.WaitGroup
4292+
defer wg.Wait()
4293+
getBody := func() (io.ReadCloser, error) {
4294+
wg.Add(1)
4295+
body := &wgReadCloser{
4296+
Reader: strings.NewReader(bigBody),
4297+
wg: &wg,
4298+
}
4299+
return body, nil
4300+
}
4301+
42754302
for i := 0; i < count; i++ {
4276-
req, err := NewRequest("PUT", ts.URL, strings.NewReader(bigBody))
4303+
reqBody, _ := getBody()
4304+
req, err := NewRequest("PUT", ts.URL, reqBody)
42774305
if err != nil {
4306+
reqBody.Close()
42784307
t.Fatal(err)
42794308
}
4309+
req.ContentLength = int64(len(bigBody))
4310+
req.GetBody = getBody
4311+
42804312
resp, err := c.Do(req)
42814313
if err != nil {
42824314
fail++

0 commit comments

Comments
 (0)