@@ -3,7 +3,11 @@ package api
33import (
44 "context"
55 "net/http"
6+ "net/http/cgi"
7+ "os"
8+ "os/exec"
69 "path/filepath"
10+ "strings"
711
812 "github.com/danielgtaylor/huma/v2"
913 "github.com/danielgtaylor/huma/v2/adapters/humachi"
@@ -42,6 +46,7 @@ func NewHandler(conf *utils.Config) http.Handler {
4246
4347 hr .Map ("webdav.localhost" , webdavRouter (conf ))
4448 hr .Map ("api.localhost" , apiRouter (conf ))
49+ hr .Map ("git.localhost" , gitRouter (conf ))
4550 hr .Map ("*" , catchAllRouter ())
4651
4752 r .Mount ("/" , hr )
@@ -121,6 +126,46 @@ func apiRouter(conf *utils.Config) chi.Router {
121126 return r
122127}
123128
129+ func gitRouter (conf * utils.Config ) chi.Router {
130+ r := chi .NewRouter ()
131+
132+ repoRoot := filepath .Join (conf .String ("dir" ))
133+
134+ gitPath , err := exec .LookPath ("git" )
135+ if err != nil {
136+ r .HandleFunc ("/*" , func (w http.ResponseWriter , r * http.Request ) {
137+ http .Error (w , "git binary not found on server" , http .StatusInternalServerError )
138+ })
139+ return r
140+ }
141+
142+ gitHandler := & cgi.Handler {
143+ Path : gitPath ,
144+ Args : []string {"http-backend" },
145+ Env : []string {
146+ "GIT_PROJECT_ROOT=" + repoRoot ,
147+ "GIT_HTTP_EXPORT_ALL=" , // allow read-only access
148+ },
149+ Stderr : os .Stderr ,
150+ InheritEnv : []string {
151+ "PATH" , "HOME" , // inherit some safe env vars
152+ },
153+ }
154+
155+ r .HandleFunc ("/*" , func (w http.ResponseWriter , r * http.Request ) {
156+ if strings .HasSuffix (r .URL .Path , "/git-receive-pack" ) {
157+ http .Error (w , "pushes are disabled" , http .StatusForbidden )
158+ return
159+ }
160+
161+ fixChunked (r )
162+
163+ gitHandler .ServeHTTP (w , r )
164+ })
165+
166+ return r
167+ }
168+
124169func catchAllRouter () chi.Router {
125170 r := chi .NewRouter ()
126171
@@ -131,3 +176,14 @@ func catchAllRouter() chi.Router {
131176
132177 return r
133178}
179+
180+ func fixChunked (req * http.Request ) {
181+ if len (req .TransferEncoding ) > 0 && req .TransferEncoding [0 ] == `chunked` {
182+ // hacking!
183+ req .TransferEncoding = nil
184+ req .Header .Set (`Transfer-Encoding` , `chunked` )
185+
186+ // let cgi use Body.
187+ req .ContentLength = - 1
188+ }
189+ }
0 commit comments