Merge branch 'master' into 7167-keep-rsync
[arvados.git] / services / arv-git-httpd / git_handler.go
1 package main
2
3 import (
4         "log"
5         "net"
6         "net/http"
7         "net/http/cgi"
8 )
9
10 // gitHandler is an http.Handler that invokes git-http-backend (or
11 // whatever backend is configured) via CGI, with appropriate
12 // environment variables in place for git-http-backend or
13 // gitolite-shell.
14 type gitHandler struct {
15         cgi.Handler
16 }
17
18 func newGitHandler() http.Handler {
19         return &gitHandler{
20                 Handler: cgi.Handler{
21                         Path: theConfig.GitCommand,
22                         Dir:  theConfig.Root,
23                         Env: []string{
24                                 "GIT_PROJECT_ROOT=" + theConfig.Root,
25                                 "GIT_HTTP_EXPORT_ALL=",
26                                 "SERVER_ADDR=" + theConfig.Addr,
27                         },
28                         InheritEnv: []string{
29                                 "PATH",
30                                 // Needed if GitCommand is gitolite-shell:
31                                 "GITOLITE_HTTP_HOME",
32                                 "GL_BYPASS_ACCESS_CHECKS",
33                         },
34                         Args: []string{"http-backend"},
35                 },
36         }
37 }
38
39 func (h *gitHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
40         remoteHost, remotePort, err := net.SplitHostPort(r.RemoteAddr)
41         if err != nil {
42                 log.Printf("Internal error: SplitHostPort(r.RemoteAddr==%q): %s", r.RemoteAddr, err)
43                 w.WriteHeader(http.StatusInternalServerError)
44                 return
45         }
46
47         // Copy the wrapped cgi.Handler, so these request-specific
48         // variables don't leak into the next request.
49         handlerCopy := h.Handler
50         handlerCopy.Env = append(handlerCopy.Env,
51                 // In Go1.5 we can skip this, net/http/cgi will do it for us:
52                 "REMOTE_HOST="+remoteHost,
53                 "REMOTE_ADDR="+remoteHost,
54                 "REMOTE_PORT="+remotePort,
55                 // Ideally this would be a real username:
56                 "REMOTE_USER="+r.RemoteAddr,
57         )
58         handlerCopy.ServeHTTP(w, r)
59 }