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 ...@@ -77,3 +77,7 @@ var DefaultUserAgent = defaultUserAgent
func SetPendingDialHooks(before, after func()) { func SetPendingDialHooks(before, after func()) {
prePendingDial, postPendingDial = before, after prePendingDial, postPendingDial = before, after
} }
var ExportServerNewConn = (*Server).newConn
var ExportCloseWriteAndWait = (*conn).closeWriteAndWait
...@@ -2607,6 +2607,29 @@ func TestServerConnStateNew(t *testing.T) { ...@@ -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) { func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.StopTimer() b.StopTimer()
......
...@@ -1064,15 +1064,21 @@ func (c *conn) close() { ...@@ -1064,15 +1064,21 @@ func (c *conn) close() {
// This timeout is somewhat arbitrary (~latency around the planet). // This timeout is somewhat arbitrary (~latency around the planet).
const rstAvoidanceDelay = 500 * time.Millisecond 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 // closeWrite flushes any outstanding data and sends a FIN packet (if
// client is connected via TCP), signalling that we're done. We then // 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. // subsequent RST.
// //
// See http://golang.org/issue/3595 // See http://golang.org/issue/3595
func (c *conn) closeWriteAndWait() { func (c *conn) closeWriteAndWait() {
c.finalFlush() c.finalFlush()
if tcp, ok := c.rwc.(*net.TCPConn); ok { if tcp, ok := c.rwc.(closeWriter); ok {
tcp.CloseWrite() tcp.CloseWrite()
} }
time.Sleep(rstAvoidanceDelay) 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