Bug#1120493: trixie-pu: package mirrorbits/0.6-1+deb13u1
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: mirrorbits@packages.debian.org, arnaudr@kali.org
Control: affects -1 + src:mirrorbits
User: release.debian.org@packages.debian.org
Usertags: pu
[ Reason ]
Mirrorbits 0.6 was released just in time to be included in Debian
Trixie, however an important regression was discovered later on. It's
beend fixed in version 0.6.1, but that was too late for Trixie.
The regression is reported upstream at
https://github.com/etix/mirrorbits/issues/195.
This debdiff fixes it, and it also includes another minor fix from 0.6.1
(the fix is trivial, and it's really nice to have).
[ Impact ]
Without this debdiff, Mirrorbits might return HTTP code 500 in some
cases, while it should return a redirect.
[ Tests ]
Upstream unit tests were not included in the debdiff to keep it minimal,
but I ran it locally to make sure it passes.
[ Risks ]
Low risk. Mirrorbits is a leaf package. I'm the main upstream
contributor at the moment, and I authored the fixes proposed here. I
also run mirrorbits in production, so I know very well that these fixes
are welcome and well tested.
[ Checklist ]
[x] *all* changes are documented in the d/changelog
[x] I reviewed all changes and I approve them
[x] attach debdiff against the package in (old)stable
[x] the issue is verified as fixed in unstable
[ Changes ]
* Fix "Internal Server Error" regressions. Mirrorbits must redirect users to
the fallback mirror(s) if ever the database is unreachable. This was
broken in version 0.6, and fixed in 0.6.1.
* Normalize URL for fallback mirror(s), as it's done for all the other
mirrors. Fix bogus redirections if ever the fallback URL doesn't end with
a trailing slash.
[ Other info ]
Initially I wanted to ask to upload the new upstream version 0.6.1 into
Debian stable, rather than cherry-picking the patches. However I'm not a
regular of uploads in Debian stable, so I thought the release team would
prefer a minimal debdiff instead (easier to review).
This being said, I believe it would be more correct to also include
upstream unit tests associated with the regression in the debdiff,
however if I do that, I'm importing 95% of the changes in 0.6.1, so I'd
better ask to upload 0.6.1 instead.
I can still do that if you prefer, at your convenience.
Thanks
diff -Nru mirrorbits-0.6/debian/changelog mirrorbits-0.6/debian/changelog
--- mirrorbits-0.6/debian/changelog 2025-04-02 23:59:45.000000000 +0700
+++ mirrorbits-0.6/debian/changelog 2025-11-11 10:30:33.000000000 +0700
@@ -1,3 +1,14 @@
+mirrorbits (0.6-1+deb13u1) trixie; urgency=medium
+
+ * Fix "Internal Server Error" regressions. Mirrorbits must redirect users to
+ the fallback mirror(s) if ever the database is unreachable. This was
+ broken in version 0.6, and fixed in 0.6.1.
+ * Normalize URL for fallback mirror(s), as it's done for all the other
+ mirrors. Fix bogus redirections if ever the fallback URL doesn't end with
+ a trailing slash.
+
+ -- Arnaud Rebillout <arnaudr@debian.org> Tue, 11 Nov 2025 10:30:33 +0700
+
mirrorbits (0.6-1) unstable; urgency=medium
* Update watch file for tagged releases
diff -Nru mirrorbits-0.6/debian/gbp.conf mirrorbits-0.6/debian/gbp.conf
--- mirrorbits-0.6/debian/gbp.conf 2025-04-02 23:59:45.000000000 +0700
+++ mirrorbits-0.6/debian/gbp.conf 2025-11-11 10:30:33.000000000 +0700
@@ -1,6 +1,6 @@
[DEFAULT]
pristine-tar = True
-debian-branch = debian/latest
+debian-branch = debian/trixie
[pq]
patch-numbers = False
diff -Nru mirrorbits-0.6/debian/patches/config-Normalize-URL-for-fallback-mirrors-as-well.patch mirrorbits-0.6/debian/patches/config-Normalize-URL-for-fallback-mirrors-as-well.patch
--- mirrorbits-0.6/debian/patches/config-Normalize-URL-for-fallback-mirrors-as-well.patch 1970-01-01 08:00:00.000000000 +0800
+++ mirrorbits-0.6/debian/patches/config-Normalize-URL-for-fallback-mirrors-as-well.patch 2025-11-11 10:30:33.000000000 +0700
@@ -0,0 +1,64 @@
+From: Arnaud Rebillout <arnaudr@kali.org>
+Date: Wed, 28 May 2025 14:52:54 +0700
+Subject: config: Normalize URL for fallback mirrors as well
+
+The function `NormalizeURL` is used to ensure that a mirror URL ends
+with a trailing slash. It's applied when the mirror configuration is
+written to the database (cf. `setMirror` in `rpc/rpc.go`).
+
+Mirrorbits then relies on this fact when it constructs the redirect
+URLs, in `pagerenderer.go`:
+
+```
+path := strings.TrimPrefix(results.FileInfo.Path, "/")
+[...]
+http.Redirect([...], results.MirrorList[0].AbsoluteURL+path, http.StatusFound)
+```
+
+However, it turns out that `NormalizeURL` is not applied to the fallback
+URLs. Meaning that if your fallback is `http://mirror.org` and you
+request the file `foobar`, and if ever the fallback mechanism kicks in,
+mirrorbits will happily redirect you to `http://mirror.orgfoobar`...
+
+Easy to fix! One less papercut!
+
+Note that, in order to keep changes minimal, we duplicate the function
+NormalizeURL (defined in utils/utils.go) into config/config.go.
+---
+ config/config.go | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/config/config.go b/config/config.go
+index 9f52051..be52c10 100644
+--- a/config/config.go
++++ b/config/config.go
+@@ -8,6 +8,7 @@ import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
++ "strings"
+ "sync"
+
+ "github.com/etix/mirrorbits/core"
+@@ -175,6 +176,9 @@ func ReloadConfig() error {
+ if c.RepositoryScanInterval < 0 {
+ c.RepositoryScanInterval = 0
+ }
++ for i := range c.Fallbacks {
++ c.Fallbacks[i].URL = normalizeURL(c.Fallbacks[i].URL)
++ }
+ for _, rule := range c.AllowOutdatedFiles {
+ if len(rule.Prefix) > 0 && rule.Prefix[0] != '/' {
+ return fmt.Errorf("AllowOutdatedFiles.Prefix must start with '/'")
+@@ -272,3 +276,11 @@ func isInSlice(a string, list []string) bool {
+ }
+ return false
+ }
++
++//DUPLICATE
++func normalizeURL(url string) string {
++ if url != "" && !strings.HasSuffix(url, "/") {
++ url += "/"
++ }
++ return url
++}
diff -Nru mirrorbits-0.6/debian/patches/http-Fix-Internal-Server-Error-regressions.patch mirrorbits-0.6/debian/patches/http-Fix-Internal-Server-Error-regressions.patch
--- mirrorbits-0.6/debian/patches/http-Fix-Internal-Server-Error-regressions.patch 1970-01-01 08:00:00.000000000 +0800
+++ mirrorbits-0.6/debian/patches/http-Fix-Internal-Server-Error-regressions.patch 2025-11-11 10:30:33.000000000 +0700
@@ -0,0 +1,73 @@
+From: Arnaud Rebillout <arnaudr@kali.org>
+Date: Wed, 4 Jun 2025 15:28:02 +0700
+Subject: http: Fix "Internal Server Error" regressions
+
+If the database is not reachable for some reason, mirrorbits must not
+return "500 Internal Server Error", instead it must redirect users to
+the fallback mirror(s).
+
+This was broken in ed1db9e9cadce5fa183b3dae3c7850beb0452455, here's the
+fix.
+
+Closes: #195
+---
+ http/http.go | 7 +++----
+ http/selection.go | 11 +++++++++++
+ 2 files changed, 14 insertions(+), 4 deletions(-)
+
+diff --git a/http/http.go b/http/http.go
+index 13382b5..88f205f 100644
+--- a/http/http.go
++++ b/http/http.go
+@@ -333,12 +333,11 @@ func (h *HTTP) mirrorHandler(w http.ResponseWriter, r *http.Request, ctx *Contex
+ return
+ }
+
+- // Get details about the requested file
++ // Get details about the requested file. Errors are not fatal, and
++ // expected when the database is not ready: fallbacks will handle it.
+ fileInfo, err := h.cache.GetFileInfo(urlPath)
+ if err != nil {
+- log.Errorf("Error while fetching Fileinfo: %s", err.Error())
+- http.Error(w, err.Error(), http.StatusInternalServerError)
+- return
++ //log.Debugf("Error while fetching Fileinfo: %s", err.Error())
+ }
+
+ if checkIfModifiedSince(r, fileInfo.ModTime) == condFalse {
+diff --git a/http/selection.go b/http/selection.go
+index bbd3d9e..7e33cf8 100644
+--- a/http/selection.go
++++ b/http/selection.go
+@@ -4,6 +4,7 @@
+ package http
+
+ import (
++ "errors"
+ "fmt"
+ "math"
+ "math/rand"
+@@ -18,6 +19,10 @@ import (
+ "github.com/etix/mirrorbits/utils"
+ )
+
++var (
++ ErrInvalidFileInfo = errors.New("Invalid file info (modtime is zero)")
++)
++
+ type mirrorSelection interface {
+ // Selection must return an ordered list of selected mirror,
+ // a list of rejected mirrors and and an error code.
+@@ -29,6 +34,12 @@ type DefaultEngine struct{}
+
+ // Selection returns an ordered list of selected mirror, a list of rejected mirrors and and an error code
+ func (h DefaultEngine) Selection(ctx *Context, cache *mirrors.Cache, fileInfo *filesystem.FileInfo, clientInfo network.GeoIPRecord) (mlist mirrors.Mirrors, excluded mirrors.Mirrors, err error) {
++ // Bail out early if we don't have valid file details
++ if fileInfo.ModTime.IsZero() {
++ err = ErrInvalidFileInfo
++ return
++ }
++
+ // Prepare and return the list of all potential mirrors
+ mlist, err = cache.GetMirrors(fileInfo.Path, clientInfo)
+ if err != nil {
diff -Nru mirrorbits-0.6/debian/patches/series mirrorbits-0.6/debian/patches/series
--- mirrorbits-0.6/debian/patches/series 2025-04-02 23:59:45.000000000 +0700
+++ mirrorbits-0.6/debian/patches/series 2025-11-11 10:30:33.000000000 +0700
@@ -1,2 +1,4 @@
Adjust-mirrorbits.conf-for-Debian.patch
set-proto-package-name.patch
+http-Fix-Internal-Server-Error-regressions.patch
+config-Normalize-URL-for-fallback-mirrors-as-well.patch
Reply to: