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