Пример #1
0
// Write msg as error and report e to log
func Error(w http.ResponseWriter, e error, msg string) {
	if e != nil {
		log.Println("%v", e)
	}
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(500)
	if e := FlushJson(w, Reply(false, msg)); e != nil {
		panic(e)
	}
}
Пример #2
0
// 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
		}
	}
}