Commit d6bce32a authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: use TCP keep-alives for ListenAndServe and ListenAndServeTLS

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
parent 8da8b376
...@@ -1608,11 +1608,11 @@ func (srv *Server) ListenAndServe() error { ...@@ -1608,11 +1608,11 @@ func (srv *Server) ListenAndServe() error {
if addr == "" { if addr == "" {
addr = ":http" addr = ":http"
} }
l, e := net.Listen("tcp", addr) ln, err := net.Listen("tcp", addr)
if e != nil { if err != nil {
return e return err
} }
return srv.Serve(l) return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
} }
// Serve accepts incoming connections on the Listener l, creating a // Serve accepts incoming connections on the Listener l, creating a
...@@ -1742,12 +1742,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { ...@@ -1742,12 +1742,12 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
return err return err
} }
conn, err := net.Listen("tcp", addr) ln, err := net.Listen("tcp", addr)
if err != nil { if err != nil {
return err return err
} }
tlsListener := tls.NewListener(conn, config) tlsListener := tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, config)
return srv.Serve(tlsListener) return srv.Serve(tlsListener)
} }
...@@ -1837,6 +1837,24 @@ func (tw *timeoutWriter) WriteHeader(code int) { ...@@ -1837,6 +1837,24 @@ func (tw *timeoutWriter) WriteHeader(code int) {
tw.w.WriteHeader(code) 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. // globalOptionsHandler responds to "OPTIONS *" requests.
type globalOptionsHandler struct{} type globalOptionsHandler struct{}
......
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