scripts/
static/
templates/
.gitignore
30 B
.gitsigners
112 B
AGENTS.md
7.5 KiB
LICENSE
89 B
README.md
1.9 KiB
deploy
723 B
discuss.go
16.7 KiB
git.go
3.5 KiB
git_cli.go
16.0 KiB
git_http.go
1.9 KiB
go.mod
572 B
go.sum
1.9 KiB
handler.go
11.3 KiB
handler_test.go
69.0 KiB
main.go
5.2 KiB
template.go
8.9 KiB
watch
272 B
git_http.go
raw
| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "net/http" |
| 5 | "net/http/cgi" |
| 6 | "os/exec" |
| 7 | "strings" |
| 8 | ) |
| 9 | |
| 10 | // handleGitHTTP serves Git smart HTTP protocol requests by proxying to git-http-backend. |
| 11 | // This enables `git clone` over HTTPS. |
| 12 | func (s *server) handleGitHTTP(w http.ResponseWriter, r *http.Request, repo *RepoInfo) { |
| 13 | gitHTTPBackend, err := exec.LookPath("git-http-backend") |
| 14 | if err != nil { |
| 15 | gitExecPath, err2 := exec.Command("git", "--exec-path").Output() |
| 16 | if err2 != nil { |
| 17 | http.Error(w, "git-http-backend not found", http.StatusInternalServerError) |
| 18 | return |
| 19 | } |
| 20 | gitHTTPBackend = strings.TrimSpace(string(gitExecPath)) + "/git-http-backend" |
| 21 | } |
| 22 | |
| 23 | // Strip the base URL prefix and repo name to get the path info that git-http-backend expects. |
| 24 | // e.g. /baseurl/repo/info/refs -> /repo.git/info/refs |
| 25 | pathInfo := r.URL.Path |
| 26 | if s.baseURL != "" { |
| 27 | pathInfo = strings.TrimPrefix(pathInfo, s.baseURL) |
| 28 | } |
| 29 | // Replace /<reponame>/ with /<reponame>.git/ |
| 30 | pathInfo = strings.Replace(pathInfo, "/"+repo.Name+"/", "/"+repo.Name+".git/", 1) |
| 31 | |
| 32 | handler := &cgi.Handler{ |
| 33 | Path: gitHTTPBackend, |
| 34 | Env: []string{ |
| 35 | "GIT_PROJECT_ROOT=" + s.scanPath, |
| 36 | "GIT_HTTP_EXPORT_ALL=1", |
| 37 | "GIT_CONFIG_COUNT=1", |
| 38 | "GIT_CONFIG_KEY_0=safe.directory", |
| 39 | "GIT_CONFIG_VALUE_0=*", |
| 40 | }, |
| 41 | InheritEnv: []string{"PATH"}, |
| 42 | } |
| 43 | |
| 44 | // Override PATH_INFO for the CGI handler. |
| 45 | r2 := r.Clone(r.Context()) |
| 46 | r2.URL.Path = pathInfo |
| 47 | |
| 48 | handler.ServeHTTP(w, r2) |
| 49 | } |
| 50 | |
| 51 | // isGitHTTPRequest returns true if the request is a Git smart HTTP protocol request. |
| 52 | func isGitHTTPRequest(r *http.Request) bool { |
| 53 | query := r.URL.RawQuery |
| 54 | |
| 55 | if strings.HasSuffix(r.URL.Path, "/info/refs") && |
| 56 | (strings.Contains(query, "service=git-upload-pack") || strings.Contains(query, "service=git-receive-pack")) { |
| 57 | return true |
| 58 | } |
| 59 | if strings.HasSuffix(r.URL.Path, "/git-upload-pack") || strings.HasSuffix(r.URL.Path, "/git-receive-pack") { |
| 60 | return true |
| 61 | } |
| 62 | if strings.HasSuffix(r.URL.Path, "/HEAD") || strings.Contains(r.URL.Path, "/objects/") { |
| 63 | return true |
| 64 | } |
| 65 | return false |
| 66 | } |