|
|
|
@ -8,88 +8,12 @@ automatic support for graceful restarts/code upgrades. |
|
|
|
package graceful |
|
|
|
|
|
|
|
import ( |
|
|
|
"crypto/tls" |
|
|
|
"net" |
|
|
|
"net/http" |
|
|
|
"sync/atomic" |
|
|
|
|
|
|
|
"github.com/zenazn/goji/graceful/listener" |
|
|
|
) |
|
|
|
|
|
|
|
// Most of the code here is lifted straight from net/http
|
|
|
|
|
|
|
|
// Type Server is exactly the same as an http.Server, but provides more graceful
|
|
|
|
// implementations of its methods.
|
|
|
|
type Server http.Server |
|
|
|
|
|
|
|
func (srv *Server) ListenAndServe() error { |
|
|
|
addr := srv.Addr |
|
|
|
if addr == "" { |
|
|
|
addr = ":http" |
|
|
|
} |
|
|
|
l, e := net.Listen("tcp", addr) |
|
|
|
if e != nil { |
|
|
|
return e |
|
|
|
} |
|
|
|
return srv.Serve(l) |
|
|
|
} |
|
|
|
|
|
|
|
// Unlike the method of the same name on http.Server, this function defaults to
|
|
|
|
// enforcing TLS 1.0 or higher in order to address the POODLE vulnerability.
|
|
|
|
// Users who wish to enable SSLv3 must do so by supplying a TLSConfig
|
|
|
|
// explicitly.
|
|
|
|
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { |
|
|
|
addr := srv.Addr |
|
|
|
if addr == "" { |
|
|
|
addr = ":https" |
|
|
|
} |
|
|
|
config := &tls.Config{ |
|
|
|
MinVersion: tls.VersionTLS10, |
|
|
|
} |
|
|
|
if srv.TLSConfig != nil { |
|
|
|
*config = *srv.TLSConfig |
|
|
|
} |
|
|
|
if config.NextProtos == nil { |
|
|
|
config.NextProtos = []string{"http/1.1"} |
|
|
|
} |
|
|
|
|
|
|
|
var err error |
|
|
|
config.Certificates = make([]tls.Certificate, 1) |
|
|
|
config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
conn, err := net.Listen("tcp", addr) |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
tlsListener := tls.NewListener(conn, config) |
|
|
|
return srv.Serve(tlsListener) |
|
|
|
} |
|
|
|
|
|
|
|
// ListenAndServe behaves exactly like the net/http function of the same name.
|
|
|
|
func ListenAndServe(addr string, handler http.Handler) error { |
|
|
|
server := &Server{Addr: addr, Handler: handler} |
|
|
|
return server.ListenAndServe() |
|
|
|
} |
|
|
|
|
|
|
|
// ListenAndServeTLS behaves almost exactly like the net/http function of the
|
|
|
|
// same name. Unlike net/http, however, this function defaults to enforcing TLS
|
|
|
|
// 1.0 or higher in order to address the POODLE vulnerability. Users who wish to
|
|
|
|
// enable SSLv3 must do so by explicitly instantiating a server with an
|
|
|
|
// appropriately configured TLSConfig property.
|
|
|
|
func ListenAndServeTLS(addr, certfile, keyfile string, handler http.Handler) error { |
|
|
|
server := &Server{Addr: addr, Handler: handler} |
|
|
|
return server.ListenAndServeTLS(certfile, keyfile) |
|
|
|
} |
|
|
|
|
|
|
|
// Serve behaves exactly like the net/http function of the same name.
|
|
|
|
func Serve(l net.Listener, handler http.Handler) error { |
|
|
|
server := &Server{Handler: handler} |
|
|
|
return server.Serve(l) |
|
|
|
} |
|
|
|
|
|
|
|
// WrapListener wraps an arbitrary net.Listener for use with graceful shutdowns.
|
|
|
|
// In the background, it uses the listener sub-package to Wrap the listener in
|
|
|
|
// Deadline mode. If another mode of operation is desired, you should call
|
|
|
|
@ -105,3 +29,29 @@ func WrapListener(l net.Listener) net.Listener { |
|
|
|
appendListener(lt) |
|
|
|
return lt |
|
|
|
} |
|
|
|
|
|
|
|
func appendListener(l *listener.T) { |
|
|
|
mu.Lock() |
|
|
|
defer mu.Unlock() |
|
|
|
|
|
|
|
listeners = append(listeners, l) |
|
|
|
} |
|
|
|
|
|
|
|
const errClosing = "use of closed network connection" |
|
|
|
|
|
|
|
// During graceful shutdown, calls to Accept will start returning errors. This
|
|
|
|
// is inconvenient, since we know these sorts of errors are peaceful, so we
|
|
|
|
// silently swallow them.
|
|
|
|
func peacefulError(err error) error { |
|
|
|
if atomic.LoadInt32(&closing) == 0 { |
|
|
|
return err |
|
|
|
} |
|
|
|
// Unfortunately Go doesn't really give us a better way to select errors
|
|
|
|
// than this, so *shrug*.
|
|
|
|
if oe, ok := err.(*net.OpError); ok { |
|
|
|
if oe.Op == "accept" && oe.Err.Error() == errClosing { |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
return err |
|
|
|
} |