From 6226849735bdcb909492e518a9a6a2ac923baa19 Mon Sep 17 00:00:00 2001 From: Christopher Grebs Date: Mon, 12 Aug 2019 20:36:05 +0200 Subject: [PATCH] Handle 'None' return value of wait() properly during throttling. (#6837) --- rest_framework/views.py | 10 +++++++++- tests/test_throttling.py | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/rest_framework/views.py b/rest_framework/views.py index 832f1723309..bec10560a93 100644 --- a/rest_framework/views.py +++ b/rest_framework/views.py @@ -356,7 +356,15 @@ def check_throttles(self, request): throttle_durations.append(throttle.wait()) if throttle_durations: - self.throttled(request, max(throttle_durations)) + # Filter out `None` values which may happen in case of config / rate + # changes, see #1438 + durations = [ + duration for duration in throttle_durations + if duration is not None + ] + + duration = max(durations, default=None) + self.throttled(request, duration) def determine_version(self, request, *args, **kwargs): """ diff --git a/tests/test_throttling.py b/tests/test_throttling.py index 3c172e2636e..d5a61232d92 100644 --- a/tests/test_throttling.py +++ b/tests/test_throttling.py @@ -159,6 +159,27 @@ def test_request_throttling_multiple_throttles(self): assert response.status_code == 429 assert int(response['retry-after']) == 58 + def test_throttle_rate_change_negative(self): + self.set_throttle_timer(MockView_DoubleThrottling, 0) + request = self.factory.get('/') + for dummy in range(24): + response = MockView_DoubleThrottling.as_view()(request) + assert response.status_code == 429 + assert int(response['retry-after']) == 60 + + previous_rate = User3SecRateThrottle.rate + try: + User3SecRateThrottle.rate = '1/sec' + + for dummy in range(24): + response = MockView_DoubleThrottling.as_view()(request) + + assert response.status_code == 429 + assert int(response['retry-after']) == 60 + finally: + # reset + User3SecRateThrottle.rate = previous_rate + def ensure_response_header_contains_proper_throttle_field(self, view, expected_headers): """ Ensure the response returns an Retry-After field with status and next attributes