fix: an exact redirect with a query wins over the path-only rule (WR-08)

Match tried the path-only key before the path?query key, so a rule for
/products?id=5 never fired while /products had one.
This commit is contained in:
2026-10-27 15:25:39 +01:00
parent 3ecbd1f711
commit 58b2504fe3
3 changed files with 28 additions and 5 deletions

View File

@@ -27,6 +27,27 @@ const rdSite = "https://example.test"
// (the database writes of AddressChanged are covered by TestSlugChange301
// and TestAddressChangeFromEvent in the plugin package).
func TestRedirectGraph(t *testing.T) {
t.Run("a source with a query wins over the path-only source", func(t *testing.T) {
for _, rules := range [][]models.Redirect{
{rd(1, "/products", "/shop"), rd(2, "/products?id=5", "/shop/item-5")},
{rd(1, "/products?id=5", "/shop/item-5"), rd(2, "/products", "/shop")},
} {
set := NewRedirectSet(rules)
hit, ok, err := set.Match("/products", "id=5")
if err != nil || !ok || hit.Target != "/shop/item-5" {
t.Fatalf("rules %v: /products?id=5 = %+v, %v, %v; want /shop/item-5", rules, hit, ok, err)
}
hit, ok, err = set.Match("/products", "id=6")
if err != nil || !ok || hit.Target != "/shop" {
t.Fatalf("rules %v: /products?id=6 = %+v, %v, %v; want /shop", rules, hit, ok, err)
}
}
check, err := checkRedirectRules(rdSite, []models.Redirect{rd(1, "/products", "/shop")}, rd(0, "/products?id=5", "/shop/item-5"))
if err != nil || check.Loop || check.Chain {
t.Fatalf("check = %+v, %v", check, err)
}
})
t.Run("a chain A to B to C is a chain notice from A to C", func(t *testing.T) {
stored := []models.Redirect{rd(1, "/b", "/c")}
check, err := checkRedirectRules(rdSite, stored, rd(0, "/a", "/b"))

View File

@@ -129,13 +129,15 @@ func exactKey(source string) string {
return key
}
// exactKeys are the lookup keys a request path and query may match.
// exactKeys are the lookup keys a request path and query may match, the
// most specific first: a source with the request's query wins over the
// path-only source (WR-08).
func exactKeys(path, rawQuery string) []string {
keys := []string{strings.ToLower(trimSlash(path))}
key := strings.ToLower(trimSlash(path))
if rawQuery != "" {
keys = append(keys, keys[0]+"?"+rawQuery)
return []string{key + "?" + rawQuery, key}
}
return keys
return []string{key}
}
// exactMatches reports whether an exact rule matches the request: the