diff --git a/graceful/graceful.go b/graceful/graceful.go index 255f24c..19384ff 100644 --- a/graceful/graceful.go +++ b/graceful/graceful.go @@ -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 +} diff --git a/graceful/server.go b/graceful/server.go new file mode 100644 index 0000000..ab69236 --- /dev/null +++ b/graceful/server.go @@ -0,0 +1,82 @@ +package graceful + +import ( + "crypto/tls" + "net" + "net/http" +) + +// 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) +} diff --git a/graceful/signal.go b/graceful/signal.go index 6bd3d84..2787476 100644 --- a/graceful/signal.go +++ b/graceful/signal.go @@ -1,7 +1,6 @@ package graceful import ( - "net" "os" "os/signal" "sync" @@ -117,29 +116,3 @@ func waitForSignal() { func Wait() { <-wait } - -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 -}