From d6bce32a3607222075734bf4363ca3fea02ea1e5 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 9 Jan 2014 15:05:09 -0800 Subject: [PATCH] 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 --- src/pkg/net/http/server.go | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go index 7ebd8575f3..a56aa3df31 100644 --- a/src/pkg/net/http/server.go +++ b/src/pkg/net/http/server.go @@ -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 @@ -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) } @@ -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{} -- 2.48.1