Created
August 20, 2015 20:14
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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