in lib/limit.go [433:494]
func limitPolicy(h http.Header, prefix string, canonical, delta bool, window time.Duration, burst int) map[string]interface{} {
get := getNonCanonical
if canonical {
get = http.Header.Get
}
limitKey := prefix + "-Limit"
limit := get(h, limitKey)
remainingKey := prefix + "-Remaining"
remaining := get(h, remainingKey)
resetKey := prefix + "-Reset"
reset := get(h, resetKey)
m := map[string]interface{}{
"headers": fmt.Sprintf("%s=%q %s=%q %s=%q",
limitKey, limit, remainingKey, remaining, resetKey, reset),
}
if limit == "" || remaining == "" || reset == "" {
return m
}
lim, err := strconv.ParseFloat(limit, 64)
if err != nil {
m["error"] = err.Error()
return m
}
rem, err := strconv.ParseFloat(remaining, 64)
if err != nil {
m["error"] = err.Error()
return m
}
var (
per float64
resetTime time.Time
)
if d, err := strconv.ParseInt(reset, 10, 64); err == nil {
if delta {
per = float64(d)
resetTime = time.Now().Add(time.Duration(d) * time.Second)
} else {
resetTime = time.Unix(d, 0)
per = time.Until(resetTime).Seconds()
}
} else if t, err := time.Parse(http.TimeFormat, reset); err == nil {
per = time.Until(t).Seconds()
resetTime = t
} else if t, err := time.Parse(time.RFC1123, reset); err == nil {
per = time.Until(t).Seconds()
resetTime = t
} else {
m["error"] = fmt.Sprintf("could not parse %q as number or timestamp", reset)
return m
}
per *= window.Seconds()
m["next"] = rate.Limit(lim / window.Seconds())
m["rate"] = rate.Limit(rem / per)
if burst < 1 {
burst = 1
}
m["burst"] = burst
m["reset"] = resetTime.UTC()
return m
}