Commit 241facbb authored by Jacob Vosmaer's avatar Jacob Vosmaer

Get rid of underscores

Supposedly they are not idiomatic!
parent 23ff988f
...@@ -27,24 +27,24 @@ import ( ...@@ -27,24 +27,24 @@ import (
) )
type gitService struct { type gitService struct {
method string method string
regexp *regexp.Regexp regexp *regexp.Regexp
handle_func func(string, string, string, http.ResponseWriter, *http.Request) handleFunc func(string, string, string, http.ResponseWriter, *http.Request)
rpc string rpc string
} }
var http_client = &http.Client{} var httpClient = &http.Client{}
var path_traversal = regexp.MustCompile(`/../`) var pathTraversal = regexp.MustCompile(`/../`)
// Command-line options // Command-line options
var repo_root string var repoRoot string
var listen_addr = flag.String("listen_addr", "localhost:8181", "Listen address for HTTP server") var listenAddr = flag.String("listenAddr", "localhost:8181", "Listen address for HTTP server")
var auth_backend = flag.String("auth_backend", "http://localhost:8080", "Authentication/authorization backend") var authBackend = flag.String("authBackend", "http://localhost:8080", "Authentication/authorization backend")
var git_services = [...]gitService{ var gitServices = [...]gitService{
gitService{"GET", regexp.MustCompile(`\A(/..*)/info/refs\z`), handle_get_info_refs, ""}, gitService{"GET", regexp.MustCompile(`\A(/..*)/info/refs\z`), handleGetInfoRefs, ""},
gitService{"POST", regexp.MustCompile(`\A(/..*)/git-upload-pack\z`), handle_post_rpc, "git-upload-pack"}, gitService{"POST", regexp.MustCompile(`\A(/..*)/git-upload-pack\z`), handlePostRPC, "git-upload-pack"},
gitService{"POST", regexp.MustCompile(`\A(/..*)/git-receive-pack\z`), handle_post_rpc, "git-receive-pack"}, gitService{"POST", regexp.MustCompile(`\A(/..*)/git-receive-pack\z`), handlePostRPC, "git-receive-pack"},
} }
func main() { func main() {
...@@ -55,107 +55,107 @@ func main() { ...@@ -55,107 +55,107 @@ func main() {
flag.PrintDefaults() flag.PrintDefaults()
} }
flag.Parse() flag.Parse()
repo_root = flag.Arg(0) repoRoot = flag.Arg(0)
if repo_root == "" { if repoRoot == "" {
flag.Usage() flag.Usage()
os.Exit(1) os.Exit(1)
} }
log.Printf("repo_root: %s", repo_root) log.Printf("repoRoot: %s", repoRoot)
http.HandleFunc("/", git_handler) http.HandleFunc("/", gitHandler)
log.Fatal(http.ListenAndServe(*listen_addr, nil)) log.Fatal(http.ListenAndServe(*listenAddr, nil))
} }
func git_handler(w http.ResponseWriter, r *http.Request) { func gitHandler(w http.ResponseWriter, r *http.Request) {
var gl_id string var gl_id string
var path_match []string var pathMatch []string
var g gitService var g gitService
var found_service bool var foundService bool
log.Print(r.Method, " ", r.URL) log.Print(r.Method, " ", r.URL)
// Look for a matching Git service // Look for a matching Git service
for _, g = range git_services { for _, g = range gitServices {
path_match = g.regexp.FindStringSubmatch(r.URL.Path) pathMatch = g.regexp.FindStringSubmatch(r.URL.Path)
if r.Method == g.method && path_match != nil { if r.Method == g.method && pathMatch != nil {
found_service = true foundService = true
break break
} }
} }
if !found_service { if !foundService {
http.Error(w, "Not Found", 404) http.Error(w, "Not Found", 404)
return return
} }
// Ask the auth backend if the request is allowed, and what the // Ask the auth backend if the request is allowed, and what the
// user ID (GL_ID) is. // user ID (GL_ID) is.
auth_response, err := do_auth_request(r) authResponse, err := doAuthRequest(r)
if err != nil { if err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
if auth_response.StatusCode != 200 { if authResponse.StatusCode != 200 {
// The Git request is not allowed by the backend. Maybe the // The Git request is not allowed by the backend. Maybe the
// client needs to send HTTP Basic credentials. Forward the // client needs to send HTTP Basic credentials. Forward the
// response from the auth backend to our client. This includes // response from the auth backend to our client. This includes
// the 'WWW-Authentication' header that acts as a hint that // the 'WWW-Authentication' header that acts as a hint that
// Basic auth credentials are needed. // Basic auth credentials are needed.
for k, v := range auth_response.Header { for k, v := range authResponse.Header {
w.Header()[k] = v w.Header()[k] = v
} }
w.WriteHeader(auth_response.StatusCode) w.WriteHeader(authResponse.StatusCode)
io.Copy(w, auth_response.Body) io.Copy(w, authResponse.Body)
return return
} }
// The auth backend validated the client request and told us who // The auth backend validated the client request and told us who
// the user is according to them (GL_ID). We must extract this // the user is according to them (GL_ID). We must extract this
// information from the auth response body. // information from the auth response body.
if _, err := fmt.Fscan(auth_response.Body, &gl_id); err != nil { if _, err := fmt.Fscan(authResponse.Body, &gl_id); err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
// Validate the path to the Git repository // Validate the path to the Git repository
found_path := path_match[1] foundPath := pathMatch[1]
if !valid_path(found_path) { if !validPath(foundPath) {
http.Error(w, "Not Found", 404) http.Error(w, "Not Found", 404)
return return
} }
g.handle_func(gl_id, g.rpc, path.Join(repo_root, found_path), w, r) g.handleFunc(gl_id, g.rpc, path.Join(repoRoot, foundPath), w, r)
} }
func valid_path(p string) bool { func validPath(p string) bool {
if path_traversal.MatchString(p) { if pathTraversal.MatchString(p) {
log.Printf("path traversal detected in %s", p) log.Printf("path traversal detected in %s", p)
return false return false
} }
// If /path/to/foo.git/objects exists then let's assume it is a valid Git // If /path/to/foo.git/objects exists then let's assume it is a valid Git
// repository. // repository.
if _, err := os.Stat(path.Join(repo_root, p, "objects")); err != nil { if _, err := os.Stat(path.Join(repoRoot, p, "objects")); err != nil {
log.Print(err) log.Print(err)
return false return false
} }
return true return true
} }
func do_auth_request(r *http.Request) (result *http.Response, err error) { func doAuthRequest(r *http.Request) (result *http.Response, err error) {
url := fmt.Sprintf("%s%s", *auth_backend, r.URL.RequestURI()) url := fmt.Sprintf("%s%s", *authBackend, r.URL.RequestURI())
auth_req, err := http.NewRequest(r.Method, url, nil) authReq, err := http.NewRequest(r.Method, url, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Forward all headers from our client to the auth backend. This includes // Forward all headers from our client to the auth backend. This includes
// HTTP Basic authentication credentials (the 'Authorization' header). // HTTP Basic authentication credentials (the 'Authorization' header).
for k, v := range r.Header { for k, v := range r.Header {
auth_req.Header[k] = v authReq.Header[k] = v
} }
return http_client.Do(auth_req) return httpClient.Do(authReq)
} }
func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWriter, r *http.Request) { func handleGetInfoRefs(gl_id string, _ string, path string, w http.ResponseWriter, r *http.Request) {
rpc := r.URL.Query().Get("service") rpc := r.URL.Query().Get("service")
if !(rpc == "git-upload-pack" || rpc == "git-receive-pack") { if !(rpc == "git-upload-pack" || rpc == "git-receive-pack") {
// The 'dumb' Git HTTP protocol is not supported // The 'dumb' Git HTTP protocol is not supported
...@@ -164,28 +164,28 @@ func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWr ...@@ -164,28 +164,28 @@ func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWr
} }
// Prepare our Git subprocess // Prepare our Git subprocess
cmd := exec.Command("git", sub_command(rpc), "--stateless-rpc", "--advertise-refs", path) cmd := exec.Command("git", subCommand(rpc), "--stateless-rpc", "--advertise-refs", path)
set_cmd_env(cmd, gl_id) setCmdEnv(cmd, gl_id)
stdout, err := cmd.StdoutPipe() stdout, err := cmd.StdoutPipe()
if err != nil { if err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
defer stdout.Close() defer stdout.Close()
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
defer cmd.Wait() defer cmd.Wait()
// Start writing the response // Start writing the response
w.Header().Add("Content-Type", fmt.Sprintf("application/x-%s-advertisement", rpc)) w.Header().Add("Content-Type", fmt.Sprintf("application/x-%s-advertisement", rpc))
header_no_cache(w) setHeaderNoCache(w)
w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just panic w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just panic
if err := pkt_line(w, fmt.Sprintf("# service=%s\n", rpc)); err != nil { if err := pktLine(w, fmt.Sprintf("# service=%s\n", rpc)); err != nil {
panic(err) panic(err)
} }
if err := pkt_flush(w); err != nil { if err := pktFlush(w); err != nil {
panic(err) panic(err)
} }
if _, err := io.Copy(w, stdout); err != nil { if _, err := io.Copy(w, stdout); err != nil {
...@@ -196,18 +196,18 @@ func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWr ...@@ -196,18 +196,18 @@ func handle_get_info_refs(gl_id string, _ string, path string, w http.ResponseWr
} }
} }
func sub_command(rpc string) string { func subCommand(rpc string) string {
return strings.TrimPrefix(rpc, "git-") return strings.TrimPrefix(rpc, "git-")
} }
func set_cmd_env(cmd *exec.Cmd, gl_id string) { func setCmdEnv(cmd *exec.Cmd, gl_id string) {
cmd.Env = []string{ cmd.Env = []string{
fmt.Sprintf("PATH=%s", os.Getenv("PATH")), fmt.Sprintf("PATH=%s", os.Getenv("PATH")),
fmt.Sprintf("GL_ID=%s", gl_id), fmt.Sprintf("GL_ID=%s", gl_id),
} }
} }
func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWriter, r *http.Request) { func handlePostRPC(gl_id string, rpc string, path string, w http.ResponseWriter, r *http.Request) {
var body io.Reader var body io.Reader
var err error var err error
...@@ -215,7 +215,7 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite ...@@ -215,7 +215,7 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
if r.Header.Get("Content-Encoding") == "gzip" { if r.Header.Get("Content-Encoding") == "gzip" {
body, err = gzip.NewReader(r.Body) body, err = gzip.NewReader(r.Body)
if err != nil { if err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
} else { } else {
...@@ -223,36 +223,36 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite ...@@ -223,36 +223,36 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
} }
// Prepare our Git subprocess // Prepare our Git subprocess
cmd := exec.Command("git", sub_command(rpc), "--stateless-rpc", path) cmd := exec.Command("git", subCommand(rpc), "--stateless-rpc", path)
set_cmd_env(cmd, gl_id) setCmdEnv(cmd, gl_id)
stdout, err := cmd.StdoutPipe() stdout, err := cmd.StdoutPipe()
if err != nil { if err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
defer stdout.Close() defer stdout.Close()
stdin, err := cmd.StdinPipe() stdin, err := cmd.StdinPipe()
if err != nil { if err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
defer stdin.Close() defer stdin.Close()
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
defer cmd.Wait() defer cmd.Wait()
// Write the client request body to Git's standard input // Write the client request body to Git's standard input
if _, err := io.Copy(stdin, body); err != nil { if _, err := io.Copy(stdin, body); err != nil {
fail_500(w, err) fail500(w, err)
return return
} }
stdin.Close() stdin.Close()
// Start writing the response // Start writing the response
w.Header().Add("Content-Type", fmt.Sprintf("application/x-%s-result", rpc)) w.Header().Add("Content-Type", fmt.Sprintf("application/x-%s-result", rpc))
header_no_cache(w) setHeaderNoCache(w)
w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just panic w.WriteHeader(200) // Don't bother with HTTP 500 from this point on, just panic
if _, err := io.Copy(w, stdout); err != nil { if _, err := io.Copy(w, stdout); err != nil {
panic(err) panic(err)
...@@ -262,21 +262,21 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite ...@@ -262,21 +262,21 @@ func handle_post_rpc(gl_id string, rpc string, path string, w http.ResponseWrite
} }
} }
func pkt_line(w io.Writer, s string) error { func pktLine(w io.Writer, s string) error {
_, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s) _, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s)
return err return err
} }
func pkt_flush(w io.Writer) error { func pktFlush(w io.Writer) error {
_, err := fmt.Fprint(w, "0000") _, err := fmt.Fprint(w, "0000")
return err return err
} }
func fail_500(w http.ResponseWriter, err error) { func fail500(w http.ResponseWriter, err error) {
http.Error(w, "Internal server error", 500) http.Error(w, "Internal server error", 500)
log.Print(err) log.Print(err)
} }
func header_no_cache(w http.ResponseWriter) { func setHeaderNoCache(w http.ResponseWriter) {
w.Header().Add("Cache-Control", "no-cache") w.Header().Add("Cache-Control", "no-cache")
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment