aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/zenazn/goji/graceful/serve13.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/zenazn/goji/graceful/serve13.go')
-rw-r--r--vendor/github.com/zenazn/goji/graceful/serve13.go76
1 files changed, 76 insertions, 0 deletions
diff --git a/vendor/github.com/zenazn/goji/graceful/serve13.go b/vendor/github.com/zenazn/goji/graceful/serve13.go
new file mode 100644
index 0000000..68cac04
--- /dev/null
+++ b/vendor/github.com/zenazn/goji/graceful/serve13.go
@@ -0,0 +1,76 @@
+// +build go1.3
+
+package graceful
+
+import (
+ "log"
+ "net"
+ "net/http"
+
+ "github.com/zenazn/goji/graceful/listener"
+)
+
+// This is a slightly hacky shim to disable keepalives when shutting a server
+// down. We could have added extra functionality in listener or signal.go to
+// deal with this case, but this seems simpler.
+type gracefulServer struct {
+ net.Listener
+ s *http.Server
+}
+
+func (g gracefulServer) Close() error {
+ g.s.SetKeepAlivesEnabled(false)
+ return g.Listener.Close()
+}
+
+// A chaining http.ConnState wrapper
+type connState func(net.Conn, http.ConnState)
+
+func (c connState) Wrap(nc net.Conn, s http.ConnState) {
+ // 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:
+ if err := listener.MarkIdle(nc); err != nil {
+ log.Printf("error marking conn as idle: %v", err)
+ }
+ case http.StateHijacked:
+ if err := listener.Disown(nc); err != nil {
+ log.Printf("error disowning hijacked conn: %v", err)
+ }
+ }
+ if c != nil {
+ c(nc, s)
+ }
+}
+
+// Serve behaves like the method on net/http.Server with the same name.
+func (srv *Server) Serve(l net.Listener) error {
+ // 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)
+ shadow.ConnState = connState(shadow.ConnState).Wrap
+
+ l = gracefulServer{l, &shadow}
+ wrap := listener.Wrap(l, listener.Automatic)
+ appendListener(wrap)
+
+ err := shadow.Serve(wrap)
+ return peacefulError(err)
+}