fix: a URL rule's address is capped at 2048 bytes (WR-23)
Rule.Problems had no length check, so a long address reached the (url, match) UNIQUE btree index and failed with a 500. It now refuses an address over models.MaxRuleURL with rules.url_invalid, like redirect sources.
This commit is contained in:
10
mcp_test.go
10
mcp_test.go
@@ -268,6 +268,16 @@ func TestManagementAPI(t *testing.T) {
|
||||
t.Fatalf("set_url_seo locale pl = %v", got)
|
||||
}
|
||||
|
||||
// A rule address is capped like a redirect source, so a long one is a
|
||||
// field refusal, not a database error from the unique index (WR-23).
|
||||
long := "/" + strings.Repeat("x", 3000)
|
||||
if rec := env.mcp(t, http.MethodPost, "/_seo/api/v1/rules", agent, map[string]any{"url": long, "title": "Long"}); rec.Code != http.StatusUnprocessableEntity || !strings.Contains(rec.Body.String(), `"url"`) {
|
||||
t.Fatalf("create_rule with a 3001-byte url = %d %s, want 422 on url", rec.Code, rec.Body.String())
|
||||
}
|
||||
if rec := env.mcp(t, http.MethodPut, "/_seo/api/v1/seo", agent, map[string]any{"url": long, "values": map[string]any{"title": "Long"}}); rec.Code != http.StatusUnprocessableEntity {
|
||||
t.Fatalf("set_url_seo on a 3001-byte url = %d %s, want 422", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
// URL rules.
|
||||
rule := env.mcpExpect(t, http.StatusCreated, http.MethodPost, "/_seo/api/v1/rules", agent, map[string]any{"url": "/blog?tag=*", "match": "pattern", "robots": "noindex"})
|
||||
data, _ := rule["data"].(map[string]any)
|
||||
|
||||
@@ -96,14 +96,20 @@ func NormalizeMatch(m string) string {
|
||||
return MatchExact
|
||||
}
|
||||
|
||||
// Problems refuses an address that does not start with "/" or carries * in
|
||||
// an exact rule, and an address and match another rule already has (db is
|
||||
// the save transaction; nil skips the uniqueness check).
|
||||
// MaxRuleURL caps a URL rule's address in bytes, like MaxRedirectURL: the
|
||||
// (url, match) UNIQUE btree index refuses rows over about 2.7 KB with a
|
||||
// database error (WR-23).
|
||||
const MaxRuleURL = 2048
|
||||
|
||||
// Problems refuses an address that does not start with "/", is longer than
|
||||
// MaxRuleURL or carries * in an exact rule, and an address and match
|
||||
// another rule already has (db is the save transaction; nil skips the
|
||||
// uniqueness check).
|
||||
func (r Rule) Problems(db *gorm.DB) map[string][]Problem {
|
||||
out := map[string][]Problem{}
|
||||
url := strings.TrimSpace(r.URL)
|
||||
match := NormalizeMatch(r.Match)
|
||||
if !strings.HasPrefix(url, "/") || strings.HasPrefix(url, "//") || strings.ContainsAny(url, " \t\r\n") || (match == MatchExact && strings.Contains(url, "*")) {
|
||||
if len(url) > MaxRuleURL || !strings.HasPrefix(url, "/") || strings.HasPrefix(url, "//") || strings.ContainsAny(url, " \t\r\n") || (match == MatchExact && strings.Contains(url, "*")) {
|
||||
out["url"] = []Problem{{Key: errRuleURLInvalid}}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user