Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
808245e7d5 |
@@ -412,8 +412,9 @@ refusal comes with `SWWAF_ALLOW_NETS` in milestone 3 or later.
|
||||
the checks, passes the request to the app and the answer back with the
|
||||
standard library's `httputil.ReverseProxy` within the timeouts and size
|
||||
limits, and writes the request's log line. Its `check` method is where a
|
||||
request is refused before anything reaches the app: for a rate limit, and,
|
||||
with the rest of milestone 2, for the country lists.
|
||||
request is refused before anything reaches the app: for a rate limit, for an
|
||||
announced body over the size limit, and, with the rest of milestone 2, for the
|
||||
country lists.
|
||||
- `internal/ratelimit`: counts each client's requests and tells when one takes
|
||||
it over a rate limit.
|
||||
- `internal/requestlog`: the lines on stdout: the request log line and the
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestRateLimitRefusesWith429BeforeTheApp(t *testing.T) {
|
||||
{client, http.StatusTooManyRequests},
|
||||
{"203.0.113.10", http.StatusOK},
|
||||
{"2001:db8::1", http.StatusOK},
|
||||
{"2001:db8::ffff:2", http.StatusTooManyRequests},
|
||||
{"2001:db8::8000:0:0:1", http.StatusTooManyRequests},
|
||||
{"2001:db8:0:1::1", http.StatusOK},
|
||||
}
|
||||
|
||||
|
||||
@@ -101,9 +101,16 @@ type buckets struct {
|
||||
// under way, and those in the bucket before it weighted by how much of
|
||||
// that bucket the window still covers.
|
||||
//
|
||||
// Concurrent requests can be counted out of order, so now can be before
|
||||
// the bucket under way began; such a request is counted in that bucket.
|
||||
// Concurrent requests can be counted out of order, so now can be a moment
|
||||
// before the bucket under way began; such a request is counted in that
|
||||
// bucket. A request dated more than a second before it means the clock
|
||||
// was set back, and the buckets start afresh: otherwise the bucket before
|
||||
// would keep its full weight until the clock caught up.
|
||||
func (b *buckets) add(now time.Time, length time.Duration) float64 {
|
||||
if now.Before(b.start.Add(-time.Second)) {
|
||||
*b = buckets{}
|
||||
}
|
||||
|
||||
start := now.Truncate(length)
|
||||
if start.After(b.start) {
|
||||
if start.Equal(b.start.Add(length)) {
|
||||
|
||||
@@ -87,6 +87,48 @@ func TestRefusedRequestsCount(t *testing.T) {
|
||||
wantCount(t, limiter, within, later, "")
|
||||
}
|
||||
|
||||
func TestRequestCountedLateGoesInTheBucketUnderWay(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerMinute: limit})
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
for range limit {
|
||||
wantCount(t, limiter, client, start, "")
|
||||
}
|
||||
|
||||
// A concurrent request dated a moment before the bucket under way, but
|
||||
// counted after it began, is counted in it: 3 + 1 is over the limit.
|
||||
wantCount(t, limiter, client, start.Add(-time.Millisecond), minute)
|
||||
}
|
||||
|
||||
func TestClockSetBackStartsTheBucketsAfresh(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
limiter := ratelimit.New(ratelimit.Limits{PerHour: limit})
|
||||
client := netip.MustParsePrefix("203.0.113.9/32")
|
||||
start := midnight()
|
||||
|
||||
for range limit {
|
||||
wantCount(t, limiter, client, start, "")
|
||||
}
|
||||
|
||||
// Half an hour into the next bucket: 3 / 2 + 1 is within the limit.
|
||||
wantCount(t, limiter, client, start.Add(time.Hour+time.Hour/2), "")
|
||||
|
||||
// The clock is set back an hour. Counted in the bucket under way, the
|
||||
// next request would find the bucket before it at full weight, 3 + 2,
|
||||
// over the limit until the clock caught up. The buckets start afresh
|
||||
// instead, and the client is refused only past the limit again.
|
||||
setBack := start.Add(time.Hour / 2)
|
||||
for range limit {
|
||||
wantCount(t, limiter, client, setBack, "")
|
||||
}
|
||||
|
||||
wantCount(t, limiter, client, setBack, hour)
|
||||
}
|
||||
|
||||
func TestKeepsAtMost20000ClientsDroppingTheLeastRecentlySeen(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user