From 2d3a7e54186a4f4ecd494b17458cf66caee455fb Mon Sep 17 00:00:00 2001 From: Luke Faraone Date: Fri, 7 Mar 2014 10:47:30 -0500 Subject: [PATCH] Use a different status code and include seconds remaining header in ratelimits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will make it slightly easier to consume the data from our clients. Ref: RFC 6585 ยง4 (imported from commit 6d323dc25db78a6d84a163add950f039e03e73d3) --- zerver/middleware.py | 3 ++- zerver/test_external.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/zerver/middleware.py b/zerver/middleware.py index 70a1995a8f..5403cff7db 100644 --- a/zerver/middleware.py +++ b/zerver/middleware.py @@ -276,7 +276,8 @@ class RateLimitMiddleware(object): def process_exception(self, request, exception): if type(exception) == RateLimited: - resp = json_error("API usage exceeded rate limit, try again in %s secs" % (request._ratelimit_secs_to_freedom,), status=403) + resp = json_error("API usage exceeded rate limit, try again in %s secs" % (request._ratelimit_secs_to_freedom,), status=429) + resp['Retry-After'] = request._ratelimit_secs_to_freedom return resp class FlushDisplayRecipientCache(object): diff --git a/zerver/test_external.py b/zerver/test_external.py index 39e171fd5b..e1a2f466d3 100644 --- a/zerver/test_external.py +++ b/zerver/test_external.py @@ -173,10 +173,12 @@ class RateLimitTests(AuthedTestCase): for i in range(6): result = self.send_api_message(email, api_key, "some stuff %s" % (i,)) - self.assertEqual(result.status_code, 403) + self.assertEqual(result.status_code, 429) json = ujson.loads(result.content) self.assertEqual(json.get("result"), "error") self.assertIn("API usage exceeded rate limit, try again in", json.get("msg")) + self.assertTrue('Retry-After' in result) + self.assertIn(result['Retry-After'], json.get("msg")) # We actually wait a second here, rather than force-clearing our history, # to make sure the rate-limiting code automatically forgives a user