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.
 
 
 

69 lines
1.8 KiB

// +build go1.3
package graceful
import (
"net"
"net/http"
)
func (srv *Server) Serve(l net.Listener) error {
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)
cs := shadow.ConnState
shadow.ConnState = func(nc net.Conn, s http.ConnState) {
if c, ok := nc.(*conn); ok {
// There are a few other states defined, most notably
// StateActive. Unfortunately it doesn't look like it's
// possible to make use of StateActive to implement
// graceful shutdown, since StateActive is set after a
// complete request has been read off the wire with an
// intent to process it. If we were to race a graceful
// shutdown against a connection that was just read off
// the wire (but not yet in StateActive), we would
// accidentally close the connection out from underneath
// an active request.
//
// We already needed to work around this for Go 1.2 by
// shimming out a full net.Conn object, so we can just
// fall back to the old behavior there.
//
// I started a golang-nuts thread about this here:
// https://groups.google.com/forum/#!topic/golang-nuts/Xi8yjBGWfCQ
// I'd be very eager to find a better way to do this, so
// reach out to me if you have any ideas.
switch s {
case http.StateIdle:
c.markIdle()
case http.StateHijacked:
c.hijack()
}
}
if cs != nil {
cs(nc, s)
}
}
go func() {
<-kill
l.Close()
shadow.SetKeepAlivesEnabled(false)
idleSet.killall()
}()
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
}
}