Skip to content

Commit 7124ee5

Browse files
rcrowleybradfitz
authored andcommitted
net/http: ensure ConnState for StateNew fires before Server.Serve returns
The addition of Server.ConnState provides all the necessary hooks to stop a Server gracefully, but StateNew previously could fire concurrently with Serve exiting (as it does when its net.Listener is closed). This previously meant one couldn't use a WaitGroup incremented in the StateNew hook along with calling Wait after Serve. Now you can. Update #4674 LGTM=bradfitz R=bradfitz CC=golang-codereviews https://golang.org/cl/70410044
1 parent 9f0bba4 commit 7124ee5

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

src/pkg/net/http/serve_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,27 @@ func TestServerKeepAlivesEnabled(t *testing.T) {
23722372
}
23732373
}
23742374

2375+
func TestServerConnStateNew(t *testing.T) {
2376+
sawNew := false // if the test is buggy, we'll race on this variable.
2377+
srv := &Server{
2378+
ConnState: func(c net.Conn, state ConnState) {
2379+
if state == StateNew {
2380+
sawNew = true // testing that this write isn't racy
2381+
}
2382+
},
2383+
Handler: HandlerFunc(func(w ResponseWriter, r *Request) {}), // irrelevant
2384+
}
2385+
srv.Serve(&oneConnListener{
2386+
conn: &rwTestConn{
2387+
Reader: strings.NewReader("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"),
2388+
Writer: ioutil.Discard,
2389+
},
2390+
})
2391+
if !sawNew { // testing that this read isn't racy
2392+
t.Error("StateNew not seen")
2393+
}
2394+
}
2395+
23752396
func BenchmarkClientServer(b *testing.B) {
23762397
b.ReportAllocs()
23772398
b.StopTimer()

src/pkg/net/http/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,6 @@ func (c *conn) setState(nc net.Conn, state ConnState) {
10901090
// Serve a new connection.
10911091
func (c *conn) serve() {
10921092
origConn := c.rwc // copy it before it's set nil on Close or Hijack
1093-
c.setState(origConn, StateNew)
10941093
defer func() {
10951094
if err := recover(); err != nil {
10961095
const size = 64 << 10
@@ -1722,6 +1721,7 @@ func (srv *Server) Serve(l net.Listener) error {
17221721
if err != nil {
17231722
continue
17241723
}
1724+
c.setState(c.rwc, StateNew) // before Serve can return
17251725
go c.serve()
17261726
}
17271727
}

0 commit comments

Comments
 (0)