50 lines
871 B
Go
50 lines
871 B
Go
package httpserver
|
|
|
|
import (
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type rateLimiter struct {
|
|
mu sync.Mutex
|
|
window time.Duration
|
|
limit int
|
|
attempts map[string][]time.Time
|
|
}
|
|
|
|
func newRateLimiter(limit int, window time.Duration) *rateLimiter {
|
|
return &rateLimiter{
|
|
window: window,
|
|
limit: limit,
|
|
attempts: make(map[string][]time.Time),
|
|
}
|
|
}
|
|
|
|
func (l *rateLimiter) Allow(key string) bool {
|
|
now := time.Now()
|
|
cutoff := now.Add(-l.window)
|
|
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
|
|
attempts := l.attempts[key]
|
|
kept := attempts[:0]
|
|
for _, attempt := range attempts {
|
|
if attempt.After(cutoff) {
|
|
kept = append(kept, attempt)
|
|
}
|
|
}
|
|
if len(kept) >= l.limit {
|
|
l.attempts[key] = kept
|
|
return false
|
|
}
|
|
kept = append(kept, now)
|
|
l.attempts[key] = kept
|
|
return true
|
|
}
|
|
|
|
func authRateLimitKey(r *http.Request) string {
|
|
return requestIP(r) + ":" + r.URL.Path
|
|
}
|