Skip to content

Commit

Permalink
net/http: use TCP keep-alives for ListenAndServe and ListenAndServeTLS
Browse files Browse the repository at this point in the history
Our default behavior for the common cases shouldn't lead to
leaked TCP connections (e.g. from people closing laptops) when
their Go servers are exposed to the open Internet without a
proxy in front.

Too many users on golang-nuts have learned this the hard way.

No API change. Only ListenAndServe and ListenAndServeTLS are
updated.

R=golang-codereviews, cespare, gobot, rsc, minux.ma
CC=golang-codereviews
https://golang.org/cl/48300043
  • Loading branch information
bradfitz committed Jan 9, 2014
1 parent 8da8b37 commit d6bce32
Showing 1 changed file with 24 additions and 6 deletions.
30 changes: 24 additions & 6 deletions src/pkg/net/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1608,11 +1608,11 @@ func (srv *Server) ListenAndServe() error {
if addr == "" {
addr = ":http"
}
l, e := net.Listen("tcp", addr)
if e != nil {
return e
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}
return srv.Serve(l)
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}

// Serve accepts incoming connections on the Listener l, creating a
Expand Down Expand Up @@ -1742,12 +1742,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
return err
}

conn, err := net.Listen("tcp", addr)
ln, err := net.Listen("tcp", addr)
if err != nil {
return err
}

tlsListener := tls.NewListener(conn, config)
tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
return srv.Serve(tlsListener)
}

Expand Down Expand Up @@ -1837,6 +1837,24 @@ func (tw *timeoutWriter) WriteHeader(code int) {
tw.w.WriteHeader(code)
}

// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
// connections. It's used by ListenAndServe and ListenAndServeTLS so
// dead TCP connections (e.g. closing laptop mid-download) eventually
// go away.
type tcpKeepAliveListener struct {
*net.TCPListener
}

func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
tc, err := ln.AcceptTCP()
if err != nil {
return
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
return tc, nil
}

// globalOptionsHandler responds to "OPTIONS *" requests.
type globalOptionsHandler struct{}

Expand Down

0 comments on commit d6bce32

Please sign in to comment.