Commit 61ed384a authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: make CloseNotifier channel buffered to not leak goroutines

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/8911044
parent 994c486a
...@@ -1370,6 +1370,7 @@ func TestContentLengthZero(t *testing.T) { ...@@ -1370,6 +1370,7 @@ func TestContentLengthZero(t *testing.T) {
} }
func TestCloseNotifier(t *testing.T) { func TestCloseNotifier(t *testing.T) {
defer afterTest(t)
gotReq := make(chan bool, 1) gotReq := make(chan bool, 1)
sawClose := make(chan bool, 1) sawClose := make(chan bool, 1)
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
...@@ -1405,6 +1406,31 @@ For: ...@@ -1405,6 +1406,31 @@ For:
ts.Close() ts.Close()
} }
func TestCloseNotifierChanLeak(t *testing.T) {
defer afterTest(t)
req := []byte(strings.Replace(`GET / HTTP/1.0
Host: golang.org
`, "\n", "\r\n", -1))
for i := 0; i < 20; i++ {
var output bytes.Buffer
conn := &rwTestConn{
Reader: bytes.NewReader(req),
Writer: &output,
closec: make(chan bool, 1),
}
ln := &oneConnListener{conn: conn}
handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
// Ignore the return value and never read from
// it, testing that we don't leak goroutines
// on the sending side:
_ = rw.(CloseNotifier).CloseNotify()
})
go Serve(ln, handler)
<-conn.closec
}
}
func TestOptions(t *testing.T) { func TestOptions(t *testing.T) {
uric := make(chan string, 2) // only expect 1, but leave space for 2 uric := make(chan string, 2) // only expect 1, but leave space for 2
mux := NewServeMux() mux := NewServeMux()
......
...@@ -146,7 +146,7 @@ func (c *conn) closeNotify() <-chan bool { ...@@ -146,7 +146,7 @@ func (c *conn) closeNotify() <-chan bool {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
if c.closeNotifyc == nil { if c.closeNotifyc == nil {
c.closeNotifyc = make(chan bool) c.closeNotifyc = make(chan bool, 1)
if c.hijackedv { if c.hijackedv {
// to obey the function signature, even though // to obey the function signature, even though
// it'll never receive a value. // it'll never receive a value.
......
...@@ -76,6 +76,7 @@ func afterTest(t *testing.T) { ...@@ -76,6 +76,7 @@ func afterTest(t *testing.T) {
"created by net/http/httptest.(*Server).Start": "an httptest.Server", "created by net/http/httptest.(*Server).Start": "an httptest.Server",
"timeoutHandler": "a TimeoutHandler", "timeoutHandler": "a TimeoutHandler",
"net.(*netFD).connect(": "a timing out dial", "net.(*netFD).connect(": "a timing out dial",
").noteClientGone(": "a closenotifier sender",
} }
var stacks string var stacks string
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment