From 54aca2a9ed381decdf94c3977ad868707a4907e9 Mon Sep 17 00:00:00 2001 From: sarge Date: Sat, 7 Mar 2026 18:59:47 +0100 Subject: [PATCH] feat: Add `HEAD` support for debian repo files (#11489) Add `HEAD` handlers for repo index file for debian package registry. Resolves #11488 Co-authored-by: sarge Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11489 Reviewed-by: Gusted Co-authored-by: sarge Co-committed-by: sarge --- routers/api/packages/api.go | 7 +++- routers/api/packages/debian/debian.go | 32 +++++++++++++++++++ tests/integration/api_packages_debian_test.go | 13 ++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 3b51ddc406..2676a6309d 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -354,11 +354,16 @@ func CommonRoutes() *web.Route { }) }, reqPackageAccess(perm.AccessModeRead)) r.Group("/debian", func() { - r.Get("/repository.key", debian.GetRepositoryKey) + r.Group("/repository.key", func() { + r.Head("", debian.GetRepositoryKey) + r.Get("", debian.GetRepositoryKey) + }) r.Group("/dists/{distribution}", func() { r.Get("/{filename}", debian.GetRepositoryFile) + r.Head("/{filename}", debian.CheckRepositoryFileExistence) r.Get("/by-hash/{algorithm}/{hash}", debian.GetRepositoryFileByHash) r.Group("/{component}/{architecture}", func() { + r.Head("/{filename}", debian.CheckRepositoryFileExistence) r.Get("/{filename}", debian.GetRepositoryFile) r.Get("/by-hash/{algorithm}/{hash}", debian.GetRepositoryFileByHash) }) diff --git a/routers/api/packages/debian/debian.go b/routers/api/packages/debian/debian.go index dbab9d9ee6..19213c6e41 100644 --- a/routers/api/packages/debian/debian.go +++ b/routers/api/packages/debian/debian.go @@ -29,6 +29,38 @@ func apiError(ctx *context.Context, status int, obj any) { }) } +func CheckRepositoryFileExistence(ctx *context.Context) { + pv, err := debian_service.GetOrCreateRepositoryVersion(ctx, ctx.Package.Owner.ID) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + key := ctx.Params("distribution") + + component := ctx.Params("component") + architecture := strings.TrimPrefix(ctx.Params("architecture"), "binary-") + if component != "" && architecture != "" { + key += "|" + component + "|" + architecture + } + + pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), key) + if err != nil { + if errors.Is(err, util.ErrNotExist) { + ctx.Status(http.StatusNotFound) + } else { + apiError(ctx, http.StatusInternalServerError, err) + } + return + } + + ctx.SetServeHeaders(&context.ServeHeaderOptions{ + Filename: pf.Name, + LastModified: pf.CreatedUnix.AsLocalTime(), + }) + ctx.Status(http.StatusOK) +} + func GetRepositoryKey(ctx *context.Context) { _, pub, err := debian_service.GetOrCreateKeyPair(ctx, ctx.Package.Owner.ID) if err != nil { diff --git a/tests/integration/api_packages_debian_test.go b/tests/integration/api_packages_debian_test.go index 40e20aa632..e22165c44b 100644 --- a/tests/integration/api_packages_debian_test.go +++ b/tests/integration/api_packages_debian_test.go @@ -70,7 +70,10 @@ func TestPackageDebian(t *testing.T) { t.Run("RepositoryKey", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - req := NewRequest(t, "GET", rootURL+"/repository.key") + req := NewRequest(t, "HEAD", rootURL+"/repository.key") + MakeRequest(t, req, http.StatusOK) + + req = NewRequest(t, "GET", rootURL+"/repository.key") resp := MakeRequest(t, req, http.StatusOK) assert.Equal(t, "application/pgp-keys", resp.Header().Get("Content-Type")) @@ -205,7 +208,10 @@ func TestPackageDebian(t *testing.T) { t.Run("Release", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - req := NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/Release", rootURL, distribution)) + req := NewRequest(t, "HEAD", fmt.Sprintf("%s/dists/%s/Release", rootURL, distribution)) + MakeRequest(t, req, http.StatusOK) + + req = NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/Release", rootURL, distribution)) resp := MakeRequest(t, req, http.StatusOK) body := resp.Body.String() @@ -231,6 +237,9 @@ func TestPackageDebian(t *testing.T) { assert.Contains(t, resp.Body.String(), "-----BEGIN PGP SIGNATURE-----") + req = NewRequest(t, "HEAD", fmt.Sprintf("%s/dists/%s/InRelease", rootURL, distribution)) + MakeRequest(t, req, http.StatusOK) + req = NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/InRelease", rootURL, distribution)) resp = MakeRequest(t, req, http.StatusOK)