From: Brad Fitzpatrick Date: Thu, 25 Sep 2014 00:01:54 +0000 (-0700) Subject: net/http: check for CloseWrite interface, not TCPConn implementation X-Git-Tag: go1.4beta1~299 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=446524269ee152b8053d44117887bc3cc8d5ef9d;p=gostls13.git net/http: check for CloseWrite interface, not TCPConn implementation Fixes #8724 LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/148040043 --- diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go index f8cc835b25..e5bc02afa2 100644 --- a/src/net/http/export_test.go +++ b/src/net/http/export_test.go @@ -77,3 +77,7 @@ var DefaultUserAgent = defaultUserAgent func SetPendingDialHooks(before, after func()) { prePendingDial, postPendingDial = before, after } + +var ExportServerNewConn = (*Server).newConn + +var ExportCloseWriteAndWait = (*conn).closeWriteAndWait diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index ee4f204995..a690ae4699 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -2607,6 +2607,29 @@ func TestServerConnStateNew(t *testing.T) { } } +type closeWriteTestConn struct { + rwTestConn + didCloseWrite bool +} + +func (c *closeWriteTestConn) CloseWrite() error { + c.didCloseWrite = true + return nil +} + +func TestCloseWrite(t *testing.T) { + var srv Server + var testConn closeWriteTestConn + c, err := ExportServerNewConn(&srv, &testConn) + if err != nil { + t.Fatal(err) + } + ExportCloseWriteAndWait(c) + if !testConn.didCloseWrite { + t.Error("didn't see CloseWrite call") + } +} + func BenchmarkClientServer(b *testing.B) { b.ReportAllocs() b.StopTimer() diff --git a/src/net/http/server.go b/src/net/http/server.go index 8f2b777b29..7ad0bcbc20 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -1064,15 +1064,21 @@ func (c *conn) close() { // This timeout is somewhat arbitrary (~latency around the planet). const rstAvoidanceDelay = 500 * time.Millisecond +type closeWriter interface { + CloseWrite() error +} + +var _ closeWriter = (*net.TCPConn)(nil) + // closeWrite flushes any outstanding data and sends a FIN packet (if // client is connected via TCP), signalling that we're done. We then -// pause for a bit, hoping the client processes it before `any +// pause for a bit, hoping the client processes it before any // subsequent RST. // // See http://golang.org/issue/3595 func (c *conn) closeWriteAndWait() { c.finalFlush() - if tcp, ok := c.rwc.(*net.TCPConn); ok { + if tcp, ok := c.rwc.(closeWriter); ok { tcp.CloseWrite() } time.Sleep(rstAvoidanceDelay)