Merge pull request #26441 from edx/feanil/make_rate_limit_errors_429s

Make rate limit errors 429s instead of 403s
This commit is contained in:
Feanil Patel
2021-02-09 15:07:22 -05:00
committed by GitHub
5 changed files with 58 additions and 3 deletions

View File

@@ -2805,7 +2805,7 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
# other users of the lms.
with freeze_time(base_time + datetime.timedelta(minutes=1)):
response = self.client.post(url, {})
assert response.status_code == 403
assert response.status_code == 429
with freeze_time(base_time + datetime.timedelta(minutes=5)):
response = self.client.post(url, {})

View File

@@ -9,11 +9,13 @@
import mimetypes
from django.conf import settings
from django.http import Http404, HttpResponseNotFound, HttpResponseServerError
from django.http import Http404, HttpResponse, HttpResponseNotFound, HttpResponseServerError
from django.shortcuts import redirect
from django.template import TemplateDoesNotExist
from django.utils.safestring import mark_safe
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.defaults import permission_denied
from ratelimit.exceptions import Ratelimited
from mako.exceptions import TopLevelLookupException
from common.djangoapps.edxmako.shortcuts import render_to_response, render_to_string
@@ -92,12 +94,32 @@ def render_press_release(request, slug):
return resp
@fix_crum_request
def render_403(request, exception=None):
"""
Render the permission_denied template unless it's a ratelimit exception in which case use the rate limit template.
"""
if isinstance(exception, Ratelimited):
return render_429(request, exception)
return permission_denied(request, exception)
@fix_crum_request
def render_404(request, exception): # lint-amnesty, pylint: disable=unused-argument
request.view_name = '404'
return HttpResponseNotFound(render_to_string('static_templates/404.html', {}, request=request))
@fix_crum_request
def render_429(request, exception=None): # lint-amnesty, pylint: disable=unused-argument
"""
Render the rate limit template as an HttpResponse.
"""
request.view_name = '429'
return HttpResponse(render_to_string('static_templates/429.html', {}, request=request), status=429)
@fix_crum_request
def render_500(request):
return HttpResponseServerError(render_to_string('static_templates/server-error.html', {}, request=request))

View File

@@ -0,0 +1,26 @@
<%page expression_filter="h"/>
<%namespace name='static' file='../static_content.html'/>
<%!
from django.utils.translation import ugettext as _
from openedx.core.djangolib.markup import HTML, Text
%>
<%inherit file="../main.html" />
<%block name="pagetitle">${_("Too Many Requests")}</%block>
<main id="main" aria-label="Content" tabindex="-1">
<section class="outside-app">
<h1>
<%block name="pageheader">${page_header or _("Too Many Requests")}</%block>
</h1>
<p>
<%block name="pagecontent">
% if page_content:
${page_content}
% else:
${Text(_('Your request has been rate-limited. Please try again later.'))}
% endif
</%block>
</p>
</section>
</main>

View File

@@ -7,6 +7,7 @@ from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.contrib.admin import autodiscover as django_autodiscover
from django.urls import path
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import RedirectView
from edx_api_doc_tools import make_docs_urls
@@ -69,7 +70,9 @@ if settings.DEBUG or settings.FEATURES.get('ENABLE_DJANGO_ADMIN_SITE'):
# Custom error pages
# These are used by Django to render these error codes. Do not remove.
# pylint: disable=invalid-name
handler403 = static_template_view_views.render_403
handler404 = static_template_view_views.render_404
handler429 = static_template_view_views.render_429
handler500 = static_template_view_views.render_500
notification_prefs_urls = [
@@ -198,6 +201,10 @@ urlpatterns = [
),
url(r'^api/discounts/', include(('openedx.features.discounts.urls', 'openedx.features.discounts'),
namespace='api_discounts')),
path('403', handler403),
path('404', handler404),
path('429', handler429),
path('500', handler500),
]
if settings.FEATURES.get('ENABLE_MOBILE_REST_API'):

View File

@@ -137,7 +137,7 @@ class LoginAndRegistrationTest(ThirdPartyAuthTestMixin, UrlResetMixin, ModuleSto
# then the rate limiter should kick in and give a HttpForbidden response
response = self.client.get(login_url)
self.assertEqual(response.status_code, 403)
self.assertEqual(response.status_code, 429)
# now reset the time to 6 mins from now in future in order to unblock
reset_time = datetime.now(UTC) + timedelta(seconds=361)