Example #1
0
// 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)
			}()
		}
	}
}
Example #2
0
	if err != nil {
		return ln, err
	}

	stopper.RunWorker(func() {
		<-stopper.ShouldDrain()
		server.Stop()
	})

	stopper.RunWorker(func() {
		FatalIfUnexpected(server.Serve(ln))
	})
	return ln, nil
}

var httpLogger = log.NewStdLogger(log.ErrorLog)

// Server is a thin wrapper around http.Server. See MakeServer for more detail.
type Server struct {
	*http.Server
}

// MakeServer constructs a Server that tracks active connections, closing them
// when signalled by stopper.
func MakeServer(stopper *stop.Stopper, tlsConfig *tls.Config, handler http.Handler) Server {
	var mu sync.Mutex
	activeConns := make(map[net.Conn]struct{})
	server := Server{
		Server: &http.Server{
			Handler:   handler,
			TLSConfig: tlsConfig,