Author | Jakob Wakeling <[email protected]> |
Date | 2023-11-16 10:06:56 |
Commit | b4de62691eccd59541652dc3c7b00c6da85e85b3 |
Parent | 35fbf5f73281709d10188c18c0ffe35025f8213f |
Implement file downloading
Diffstat
M | res/repo/tree.html | | | 2 | +- |
M | src/main.go | | | 1 | + |
A | src/repo/download.go | | | 85 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/repo/file.go | | | 2 | ++ |
M | src/repo/raw.go | | | 2 | ++ |
5 files changed, 91 insertions, 1 deletions
diff --git a/res/repo/tree.html b/res/repo/tree.html index 5bf72d1..77bfb3b 100644 --- a/res/repo/tree.html +++ b/res/repo/tree.html @@ -24,7 +24,7 @@ <a href="/{{$.Name}}/log/{{.RawPath}}">log</a> blame <a href="/{{$.Name}}/raw/{{.RawPath}}">raw</a> - download + <a href="/{{$.Name}}/download/{{.RawPath}}">download</a> {{end}} </td> </tr> diff --git a/src/main.go b/src/main.go index d59bdeb..00cedf2 100644 --- a/src/main.go +++ b/src/main.go @@ -101,6 +101,7 @@ func main() { 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/{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) diff --git a/src/repo/download.go b/src/repo/download.go new file mode 100644 index 0000000..db538be --- /dev/null +++ b/src/repo/download.go @@ -0,0 +1,85 @@ +package repo + +import ( + "errors" + "fmt" + "io" + "log" + "net/http" + "path/filepath" + + "github.com/Jamozed/Goit/src/goit" + "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) { + auth, user, err := goit.Auth(w, r, true) + if err != nil { + log.Println("[repo/raw]", err.Error()) + goit.HttpError(w, http.StatusInternalServerError) + return + } + + path := mux.Vars(r)["path"] + + repo, err := goit.GetRepoByName(mux.Vars(r)["repo"]) + if err != nil { + goit.HttpError(w, http.StatusInternalServerError) + return + } else if repo == nil || (repo.IsPrivate && (!auth || user.Id != repo.OwnerId)) { + goit.HttpError(w, http.StatusNotFound) + return + } + + gr, err := git.PlainOpen(goit.RepoPath(repo.Name, true)) + if err != nil { + log.Println("[/repo/file]", err.Error()) + goit.HttpError(w, http.StatusInternalServerError) + return + } + + ref, err := gr.Head() + if errors.Is(err, plumbing.ErrReferenceNotFound) { + goit.HttpError(w, http.StatusNotFound) + return + } else if err != nil { + log.Println("[/repo/file]", err.Error()) + goit.HttpError(w, http.StatusInternalServerError) + return + } + + commit, err := gr.CommitObject(ref.Hash()) + if err != nil { + log.Println("[/repo/file]", err.Error()) + goit.HttpError(w, http.StatusInternalServerError) + return + } + + file, err := commit.File(path) + if errors.Is(err, object.ErrFileNotFound) { + goit.HttpError(w, http.StatusNotFound) + return + } else if err != nil { + log.Println("[/repo/file]", err.Error()) + goit.HttpError(w, http.StatusInternalServerError) + return + } + + if rc, err := file.Blob.Reader(); err != nil { + log.Println("[/repo/file]", err.Error()) + goit.HttpError(w, http.StatusInternalServerError) + return + } else { + w.Header().Set("Content-Disposition", "attachement; filename="+filepath.Base(path)) + w.Header().Set("Content-Length", fmt.Sprint(file.Size)) + + if _, err := io.Copy(w, rc); err != nil { + log.Println("[/repo/download]", err.Error()) + } + + rc.Close() + } +} diff --git a/src/repo/file.go b/src/repo/file.go index da2651c..440ad1d 100644 --- a/src/repo/file.go +++ b/src/repo/file.go @@ -117,6 +117,8 @@ func HandleFile(w http.ResponseWriter, r *http.Request) { data.Body = string(append(buf, buf2...)) data.Lines = strings.Split(data.Body, "\n") } + + rc.Close() } if err := goit.Tmpl.ExecuteTemplate(w, "repo/file", data); err != nil { diff --git a/src/repo/raw.go b/src/repo/raw.go index d0b5430..6eb55ac 100644 --- a/src/repo/raw.go +++ b/src/repo/raw.go @@ -83,5 +83,7 @@ func HandleRaw(w http.ResponseWriter, r *http.Request) { goit.HttpError(w, http.StatusInternalServerError) return } + + rc.Close() } }