Browse files

added error message and clear function

  • Loading branch information...
1 parent a148254 commit 1d34d359b2e861e047f0286c1266fd689a730442 kpd committed Dec 29, 2012
Showing with 28 additions and 3 deletions.
  1. +19 −0 README.rst
  2. +4 −0 ratelimit/backends/cachebe.py
  3. +5 −3 ratelimit/decorators.py
View
19 README.rst
@@ -28,6 +28,13 @@ sensible defaults (in *italics*).
Which HTTP field(s) to use to rate-limit. May be a string or a list. *none*
``rate``:
The number of requests per unit time allowed. *5/m*
+``error_message``:
+ Optional error message passed to the 403 exception. This will be passed.
+
+
+
+``from ratelimit.decorators import clear`` can be called to reset the limiting for a given ip=True/False, field combination. While it is in the decorator module, it is *not* a decorator.
+
Examples
@@ -69,6 +76,18 @@ Examples
# Allow 4 reqs/hour.
return HttpResponse()
+ @ratelimit(field='username')
+ def login(request):
+ # If the same username OR IP is used >5 times/min, this will be True.
+ # The `username` value will come from GET or POST, determined by the
+ # request method.
+ was_limited = getattr(request, 'limited', False)
+
+ # if user logged in OK:
+ clear(field='username')
@jsocol
jsocol added a note Jan 2, 2013

This example should be clear(request, field='username'), right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ return HttpResponse()
+
Acknowledgements
================
View
4 ratelimit/backends/cachebe.py
@@ -34,3 +34,7 @@ def count(self, request, ip=True, field=None, period=60):
def limit(self, request, ip=True, field=None, count=5):
counters = cache.get_many(self._keys(request, ip, field))
return any((v > count) for v in counters.values())
+
+ def clear(self, request, ip=True, field=None):
+ cache.delete_many(self._keys(request, ip, field))
+
View
8 ratelimit/decorators.py
@@ -34,9 +34,11 @@ def _split_rate(rate):
_backend = CacheBackend()
+def clear(request, ip=True, field=None):
+ "reset counts for these parameters"
+ _backend.clear(request, ip, field)
-
-def ratelimit(ip=True, block=False, method=['POST'], field=None, rate='5/m'):
+def ratelimit(ip=True, block=False, method=['POST'], field=None, rate='5/m', error_message=None):
def decorator(fn):
count, period = _split_rate(rate)
@@ -47,7 +49,7 @@ def _wrapped(request, *args, **kw):
_backend.count(request, ip, field, period)
if _backend.limit(request, ip, field, count):
if block:
- return HttpResponseForbidden()
+ return HttpResponseForbidden() if error_message is None else HttpResponseForbidden(error_message)
@jsocol
jsocol added a note Jan 2, 2013

I'm wondering if this should raise PermissionDenied instead, to let the normal 403 handler pick it up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
request.limited = True
return fn(request, *args, **kw)
return _wrapped

0 comments on commit 1d34d35

Please sign in to comment.