Commit 44652426 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

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

Fixes #8724

LGTM=adg
R=adg
CC=golang-codereviews
https://golang.org/cl/148040043
parent e6f21be3
......@@ -77,3 +77,7 @@ var DefaultUserAgent = defaultUserAgent
func SetPendingDialHooks(before, after func()) {
prePendingDial, postPendingDial = before, after
}
var ExportServerNewConn = (*Server).newConn
var ExportCloseWriteAndWait = (*conn).closeWriteAndWait
......@@ -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()
......
......@@ -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)
......
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