net/http: check for CloseWrite interface, not TCPConn implementation

Fixes #8724

LGTM=adg
R=adg
CC=golang-codereviews
https://golang.org/cl/148040043
This commit is contained in:
Brad Fitzpatrick 2014-09-24 17:01:54 -07:00
parent e6f21be3f4
commit 446524269e
3 changed files with 35 additions and 2 deletions

View File

@ -77,3 +77,7 @@ var DefaultUserAgent = defaultUserAgent
func SetPendingDialHooks(before, after func()) {
prePendingDial, postPendingDial = before, after
}
var ExportServerNewConn = (*Server).newConn
var ExportCloseWriteAndWait = (*conn).closeWriteAndWait

View File

@ -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()

View File

@ -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)