From b8373b0afcac275546ac0b0b9dc7b9c0256badd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Roth?= Date: Mon, 25 May 2026 17:22:24 +0000 Subject: [PATCH] fix: capture gin context params before async task closure The gin context (c) may be recycled after the HTTP handler returns 202 for async tasks. Accessing c.Params.ByName() inside the task closure returns an empty string, causing 'mirror with name not found' errors. Capture the URL :name parameter into a local variable before the closure so it is safely captured by value. Affected endpoints: - PUT /api/mirrors/:name (apiMirrorsUpdate) - POST/DELETE /api/repos/:name/packages (apiReposPackagesAddDelete) --- api/mirror.go | 7 ++++--- api/repos.go | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/api/mirror.go b/api/mirror.go index 7e46b5b4..e30c9afc 100644 --- a/api/mirror.go +++ b/api/mirror.go @@ -548,7 +548,8 @@ func apiMirrorsUpdate(c *gin.Context) { collectionFactory := context.NewCollectionFactory() collection := collectionFactory.RemoteRepoCollection() - remote, err = collection.ByName(c.Params.ByName("name")) + name := c.Params.ByName("name") + remote, err = collection.ByName(name) if err != nil { AbortWithJSONError(c, 404, err) return @@ -584,8 +585,8 @@ func apiMirrorsUpdate(c *gin.Context) { taskCollectionFactory := context.NewCollectionFactory() taskCollection := taskCollectionFactory.RemoteRepoCollection() - // Fresh load after lock acquired - remote, err := taskCollection.ByName(c.Params.ByName("name")) + // Fresh load after lock acquired (use captured `name` variable, not gin context) + remote, err := taskCollection.ByName(name) if err != nil { return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to update: %s", err) } diff --git a/api/repos.go b/api/repos.go index 05452890..04e6f191 100644 --- a/api/repos.go +++ b/api/repos.go @@ -419,7 +419,8 @@ func apiReposPackagesAddDelete(c *gin.Context, taskNamePrefix string, cb func(li collectionFactory := context.NewCollectionFactory() collection := collectionFactory.LocalRepoCollection() - repo, err := collection.ByName(c.Params.ByName("name")) + name := c.Params.ByName("name") + repo, err := collection.ByName(name) if err != nil { AbortWithJSONError(c, 404, err) return @@ -432,8 +433,8 @@ func apiReposPackagesAddDelete(c *gin.Context, taskNamePrefix string, cb func(li taskCollectionFactory := context.NewCollectionFactory() taskCollection := taskCollectionFactory.LocalRepoCollection() - // Fresh load after lock acquired - repo, err := taskCollection.ByName(c.Params.ByName("name")) + // Fresh load after lock acquired (use captured `name` variable, not gin context) + repo, err := taskCollection.ByName(name) if err != nil { return &task.ProcessReturnValue{Code: http.StatusNotFound, Value: nil}, err }