vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
| 1 | package server |
| 2 | |
| 3 | // The two paths the forge serves that are not pages: a repository's Git |
| 4 | // transport at <name>.git/…, and the go command's module discovery probe on a |
| 5 | // module path. Both decide from the first path segment alone, so they run before |
| 6 | // the mux instead of as routes; a wildcard in a route fills a whole segment, and |
| 7 | // neither "<name>.git" nor a module path with a package suffix can be written as |
| 8 | // one. |
| 9 | |
| 10 | import ( |
| 11 | "net/http" |
| 12 | "path" |
| 13 | "strings" |
| 14 | |
| 15 | "rodent.software/vole/server/githttp" |
| 16 | ) |
| 17 | |
| 18 | // forgeHandler is the mux with the non-page paths in front of it. It sits inside |
| 19 | // the web middleware, so the session, the security headers, the compressor and |
| 20 | // the page-view recorder behave exactly as they do for a page. |
| 21 | func (s *Server) forgeHandler(next http.Handler) http.Handler { |
| 22 | return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { |
| 23 | if s.gitTransport(rw, r) { |
| 24 | return |
| 25 | } |
| 26 | if s.Web.GoModuleMeta(rw, r) { |
| 27 | return |
| 28 | } |
| 29 | next.ServeHTTP(rw, r) |
| 30 | }) |
| 31 | } |
| 32 | |
| 33 | // gitTransport serves a clone or fetch from <name>.git/…, the URL the clone |
| 34 | // menu and the go-import tag advertise. githttp.Route parses that shape; this |
| 35 | // only decides whether the request belongs to the transport or to the mux. |
| 36 | // |
| 37 | // LFS requests are left to the mux: a client asks <name>.git/info/lfs/…, and |
| 38 | // those handlers own the batch and object endpoints. |
| 39 | func (s *Server) gitTransport(rw http.ResponseWriter, r *http.Request) bool { |
| 40 | if s.Proxy == nil || s.Cfg == nil || !s.Cfg.GitHTTP { |
| 41 | return false |
| 42 | } |
| 43 | // An unclean path is the mux's business: it redirects to the cleaned one, and |
| 44 | // the transport must not be the one place that skips that check. |
| 45 | if path.Clean(r.URL.Path) != r.URL.Path { |
| 46 | return false |
| 47 | } |
| 48 | _, rest, ok := githttp.Route(r.URL.Path) |
| 49 | if !ok || rest == "" || strings.HasPrefix(rest, "info/lfs") { |
| 50 | return false |
| 51 | } |
| 52 | s.Proxy.ServeHTTP(rw, r) |
| 53 | return true |
| 54 | } |
| 55 |