From 7016f7b37f6caae1235ef6fcfaa30658f6e6e58a Mon Sep 17 00:00:00 2001 From: Rayan Salhab Date: Sun, 3 May 2026 10:19:21 +0300 Subject: [PATCH] fix(packages): use file names for generic web downloads (#37514) Fixes #37511. Serve Generic package web asset downloads with the stored package filename Signed-off-by: cyphercodes Co-authored-by: cyphercodes Co-authored-by: wxiaoguang --- models/packages/package_file.go | 2 +- routers/web/user/package.go | 6 ++++- .../integration/api_packages_generic_test.go | 23 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/models/packages/package_file.go b/models/packages/package_file.go index 69401eee3e8..64bd08f0b21 100644 --- a/models/packages/package_file.go +++ b/models/packages/package_file.go @@ -68,7 +68,7 @@ func TryInsertFile(ctx context.Context, pf *PackageFile) (*PackageFile, error) { // GetFilesByVersionID gets all files of a version func GetFilesByVersionID(ctx context.Context, versionID int64) ([]*PackageFile, error) { pfs := make([]*PackageFile, 0, 10) - return pfs, db.GetEngine(ctx).Where("version_id = ?", versionID).Find(&pfs) + return pfs, db.GetEngine(ctx).Where("version_id = ?", versionID).OrderBy("lower_name, created_unix, id").Find(&pfs) } // GetFileForVersionByID gets a file of a version by id diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 1484ba2fdff..d25dc45ba87 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -566,7 +566,11 @@ func DownloadPackageFile(ctx *context.Context) { return } - packages_helper.ServePackageFile(ctx, s, u, pf) + packages_helper.ServePackageFile(ctx, s, u, pf, httplib.ServeHeaderOptions{ + Filename: pf.Name, + LastModified: pf.CreatedUnix.AsLocalTime(), + ContentDisposition: httplib.ContentDispositionAttachment, + }) } // ActionPackageTerraformLock locks a terraform state diff --git a/tests/integration/api_packages_generic_test.go b/tests/integration/api_packages_generic_test.go index c7eb4486d29..8ff51033c7b 100644 --- a/tests/integration/api_packages_generic_test.go +++ b/tests/integration/api_packages_generic_test.go @@ -7,7 +7,9 @@ import ( "bytes" "fmt" "io" + "mime" "net/http" + neturl "net/url" "testing" "code.gitea.io/gitea/models/packages" @@ -173,6 +175,27 @@ func TestPackageGeneric(t *testing.T) { checkDownloadCount(3) }) + + t.Run("WebAssetUsesFilename", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + pvs, err := packages.GetVersionsByPackageType(t.Context(), user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Len(t, pvs, 1) + + pfs, err := packages.GetFilesByVersionID(t.Context(), pvs[0].ID) + assert.NoError(t, err) + assert.NotEmpty(t, pfs) + + req = NewRequest(t, "GET", fmt.Sprintf("/%s/-/packages/generic/%s/%s/files/%d", user.Name, neturl.PathEscape(packageName), neturl.PathEscape(packageVersion), pfs[0].ID)) + resp = MakeRequest(t, req, http.StatusOK) + assert.Equal(t, content, resp.Body.Bytes()) + + disposition, params, err := mime.ParseMediaType(resp.Header().Get("Content-Disposition")) + assert.NoError(t, err) + assert.Equal(t, "attachment", disposition) + assert.Equal(t, pfs[0].Name, params["filename"]) + }) }) t.Run("Delete", func(t *testing.T) {