Skip to content

Instantly share code, notes, and snippets.

@mikesname
Created August 20, 2015 20:14
Show Gist options
  • Save mikesname/5f1fa856ecc772eaac08 to your computer and use it in GitHub Desktop.
Save mikesname/5f1fa856ecc772eaac08 to your computer and use it in GitHub Desktop.
An extremely naive (doesn't properly handle concurrent accesses) rate limited action builder for POST requests.
trait RateLimitingController {
this: Controller with ControllerHelpers =>
// Abstract cache member
def cache: play.api.cache.CacheApi
// Function to check if current IP exceeds limit for request path
def checkRateLimit[A](implicit request: Request[A]): Boolean = {
val limit: Int = getConfigInt("ratelimit.limit")
val timeoutSecs: Int = getConfigInt("ratelimit.timeout")
val ip = getRemoteIp(request)
val key = request.path + ip
val duration: FiniteDuration = Duration(timeoutSecs, TimeUnit.SECONDS)
val count = cache.get(key).getOrElse(0)
if (count < limit) {
cache.set(key, count + 1, duration)
true
} else {
Logger.warn(s"Rate limit refusal for IP $ip at ${request.path}")
false
}
}
// Action builder for rate-limited actions
def RateLimit = new ActionBuilder[Request] {
override def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]): Future[Result] = {
if (request.method != "POST") block(request)
else {
if (checkRateLimit(request)) block(request)
else immediate(TooManyRequest(rateLimitError(request)))
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment