// Limit the amount of requests one IP can do per second. // // fillrate = Amount of requests allowed in one second // capacity = Amount of 'extra'(burst) requests a-top fillrate allowed // delay = Duration before changing http status 429 to 503 // // If the fillrate+capacity are overloaded a HTTP 429 is returned // If the callee keeps firing requests the 429 is changed into a 503 // if delay is passed. func Use(fillrate float64, capacity float64) middleware.HandlerFunc { cache = lru.New(CacheSize) // Some sanity checks on fillrate and capacity if fillrate > capacity { panic("ratelimit: fillrate must be equal to or lower than capacity") } if fillrate < 1.0 { panic("ratelimit: fillrate must be equal to or higher than 1") } // Everything is OK return func(w http.ResponseWriter, r *http.Request) bool { httpCode := check(r.RemoteAddr, fillrate, capacity) switch httpCode { case StatusRateLimit: // Ratelimit request log.Println("ratelimit: Dropped HTTP %s (IP=%s)", r.URL.String(), r.RemoteAddr) w.Header().Set("Retry-After", strconv.Itoa(Delay)) w.WriteHeader(StatusRateLimit) if e := httpd.FlushJson(w, httpd.Reply(false, StatusRateLimitText)); e != nil { httpd.Error(w, e, "Flush failed") } return false case http.StatusServiceUnavailable: // Abusive client, responding less friendly log.Println("ratelimit: Banned abusive HTTP %s (IP=%s)", r.URL.String(), r.RemoteAddr) w.Header().Set("Retry-After", strconv.Itoa(Delay)) w.WriteHeader(http.StatusServiceUnavailable) if e := httpd.FlushJson(w, httpd.Reply(false, http.StatusText(http.StatusServiceUnavailable))); e != nil { httpd.Error(w, e, "Flush failed") } return false default: return true } } }
func verbose(w http.ResponseWriter, r *http.Request) { msg := `{success: true, msg: "Set verbosity to ` if config.Verbose { config.Verbose = false msg += "OFF" } else { config.Verbose = true msg += "ON" } msg += `"}` if _, e := w.Write([]byte(msg)); e != nil { httpd.Error(w, e, "Flush failed") return } }