package routes import ( "log" "net/http" "path" "path/filepath" "strings" "github.com/dimfeld/httptreemux/v5" "github.com/fsnotify/fsnotify" "alin.ovh/elgit/config" ) // Checks for gitprotocol-http(5) specific smells; if found, passes // the request on to the git http service, else render the web frontend. func (d *deps) Multiplex(w http.ResponseWriter, r *http.Request, params map[string]string) { rest := params["rest"] switch params["name"] { case "info", "git-upload-pack": rest = path.Join(params["name"], params["rest"]) params["name"] = params["category"] params["category"] = "" } if d.isNotAllowed(path.Join(params["category"], params["name"])) { d.Write404(w) return } if r.URL.RawQuery == "service=git-receive-pack" { w.WriteHeader(http.StatusBadRequest) _, err := w.Write([]byte("no pushing allowed!")) if err != nil { log.Println(err) d.Write500(w) return } return } if rest == "info/refs" && r.URL.RawQuery == "service=git-upload-pack" && r.Method == "GET" { d.InfoRefs(w, r, params) } else if rest == "git-upload-pack" && r.Method == "POST" { d.UploadPack(w, r, params) } else if r.Method == "GET" { if fixed, found := strings.CutSuffix(r.URL.Path, "/"); found { http.Redirect(w, r, fixed, http.StatusPermanentRedirect) } else { d.RepoIndex(w, r, params) } } } func Handlers(c *config.Config) *httptreemux.TreeMux { mux := httptreemux.New() plist := filepath.Join(c.Repo.Root, "projects.list") projects, err := ReadProjectsList(plist) if err != nil { log.Fatal(err) } d := deps{ c, projects, } watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatal(err) } err = watcher.Add(plist) if err != nil { log.Fatal(err) } go func() { for { select { case event, ok := <-watcher.Events: if !ok { continue } if event.Op.Has(fsnotify.Write) { d.projects, err = ReadProjectsList(plist) if err != nil { log.Println(err) } } case err, ok := <-watcher.Errors: if !ok { continue } log.Println("error:", err) } } }() mux.NotFoundHandler = func(w http.ResponseWriter, r *http.Request) { d.Write404(w) } mux.RedirectTrailingSlash = false mux.GET("/", d.Index) mux.GET("/static/:file", d.ServeStatic) mux.GET("/:name/tree/:ref/*rest", d.RepoTree) mux.GET("/:name/blob/:ref/*rest", d.FileContent) mux.GET("/:name/tree/:ref/", d.RepoTree) mux.GET("/:name/blob/:ref/", d.FileContent) mux.GET("/:name/log/:ref", d.Log) mux.GET("/:name/archive/:file", d.Archive) mux.GET("/:name/commit/:ref", d.Diff) mux.GET("/:name/commit/:ref/*file", d.FileDiff) mux.GET("/:name/refs/", d.Refs) mux.GET("/:name", d.Multiplex) mux.POST("/:name", d.Multiplex) mux.GET("/:name/", d.Multiplex) mux.POST("/:name/", d.Multiplex) mux.GET("/:name/*rest", d.Multiplex) mux.POST("/:name/*rest", d.Multiplex) mux.GET("/:category/:name/tree/:ref/*rest", d.RepoTree) mux.GET("/:category/:name/blob/:ref/*rest", d.FileContent) mux.GET("/:category/:name/tree/:ref/", d.RepoTree) mux.GET("/:category/:name/blob/:ref/", d.FileContent) mux.GET("/:category/:name/log/:ref", d.Log) mux.GET("/:category/:name/archive/:file", d.Archive) mux.GET("/:category/:name/commit/:ref", d.Diff) mux.GET("/:category/:name/commit/:ref/*file", d.FileDiff) mux.GET("/:category/:name/refs/", d.Refs) mux.GET("/:category/:name", d.Multiplex) mux.POST("/:category/:name", d.Multiplex) mux.GET("/:category/:name/", d.Multiplex) mux.POST("/:category/:name/", d.Multiplex) mux.GET("/:category/:name/*rest", d.Multiplex) mux.POST("/:category/:name/*rest", d.Multiplex) return mux }