Per-client request rate limits over a minute, an hour and a day (closes #43)
check / check (push) Successful in 3m32s

Each client, one IPv4 address or one IPv6 /64, has its requests counted
in two buckets per window, the earlier weighted by how much of it the
window still covers, in a table of at most 20,000 clients that drops the
least recently seen. A request over SWWAF_RATE_LIMIT_PER_MINUTE, _HOUR or
_DAY (1000, 10000, 50000, or off) gets 429 before anything reaches the
app, and refused requests count. The log line gains limit_hit and the
action rate_limited. The rate limits run before the announced-size
check, so a request refused with 413 is counted too.

Deviation from SPEC.md, per the issue: the 20,000 bound and the /64 are fixed, not settings.
Judgement call: golang-lru/v2 holds the table; httprate is not used, as it reads the wall clock and does not count refused requests.
Deviation: go.mod and go.sum were written by hand from the Go checksum database, as no make target runs go mod tidy.

Model: opus-5-5
This commit is contained in:
2026-10-04 01:23:42 +00:00
parent bedd324f3c
commit a2aba8f48a
15 changed files with 507 additions and 28 deletions
+3 -1
View File
@@ -49,7 +49,9 @@ func TestWriteWritesOneJSONLineMarkedRequest(t *testing.T) {
}
}
unset := []string{"upstream_status", "aborted", "duration_upstream_total"}
unset := []string{
"upstream_status", "limit_hit", "aborted", "duration_upstream_total",
}
for _, name := range unset {
_, present := fields[name]
if present {