pip compatible server to serve Python packages out of GitHub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

136 lines
4.2 KiB

/*
Package graceful implements graceful shutdown for HTTP servers by closing idle
connections after receiving a signal. By default, this package listens for
interrupts (i.e., SIGINT), but when it detects that it is running under Einhorn
it will additionally listen for SIGUSR2 as well, giving your application
automatic support for graceful upgrades.
It's worth mentioning explicitly that this package is a hack to shim graceful
shutdown behavior into the net/http package provided in Go 1.2. It was written
by carefully reading the sequence of function calls net/http happened to use as
of this writing and finding enough surface area with which to add appropriate
behavior. There's a very good chance that this package will cease to work in
future versions of Go, but with any luck the standard library will add support
of its own by then (https://code.google.com/p/go/issues/detail?id=4674).
If you're interested in figuring out how this package works, we suggest you read
the documentation for WrapConn() and net.go.
*/
package graceful
import (
"crypto/tls"
"net"
"net/http"
"time"
)
// Exactly like net/http's Server. In fact, it *is* a net/http Server, just with
// different method implementations
type Server http.Server
// About 200 years, also known as "forever"
const forever time.Duration = 200 * 365 * 24 * time.Hour
/*
You might notice that these methods look awfully similar to the methods of the
same name from the go standard library--that's because they were stolen from
there! If go were more like, say, Ruby, it'd actually be possible to shim just
the Serve() method, since we can do everything we want from there. However, it's
not possible to get the other methods which call Serve() (ListenAndServe(), say)
to call your shimmed copy--they always call the original.
Since I couldn't come up with a better idea, I just copy-and-pasted both
ListenAndServe and ListenAndServeTLS here more-or-less verbatim. "Oh well!"
*/
// Behaves exactly like the net/http function of the same name.
func (srv *Server) Serve(l net.Listener) (err error) {
go func() {
<-kill
l.Close()
}()
l = WrapListener(l)
// Spawn a shadow http.Server to do the actual servering. We do this
// because we need to sketch on some of the parameters you passed in,
// and it's nice to keep our sketching to ourselves.
shadow := *(*http.Server)(srv)
if shadow.ReadTimeout == 0 {
shadow.ReadTimeout = forever
}
shadow.Handler = Middleware(shadow.Handler)
err = shadow.Serve(l)
// We expect an error when we close the listener, so we indiscriminately
// swallow Serve errors when we're in a shutdown state.
select {
case <-kill:
return nil
default:
return err
}
}
// Behaves exactly like the net/http function of the same name.
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)
}
// Behaves exactly like the net/http function of the same name.
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
addr := srv.Addr
if addr == "" {
addr = ":https"
}
config := &tls.Config{}
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)
}
// 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()
}
// Behaves exactly like the net/http function of the same name.
func ListenAndServeTLS(addr, certfile, keyfile string, handler http.Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServeTLS(certfile, keyfile)
}
// 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)
}