func main() { var srv http.Server flag.BoolVar(&http2.VerboseLogs, "verbose", false, "Verbose HTTP/2 debugging.") flag.Parse() srv.Addr = *httpsAddr srv.ConnState = idleTimeoutHook() registerHandlers() if *prod { *hostHTTP = "http2.golang.org" *hostHTTPS = "http2.golang.org" log.Fatal(serveProd()) } url := "https://" + httpsHost() + "/" log.Printf("Listening on " + url) http2.ConfigureServer(&srv, &http2.Server{}) if *httpAddr != "" { go func() { log.Printf("Listening on http://" + httpHost() + "/ (for unencrypted HTTP/1)") log.Fatal(http.ListenAndServe(*httpAddr, nil)) }() } go func() { log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key")) }() select {} }
// Run the http server on a given host and port. func (m *Martini) RunOnAddr(addr string) { // TODO: Should probably be implemented using a new instance of http.Server in place of // calling http.ListenAndServer directly, so that it could be stored in the martini struct for later use. // This would also allow to improve testing when a custom host and port are passed. logger := m.Injector.Get(reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s (%s)\n", addr, Env) l, err := net.Listen("tcp", addr) if err != nil { logger.Fatalln(err.Error()) return } var server http.Server server.Handler = m server.ConnState = m.connectStateChange m.server.l = l go func() { channel := m.server.stateChannel for input := range channel { switch input.state { case http.StateNew, http.StateActive, http.StateIdle: m.server.connsLock.Lock() m.server.stateMap[input.conn] = input.state m.server.connsLock.Unlock() case http.StateHijacked, http.StateClosed: m.server.connsLock.Lock() delete(m.server.stateMap, input.conn) m.server.connsLock.Unlock() } } }() server.Serve(l) }
// NewServeCloser wraps srv and returns a closable HTTP server. func NewServeCloser(srv *http.Server) (s *ServeCloser) { s = &ServeCloser{ Server: srv, stateHook: srv.ConnState, conns: make(map[net.Conn]bool), } srv.ConnState = s.connState return }
// Similar to http.Serve. The listener passed must wrap a GracefulListener. func (s *GracefulServer) Serve(listener net.Listener, handler http.Handler) error { s.shutdownHandler = func() { listener.Close() } s.listenForShutdown() server := http.Server{Handler: handler} server.ConnState = func(conn net.Conn, newState http.ConnState) { switch newState { case http.StateNew: s.StartRoutine() case http.StateClosed, http.StateHijacked: s.FinishRoutine() } } err := server.Serve(listener) // This block is reached when the server has received a shut down command. if err == nil { return nil } else if _, ok := err.(listenerAlreadyClosed); ok { s.wg.Wait() return nil } return err }
// Serve provides the low-level API which is useful if you're creating your own // net.Listener. func (h HTTP) Serve(s *http.Server, l net.Listener) Server { stopTimeout := h.StopTimeout if stopTimeout == 0 { stopTimeout = defaultStopTimeout } killTimeout := h.KillTimeout if killTimeout == 0 { killTimeout = defaultKillTimeout } klock := h.Clock if klock == nil { klock = clock.New() } ss := &server{ stopTimeout: stopTimeout, killTimeout: killTimeout, stats: h.Stats, clock: klock, oldConnState: s.ConnState, listener: l, server: s, serveDone: make(chan struct{}), serveErr: make(chan error, 1), new: make(chan net.Conn), active: make(chan net.Conn), idle: make(chan net.Conn), closed: make(chan net.Conn), stop: make(chan chan struct{}), kill: make(chan chan struct{}), } s.ConnState = ss.connState go ss.manage() go ss.serve() return ss }
// ServeHandler serves the handler on the listener and returns a function that // serves an additional listener using a function that takes a connection. The // returned function can be called multiple times. func ServeHandler( stopper *stop.Stopper, handler http.Handler, ln net.Listener, tlsConfig *tls.Config, ) func(net.Listener, func(net.Conn)) error { var mu sync.Mutex activeConns := make(map[net.Conn]struct{}) logger := log.NewStdLogger(log.ErrorLog) httpServer := http.Server{ Handler: handler, TLSConfig: tlsConfig, ConnState: func(conn net.Conn, state http.ConnState) { mu.Lock() switch state { case http.StateNew: activeConns[conn] = struct{}{} case http.StateClosed: delete(activeConns, conn) } mu.Unlock() }, ErrorLog: logger, } // net/http.(*Server).Serve/http2.ConfigureServer are not thread safe with // respect to net/http.(*Server).TLSConfig, so we call it synchronously here. if err := http2.ConfigureServer(&httpServer, nil); err != nil { log.Fatal(err) } stopper.RunWorker(func() { FatalIfUnexpected(httpServer.Serve(ln)) <-stopper.ShouldStop() mu.Lock() for conn := range activeConns { conn.Close() } mu.Unlock() }) logFn := logger.Printf return func(l net.Listener, serveConn func(net.Conn)) error { // Inspired by net/http.(*Server).Serve var tempDelay time.Duration // how long to sleep on accept failure for { rw, e := l.Accept() if e != nil { if ne, ok := e.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } logFn("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } return e } tempDelay = 0 go func() { httpServer.ConnState(rw, http.StateNew) // before Serve can return serveConn(rw) httpServer.ConnState(rw, http.StateClosed) }() } } }