13 Addr string // host:port where the server is listening.
17 listener *net.TCPListener
21 func (srv *server) Start() error {
22 gitHandler := &cgi.Handler{
23 Path: theConfig.GitCommand,
26 "GIT_PROJECT_ROOT=" + theConfig.Root,
27 "GIT_HTTP_EXPORT_ALL=",
29 InheritEnv: []string{"PATH"},
30 Args: []string{"http-backend"},
33 // The rest of the work here is essentially
34 // http.ListenAndServe() with two more features: (1) whoever
35 // called Start() can discover which address:port we end up
36 // listening to -- which makes listening on ":0" useful in
37 // test suites -- and (2) the server can be shut down without
38 // killing the process -- which is useful in test cases, and
39 // makes it possible to shut down gracefully on SIGTERM
40 // without killing active connections.
42 addr, err := net.ResolveTCPAddr("tcp", theConfig.Addr)
46 srv.listener, err = net.ListenTCP("tcp", addr)
50 srv.Addr = srv.listener.Addr().String()
51 mux := http.NewServeMux()
52 mux.Handle("/", &authHandler{gitHandler})
55 mutex := &sync.RWMutex{}
56 srv.cond = sync.NewCond(mutex.RLocker())
59 err = srv.Serve(tcpKeepAliveListener{srv.listener})
71 // Wait returns when the server has shut down.
72 func (srv *server) Wait() error {
77 defer srv.cond.L.Unlock()
84 // Close shuts down the server and returns when it has stopped.
85 func (srv *server) Close() error {
91 // tcpKeepAliveListener is copied from net/http because not exported.
93 type tcpKeepAliveListener struct {
97 func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
98 tc, err := ln.AcceptTCP()
102 tc.SetKeepAlive(true)
103 tc.SetKeepAlivePeriod(3 * time.Minute)