Goit

Simple and lightweight Git web server
Mirror of https://github.com/Jamozed/Goit
git clone http://git.omkov.net/Goit
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2023-12-01 10:26:03
Commit3f4c3f42896da1308bb466a5608210eb22e2490b
Parentdb4ceebc97457e4d81187c42f32caae1c6e15278

Switch to Chi from Gorilla Mux

Diffstat

M go.mod | 2 +-
M go.sum | 4 ++--
M src/goit/git.go | 5 +++--
M src/main.go | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
M src/repo/commit.go | 6 +++---
M src/repo/download.go | 13 ++++++-------
M src/repo/edit.go | 5 +++--
M src/repo/file.go | 8 ++++----
M src/repo/log.go | 11 ++++++-----
M src/repo/raw.go | 8 ++++----
M src/repo/refs.go | 4 ++--
M src/repo/tree.go | 23 ++++++++++++-----------

12 files changed, 114 insertions, 62 deletions

diff --git a/go.mod b/go.mod
index f46ede9..db3300d 100644
--- a/go.mod
+++ b/go.mod
@@ -6,9 +6,9 @@ require (
 	github.com/adrg/xdg v0.4.0
 	github.com/buildkite/terminal-to-html/v3 v3.9.1
 	github.com/dustin/go-humanize v1.0.1
+	github.com/go-chi/chi/v5 v5.0.10
 	github.com/go-git/go-git/v5 v5.10.1
 	github.com/gorilla/csrf v1.7.2
-	github.com/gorilla/mux v1.8.1
 	github.com/mattn/go-sqlite3 v1.14.18
 	golang.org/x/crypto v0.16.0
 )
diff --git a/go.sum b/go.sum
index 8390d7b..31a6ee8 100644
--- a/go.sum
+++ b/go.sum
@@ -30,6 +30,8 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc
 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
 github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
+github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
+github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
 github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
@@ -46,8 +48,6 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
 github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI=
 github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk=
-github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
-github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
 github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA=
 github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
diff --git a/src/goit/git.go b/src/goit/git.go
index 1c5197d..4bdfa47 100644
--- a/src/goit/git.go
+++ b/src/goit/git.go
@@ -15,9 +15,9 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5/plumbing/format/diff"
 	"github.com/go-git/go-git/v5/plumbing/object"
-	"github.com/gorilla/mux"
 )
 
 type gitCommand struct {
@@ -81,7 +81,7 @@ func HandleReceivePack(w http.ResponseWriter, r *http.Request) {
 }
 
 func gitHttpBase(w http.ResponseWriter, r *http.Request, service string) *Repo {
-	reponame := mux.Vars(r)["repo"]
+	reponame := chi.URLParam(r, "repo")
 
 	/* Check that the Git service and protocol version are supported */
 	if service != "git-upload-pack" && service != "git-receive-pack" {
diff --git a/src/main.go b/src/main.go
index 26bf003..8b830a7 100644
--- a/src/main.go
+++ b/src/main.go
@@ -13,6 +13,7 @@ import (
 	"net/http"
 	"os"
 	"os/signal"
+	"path"
 	"path/filepath"
 	"strings"
 	"sync"
@@ -25,8 +26,9 @@ import (
 	"github.com/Jamozed/Goit/src/user"
 	"github.com/Jamozed/Goit/src/util"
 	"github.com/adrg/xdg"
+	"github.com/go-chi/chi/v5"
+	"github.com/go-chi/chi/v5/middleware"
 	"github.com/gorilla/csrf"
-	"github.com/gorilla/mux"
 )
 
 func main() {
@@ -77,43 +79,65 @@ func main() {
 		log.Fatalln(err.Error())
 	}
 
-	h := mux.NewRouter()
-	h.StrictSlash(true)
-
-	h.Path("/").HandlerFunc(goit.HandleIndex)
-	h.Path("/user/login").Methods("GET", "POST").HandlerFunc(user.HandleLogin)
-	h.Path("/user/logout").Methods("GET", "POST").HandlerFunc(goit.HandleUserLogout)
-	h.Path("/user/sessions").Methods("GET", "POST").HandlerFunc(user.HandleSessions)
-	h.Path("/user/edit").Methods("GET", "POST").HandlerFunc(user.HandleEdit)
-	h.Path("/repo/create").Methods("GET", "POST").HandlerFunc(repo.HandleCreate)
-	h.Path("/admin").Methods("GET").HandlerFunc(admin.HandleIndex)
-	h.Path("/admin/users").Methods("GET").HandlerFunc(admin.HandleUsers)
-	h.Path("/admin/user/create").Methods("GET", "POST").HandlerFunc(admin.HandleUserCreate)
-	h.Path("/admin/user/edit").Methods("GET", "POST").HandlerFunc(admin.HandleUserEdit)
-	h.Path("/admin/repos").Methods("GET").HandlerFunc(admin.HandleRepos)
-	h.Path("/admin/repo/edit").Methods("GET", "POST").HandlerFunc(admin.HandleRepoEdit)
-
-	h.Path("/{repo:.+(?:\\.git)$}").Methods("GET").HandlerFunc(redirectDotGit)
-	h.Path("/{repo}").Methods("GET").HandlerFunc(repo.HandleLog)
-	h.Path("/{repo}/log").Methods("GET").HandlerFunc(repo.HandleLog)
-	h.Path("/{repo}/log/{path:.*}").Methods("GET").HandlerFunc(repo.HandleLog)
-	h.Path("/{repo}/commit/{hash}").Methods("GET").HandlerFunc(repo.HandleCommit)
-	h.Path("/{repo}/tree").Methods("GET").HandlerFunc(repo.HandleTree)
-	h.Path("/{repo}/tree/{path:.*}").Methods("GET").HandlerFunc(repo.HandleTree)
-	h.Path("/{repo}/file/{path:.*}").Methods("GET").HandlerFunc(repo.HandleFile)
-	h.Path("/{repo}/raw/{path:.*}").Methods("GET").HandlerFunc(repo.HandleRaw)
-	h.Path("/{repo}/download").Methods("GET").HandlerFunc(repo.HandleDownload)
-	h.Path("/{repo}/download/{path:.*}").Methods("GET").HandlerFunc(repo.HandleDownload)
-	h.Path("/{repo}/refs").Methods("GET").HandlerFunc(repo.HandleRefs)
-	h.Path("/{repo}/edit").Methods("GET", "POST").HandlerFunc(repo.HandleEdit)
-	h.Path("/{repo}/info/refs").Methods("GET").HandlerFunc(goit.HandleInfoRefs)
-	h.Path("/{repo}/git-upload-pack").Methods("POST").HandlerFunc(goit.HandleUploadPack)
-	h.Path("/{repo}/git-receive-pack").Methods("POST").HandlerFunc(goit.HandleReceivePack)
-
-	h.Path("/static/style.css").Methods("GET").HandlerFunc(handleStyle)
-	h.Path("/static/favicon.png").Methods("GET").HandlerFunc(handleFavicon)
-
-	h.PathPrefix("/").HandlerFunc(goit.HttpNotFound)
+	h := chi.NewRouter()
+	h.NotFound(goit.HttpNotFound)
+	h.Use(middleware.RedirectSlashes)
+
+	if goit.Debug {
+		h.Use(middleware.Logger)
+	} else {
+		h.Use(logHttp)
+	}
+
+	h.Use(csrf.Protect(
+		[]byte(goit.Conf.CsrfSecret), csrf.FieldName("csrf.Token"), csrf.CookieName("csrf"),
+		csrf.Secure(util.If(goit.Conf.UsesHttps, true, false)),
+	))
+
+	h.Get("/", goit.HandleIndex)
+	h.Get("/user/login", user.HandleLogin)
+	h.Post("/user/login", user.HandleLogin)
+	h.Get("/user/logout", goit.HandleUserLogout)
+	h.Post("/user/logout", goit.HandleUserLogout)
+	h.Get("/user/sessions", user.HandleSessions)
+	h.Post("/user/sessions", user.HandleSessions)
+	h.Get("/user/edit", user.HandleEdit)
+	h.Post("/user/edit", user.HandleEdit)
+	h.Get("/repo/create", repo.HandleCreate)
+	h.Post("/repo/create", repo.HandleCreate)
+	h.Get("/admin", admin.HandleIndex)
+	h.Get("/admin/users", admin.HandleUsers)
+	h.Get("/admin/user/create", admin.HandleUserCreate)
+	h.Post("/admin/user/create", admin.HandleUserCreate)
+	h.Get("/admin/user/edit", admin.HandleUserEdit)
+	h.Post("/admin/user/edit", admin.HandleUserEdit)
+	h.Get("/admin/repos", admin.HandleRepos)
+	h.Get("/admin/repo/edit", admin.HandleRepoEdit)
+	h.Post("/admin/repo/edit", admin.HandleRepoEdit)
+
+	h.Get("/static/style.css", handleStyle)
+	h.Get("/static/favicon.png", handleFavicon)
+	h.Get("/favicon.ico", goit.HttpNotFound)
+
+	h.Get("/{repo:.+(?:\\.git)$}", redirectDotGit)
+	h.Get("/{repo}", repo.HandleLog)
+	h.Get("/{repo}/log", repo.HandleLog)
+	h.Get("/{repo}/log/*", repo.HandleLog)
+	h.Get("/{repo}/commit/{hash}", repo.HandleCommit)
+	h.Get("/{repo}/tree", repo.HandleTree)
+	h.Get("/{repo}/tree/*", repo.HandleTree)
+	h.Get("/{repo}/file/*", repo.HandleFile)
+	h.Get("/{repo}/raw/*", repo.HandleRaw)
+	h.Get("/{repo}/download", repo.HandleDownload)
+	h.Get("/{repo}/download/*", repo.HandleDownload)
+	h.Get("/{repo}/refs", repo.HandleRefs)
+	h.Get("/{repo}/edit", repo.HandleEdit)
+	h.Post("/{repo}/edit", repo.HandleEdit)
+	h.Get("/{repo}/info/refs", goit.HandleInfoRefs)
+	h.Get("/{repo}/git-upload-pack", goit.HandleUploadPack)
+	h.Post("/{repo}/git-upload-pack", goit.HandleUploadPack)
+	h.Get("/{repo}/git-receive-pack", goit.HandleReceivePack)
+	h.Post("/{repo}/git-receive-pack", goit.HandleReceivePack)
 
 	/* Create a ticker to periodically cleanup expired sessions */
 	tick := time.NewTicker(1 * time.Hour)
@@ -137,13 +161,8 @@ func main() {
 	wait.Add(1)
 	go handleIpc(stop, wait, ipc)
 
-	protect := csrf.Protect(
-		[]byte(goit.Conf.CsrfSecret), csrf.FieldName("csrf.Token"), csrf.CookieName("csrf"),
-		csrf.Secure(util.If(goit.Conf.UsesHttps, true, false)),
-	)
-
 	/* Listen for HTTP on the specified port */
-	if err := http.ListenAndServe(goit.Conf.HttpAddr+":"+goit.Conf.HttpPort, protect(logHttp(h))); err != nil {
+	if err := http.ListenAndServe(goit.Conf.HttpAddr+":"+goit.Conf.HttpPort, h); err != nil {
 		log.Fatalln("[HTTP]", err.Error())
 	}
 }
diff --git a/src/repo/commit.go b/src/repo/commit.go
index c409427..0e696ca 100644
--- a/src/repo/commit.go
+++ b/src/repo/commit.go
@@ -14,9 +14,9 @@ import (
 	"github.com/Jamozed/Goit/src/goit"
 	"github.com/Jamozed/Goit/src/util"
 	"github.com/buildkite/terminal-to-html/v3"
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
-	"github.com/gorilla/mux"
 )
 
 func HandleCommit(w http.ResponseWriter, r *http.Request) {
@@ -26,7 +26,7 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) {
 		goit.HttpError(w, http.StatusInternalServerError)
 	}
 
-	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
 	if err != nil {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
@@ -79,7 +79,7 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
-	commit, err := gr.CommitObject(plumbing.NewHash(mux.Vars(r)["hash"]))
+	commit, err := gr.CommitObject(plumbing.NewHash(chi.URLParam(r, "hash")))
 	if errors.Is(err, plumbing.ErrObjectNotFound) {
 		goit.HttpError(w, http.StatusNotFound)
 		return
diff --git a/src/repo/download.go b/src/repo/download.go
index 51d5548..57c96f6 100644
--- a/src/repo/download.go
+++ b/src/repo/download.go
@@ -12,10 +12,10 @@ import (
 
 	"github.com/Jamozed/Goit/src/goit"
 	"github.com/Jamozed/Goit/src/util"
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/object"
-	"github.com/gorilla/mux"
 )
 
 func HandleDownload(w http.ResponseWriter, r *http.Request) {
@@ -26,9 +26,9 @@ func HandleDownload(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	path := mux.Vars(r)["path"]
+	tpath := chi.URLParam(r, "*")
 
-	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
 	if err != nil {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
@@ -61,7 +61,7 @@ func HandleDownload(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	file, err := commit.File(path)
+	file, err := commit.File(tpath)
 	if errors.Is(err, object.ErrFileNotFound) {
 		/* Possibly a directory, search file tree for prefix */
 		var files []string
@@ -75,7 +75,7 @@ func HandleDownload(w http.ResponseWriter, r *http.Request) {
 		}
 
 		iter.ForEach(func(f *object.File) error {
-			if path == "" || strings.HasPrefix(f.Name, path+"/") {
+			if tpath == "" || strings.HasPrefix(f.Name, tpath+"/") {
 				files = append(files, f.Name)
 				zSize += uint64(f.Size)
 			}
@@ -90,7 +90,7 @@ func HandleDownload(w http.ResponseWriter, r *http.Request) {
 
 		/* Build and write ZIP of directory */
 		w.Header().Set(
-			"Content-Disposition", "attachment; filename="+util.If(path == "", repo.Name, filepath.Base(path))+".zip",
+			"Content-Disposition", "attachment; filename="+util.If(tpath == "", repo.Name, filepath.Base(tpath))+".zip",
 		)
 		// w.Header().Set("Content-Length", fmt.Sprint(zSize))
 
@@ -134,7 +134,7 @@ func HandleDownload(w http.ResponseWriter, r *http.Request) {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
 	} else {
-		w.Header().Set("Content-Disposition", "attachement; filename="+filepath.Base(path))
+		w.Header().Set("Content-Disposition", "attachement; filename="+filepath.Base(tpath))
 		w.Header().Set("Content-Length", fmt.Sprint(file.Size))
 
 		if _, err := io.Copy(w, rc); err != nil {
diff --git a/src/repo/edit.go b/src/repo/edit.go
index fb24573..c72b342 100644
--- a/src/repo/edit.go
+++ b/src/repo/edit.go
@@ -11,10 +11,10 @@ import (
 
 	"github.com/Jamozed/Goit/src/goit"
 	"github.com/Jamozed/Goit/src/util"
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/gorilla/csrf"
-	"github.com/gorilla/mux"
 )
 
 func HandleEdit(w http.ResponseWriter, r *http.Request) {
@@ -30,7 +30,7 @@ func HandleEdit(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
 	if err != nil {
 		log.Println("[/repo/edit]", err.Error())
 		goit.HttpError(w, http.StatusInternalServerError)
diff --git a/src/repo/file.go b/src/repo/file.go
index a7ffe9e..7ad701f 100644
--- a/src/repo/file.go
+++ b/src/repo/file.go
@@ -13,10 +13,10 @@ import (
 	"github.com/Jamozed/Goit/src/goit"
 	"github.com/Jamozed/Goit/src/util"
 	"github.com/dustin/go-humanize"
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/object"
-	"github.com/gorilla/mux"
 )
 
 func HandleFile(w http.ResponseWriter, r *http.Request) {
@@ -26,9 +26,9 @@ func HandleFile(w http.ResponseWriter, r *http.Request) {
 		goit.HttpError(w, http.StatusInternalServerError)
 	}
 
-	treepath := mux.Vars(r)["path"]
+	tpath := chi.URLParam(r, "*")
 
-	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
 	if err != nil {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
@@ -82,7 +82,7 @@ func HandleFile(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	file, err := commit.File(treepath)
+	file, err := commit.File(tpath)
 	if errors.Is(err, object.ErrFileNotFound) {
 		goit.HttpError(w, http.StatusNotFound)
 		return
diff --git a/src/repo/log.go b/src/repo/log.go
index 73192b3..cdb934e 100644
--- a/src/repo/log.go
+++ b/src/repo/log.go
@@ -11,10 +11,10 @@ import (
 
 	"github.com/Jamozed/Goit/src/goit"
 	"github.com/Jamozed/Goit/src/util"
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/object"
-	"github.com/gorilla/mux"
 )
 
 func HandleLog(w http.ResponseWriter, r *http.Request) {
@@ -25,9 +25,9 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	path := mux.Vars(r)["path"]
+	tpath := chi.URLParam(r, "*")
 
-	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
 	if err != nil {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
@@ -88,11 +88,12 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 	} else if err := iter.ForEach(func(c *object.Commit) error {
 		var files, additions, deletions int
 
+		/* TODO speed this up or cache it, diff calculations are quite slow */
 		if stats, err := goit.DiffStats(c); err != nil {
 			log.Println("[/repo/log]", err.Error())
-		} else if path != "" {
+		} else if tpath != "" {
 			for _, s := range stats {
-				if s.Name == path || strings.HasPrefix(s.Name, path+"/") {
+				if s.Name == tpath || strings.HasPrefix(s.Name, tpath+"/") {
 					files += 1
 					additions += s.Addition
 					deletions += s.Deletion
diff --git a/src/repo/raw.go b/src/repo/raw.go
index 6eb55ac..b7de68f 100644
--- a/src/repo/raw.go
+++ b/src/repo/raw.go
@@ -7,10 +7,10 @@ import (
 	"net/http"
 
 	"github.com/Jamozed/Goit/src/goit"
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/object"
-	"github.com/gorilla/mux"
 )
 
 func HandleRaw(w http.ResponseWriter, r *http.Request) {
@@ -21,9 +21,9 @@ func HandleRaw(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	treepath := mux.Vars(r)["path"]
+	tpath := chi.URLParam(r, "*")
 
-	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
 	if err != nil {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
@@ -56,7 +56,7 @@ func HandleRaw(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	file, err := commit.File(treepath)
+	file, err := commit.File(tpath)
 	if errors.Is(err, object.ErrFileNotFound) {
 		goit.HttpError(w, http.StatusNotFound)
 		return
diff --git a/src/repo/refs.go b/src/repo/refs.go
index b0f2af4..dfac9b0 100644
--- a/src/repo/refs.go
+++ b/src/repo/refs.go
@@ -10,9 +10,9 @@ import (
 
 	"github.com/Jamozed/Goit/src/goit"
 	"github.com/Jamozed/Goit/src/util"
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
-	"github.com/gorilla/mux"
 )
 
 func HandleRefs(w http.ResponseWriter, r *http.Request) {
@@ -22,7 +22,7 @@ func HandleRefs(w http.ResponseWriter, r *http.Request) {
 		goit.HttpError(w, http.StatusInternalServerError)
 	}
 
-	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
 	if err != nil {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
diff --git a/src/repo/tree.go b/src/repo/tree.go
index 18bcdff..e02648a 100644
--- a/src/repo/tree.go
+++ b/src/repo/tree.go
@@ -12,10 +12,10 @@ import (
 	"github.com/Jamozed/Goit/src/goit"
 	"github.com/Jamozed/Goit/src/util"
 	"github.com/dustin/go-humanize"
+	"github.com/go-chi/chi/v5"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/object"
-	"github.com/gorilla/mux"
 )
 
 func HandleTree(w http.ResponseWriter, r *http.Request) {
@@ -25,9 +25,9 @@ func HandleTree(w http.ResponseWriter, r *http.Request) {
 		goit.HttpError(w, http.StatusInternalServerError)
 	}
 
-	treepath := mux.Vars(r)["path"]
+	tpath := chi.URLParam(r, "*")
 
-	repo, err := goit.GetRepoByName(mux.Vars(r)["repo"])
+	repo, err := goit.GetRepoByName(chi.URLParam(r, "repo"))
 	if err != nil {
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
@@ -53,7 +53,7 @@ func HandleTree(w http.ResponseWriter, r *http.Request) {
 		Editable: (auth && repo.OwnerId == user.Id),
 	}
 
-	parts := strings.Split(treepath, "/")
+	parts := strings.Split(tpath, "/")
 	htmlPath := "<b style=\"padding-left: 0.4rem;\"><a href=\"/" + repo.Name + "/tree\">" + repo.Name + "</a></b>/"
 	dirPath := ""
 
@@ -100,12 +100,12 @@ func HandleTree(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
-		if treepath != "" {
+		if tpath != "" {
 			data.Files = append(data.Files, row{
-				Mode: "d---------", Name: "..", Path: path.Join("tree", path.Dir(treepath)),
+				Mode: "d---------", Name: "..", Path: path.Join("tree", path.Dir(tpath)),
 			})
 
-			tree, err = tree.Tree(treepath)
+			tree, err = tree.Tree(tpath)
 			if errors.Is(err, object.ErrDirectoryNotFound) {
 				goit.HttpError(w, http.StatusNotFound)
 				return
@@ -138,8 +138,8 @@ func HandleTree(w http.ResponseWriter, r *http.Request) {
 					return
 				}
 
-				fpath = path.Join("file", treepath, v.Name)
-				rpath = path.Join(treepath, v.Name)
+				fpath = path.Join("file", tpath, v.Name)
+				rpath = path.Join(tpath, v.Name)
 				size = humanize.IBytes(uint64(file.Size))
 
 				isFile = true
@@ -164,8 +164,8 @@ func HandleTree(w http.ResponseWriter, r *http.Request) {
 					return
 				}
 
-				fpath = path.Join("tree", treepath, v.Name)
-				rpath = path.Join(treepath, v.Name)
+				fpath = path.Join("tree", tpath, v.Name)
+				rpath = path.Join(tpath, v.Name)
 				size = humanize.IBytes(dirSize)
 
 				totalSize += dirSize