Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http: Transport leaks goroutines when request.ContentLength is explicitly short #4531

gopherbot opened this issue Dec 12, 2012 · 8 comments


Copy link

@gopherbot gopherbot commented Dec 12, 2012

by zarcardfly:

Before filing a bug, please check whether it has been fixed since the
latest release. Search the issue tracker and check that you're running the
latest version of Go:

Run "go version" and compare against  If a newer version of Go exists,
install it and retry what you did to reproduce the problem.


What steps will reproduce the problem?
If possible, include a link to a program on
  1. sample code:
  2. I call http.Client.Do with a http.Request whose ContentLength is unequal to the posted body's length.
  3. http.Client.Do failed as assume, but the readLoop() goruntine is still running, it hang up at : 558            rc := <-pc.reqch
  4. I check the net/http/transport.go code:
   670      pc.numExpectedResponses++
   673      err = req.Request.write(, pc.isProxy, req.extra)
   674      if err != nil {
   675          pc.close()
   676          return
   677      }
   680      ch := make(chan responseAndError, 1)
   681      pc.reqch <- requestAndChan{req.Request, ch, requestedGzip}
   682      re := <-ch
   684      pc.numExpectedResponses--
  when 673 failed, the function returned without dec numExpectedResponses.
   544          pb, err :=
   547          if pc.numExpectedResponses == 0 {
   548              pc.closeLocked()
   550              if len(pb) > 0 {
   551                  log.Printf("Unsolicited response received on idle HTTP channel starting with %q; err=%v",
   552                      string(pb), err)
   553              }
   554              return
   555          }
   558          rc := <-pc.reqch
  And the result of line 547 is false, and then the goroutine block in 558.

What is the expected output?
  the number of goroutine is a small number, such as 5.

What do you see instead?
  the number of goroutine is more than 20.

Which compiler are you using (5g, 6g, 8g, gccgo)?

Which operating system are you using?
  mac os x 10.8

Which version are you using?  (run 'go version')
  I found it in an old version go, but I check the '', it still being there.

Please provide any additional information below.
 Tell me if I miss something, thank you, and sorry for my poor english.
Copy link

@bradfitz bradfitz commented Dec 14, 2012

Comment 1:

You said:
> but I check the '', it still being
But that is not the latest code.
Much has changed in this code.
Please try to reproduce with the tip version. "hg update default; cd src; ./all.bash",

Status changed to WaitingForReply.

Copy link

@gopherbot gopherbot commented Dec 15, 2012

Comment 2 by zarcardfly:

hi, I try as your recommended:
    hg clone -u release
    cd go
    hg update default
    cd src
I checked the code version:
~/hg/go $ hg summary
parent: 15135:7e135713451d tip
 src: gofmt -w -s
branch: default
commit: 1 modified
update: (current)
And I run my program ‘’, the problem still exists.
The number of goroutines is more than 40 now, and the connections are 'leaking' too.
I checked the code and debuged with gdb, here is my preliminary analysis:
There are two goroutines for a new created persistConn.
The reader goroutine is stuck in readLoop():559:
558         for alive {
559                 pb, err :=
The writer goroutine is stuck in writeLoop():661:
660         for {
661                 select {
662                 case wr := <-pc.writech:
In my code, line 667 returned a none nil err 'http: Request.ContentLength=3 with Body
length 5', the 'pc' was maked broken, and was't flushed, so line 559 in reader
goroutine would never returned. The writer goroutine go back to line 661, and stuck
667                         err := wr.req.Request.write(, pc.isProxy, wr.req.extra)
668                         if err == nil {
669                                 err =
670                         }
671                         if err != nil {
672                                 pc.markBroken()
673                         }       
674                <- err
Because the persistConn was new created or picked from Transport.idleConn, no one could
obtain it again, it was 'leaked', with two goroutines and one connection.

Copy link

@bradfitz bradfitz commented Dec 17, 2012

Comment 3:

Thanks for confirming with tip.
I've changed the summary of this bug.

Owner changed to @bradfitz.

Status changed to Accepted.

Copy link

@bradfitz bradfitz commented Dec 17, 2012

Comment 4:

Fix out for review:

Status changed to Started.

Copy link

@bradfitz bradfitz commented Dec 17, 2012

Comment 5:

This issue was closed by revision 7c3577e.

Status changed to Fixed.

Copy link

@gopherbot gopherbot commented Mar 25, 2014

Comment 6 by ibilicc:

6842 @ 0x41a716 0x4080d4 0x407d22 0x488021 0x41a8e0
#   0x4080d4    selectgo+0x384              /usr/local/go/src/pkg/runtime/chan.c:996
#   0x407d22    runtime.selectgo+0x12           /usr/local/go/src/pkg/runtime/chan.c:840
#   0x488021    net/http.(*persistConn).writeLoop+0x271 /usr/local/go/src/pkg/net/http/transport.go:791
6811 @ 0x41a716 0x4072d2 0x407718 0x4879cf 0x41a8e0
#   0x4879cf    net/http.(*persistConn).readLoop+0x68f  /usr/local/go/src/pkg/net/http/transport.go:778
when my program runs several hours, there're thousands writeLoop and readLoop goroutings
dangling around, i think somewhere someplace transport still leaking...

Copy link

@bradfitz bradfitz commented Mar 25, 2014

Comment 7:

Old bugs are not the right place for discussion. Please ask on golang-nuts and I or
somebody else will answer your question.

Copy link

@gopherbot gopherbot commented Mar 26, 2014

Comment 8 by ibilicc:

I've posted a topic on go-nuts!topic/golang-nuts/FnJZ9iZ0i_g, thanks for your reply.

@rsc rsc added this to the Go1.1 milestone Apr 14, 2015
@rsc rsc removed the go1.1 label Apr 14, 2015
@golang golang locked and limited conversation to collaborators Jun 24, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet

No branches or pull requests

3 participants