From f3dfce1494ad3c2aea48fb7182c0086347b90375 Mon Sep 17 00:00:00 2001 From: Winter Date: Sat, 9 Aug 2025 23:13:36 -0400 Subject: [PATCH] knotserver: allow downloading archives of refs with slashes in their names Change-Id: nznsykstnxtwzkylxxzsmwtqmuurtplr This allows us to be more precise when downloading e.g. tags that have the same name as branches (in which case Git defaults to the branch, not sure what go-git does). Signed-off-by: Winter --- knotserver/routes.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/knotserver/routes.go b/knotserver/routes.go index ba0afa3..19ef2c2 100644 --- a/knotserver/routes.go +++ b/knotserver/routes.go @@ -361,14 +361,22 @@ func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) { ref := strings.TrimSuffix(file, ".tar.gz") + unescapedRef, err := url.PathUnescape(ref) + if err != nil { + notFound(w) + return + } + + safeRefFilename := strings.ReplaceAll(plumbing.ReferenceName(unescapedRef).Short(), "/", "-") + // This allows the browser to use a proper name for the file when // downloading - filename := fmt.Sprintf("%s-%s.tar.gz", name, ref) + filename := fmt.Sprintf("%s-%s.tar.gz", name, safeRefFilename) setContentDisposition(w, filename) setGZipMIME(w) path, _ := securejoin.SecureJoin(h.c.Repo.ScanPath, didPath(r)) - gr, err := git.Open(path, ref) + gr, err := git.Open(path, unescapedRef) if err != nil { notFound(w) return @@ -377,7 +385,7 @@ func (h *Handle) Archive(w http.ResponseWriter, r *http.Request) { gw := gzip.NewWriter(w) defer gw.Close() - prefix := fmt.Sprintf("%s-%s", name, ref) + prefix := fmt.Sprintf("%s-%s", name, safeRefFilename) err = gr.WriteTar(gw, prefix) if err != nil { // once we start writing to the body we can't report error anymore -- 2.43.0