Refs #30997 -- Removed HttpRequest.is_ajax() usage.

This commit is contained in:
Claude Paroz 2019-12-15 15:30:35 +01:00 committed by Mariusz Felisiak
parent 5d654e1e71
commit 7fa0fa45c5
7 changed files with 47 additions and 30 deletions

View File

@ -48,12 +48,12 @@ def technical_500_response(request, exc_type, exc_value, tb, status_code=500):
the values returned from sys.exc_info() and friends.
"""
reporter = get_exception_reporter_class(request)(request, exc_type, exc_value, tb)
if request.is_ajax():
text = reporter.get_traceback_text()
return HttpResponse(text, status=status_code, content_type='text/plain; charset=utf-8')
else:
if request.accepts('text/html'):
html = reporter.get_traceback_html()
return HttpResponse(html, status=status_code, content_type='text/html')
else:
text = reporter.get_traceback_text()
return HttpResponse(text, status=status_code, content_type='text/plain; charset=utf-8')
@functools.lru_cache()

View File

@ -33,7 +33,7 @@ def set_language(request):
"""
next_url = request.POST.get('next', request.GET.get('next'))
if (
(next_url or not request.is_ajax()) and
(next_url or request.accepts('text/html')) and
not url_has_allowed_host_and_scheme(
url=next_url,
allowed_hosts={request.get_host()},

View File

@ -388,6 +388,11 @@ Miscellaneous
Django 3.1, the first request to any previously cached template fragment will
be a cache miss.
* The logic behind the decision to return a redirection fallback or a 204 HTTP
response from the :func:`~django.views.i18n.set_language` view is now based
on the ``Accept`` HTTP header instead of the ``X-Requested-With`` HTTP header
presence.
* The compatibility imports of ``django.core.exceptions.EmptyResultSet`` in
``django.db.models.query``, ``django.db.models.sql``, and
``django.db.models.sql.datastructures`` are removed.

View File

@ -1803,9 +1803,18 @@ redirect to that URL will be performed. Otherwise, Django may fall back to
redirecting the user to the URL from the ``Referer`` header or, if it is not
set, to ``/``, depending on the nature of the request:
* For AJAX requests, the fallback will be performed only if the ``next``
parameter was set. Otherwise a 204 status code (No Content) will be returned.
* For non-AJAX requests, the fallback will always be performed.
* If the request accepts HTML content (based on its ``Accept`` HTTP header),
the fallback will always be performed.
* If the request doesn't accept HTML, the fallback will be performed only if
the ``next`` parameter was set. Otherwise a 204 status code (No Content) will
be returned.
.. versionchanged:: 3.1
In older versions, the distinction for the fallback is based on whether the
``X-Requested-With`` header is set to the value ``XMLHttpRequest``. This is
set by the jQuery ``ajax()`` method.
Here's example HTML template code:

View File

@ -159,11 +159,11 @@ Use the ``django.test.Client`` class to make requests.
>>> c = Client()
>>> c.get('/customers/details/', {'name': 'fred', 'age': 7},
... HTTP_X_REQUESTED_WITH='XMLHttpRequest')
... HTTP_ACCEPT='application/json')
...will send the HTTP header ``HTTP_X_REQUESTED_WITH`` to the
details view, which is a good way to test code paths that use the
:meth:`django.http.HttpRequest.is_ajax()` method.
...will send the HTTP header ``HTTP_ACCEPT`` to the details view, which
is a good way to test code paths that use the
:meth:`django.http.HttpRequest.accepts()` method.
.. admonition:: CGI specification

View File

@ -1247,7 +1247,7 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin
response = self.client.get(
'/raises500/',
HTTP_SECRET_HEADER='super_secret',
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
HTTP_ACCEPT='application/json',
)
self.assertNotIn(b'super_secret', response.content)
@ -1289,17 +1289,17 @@ class CustomExceptionReporterFilterTests(SimpleTestCase):
)
class AjaxResponseExceptionReporterFilter(ExceptionReportTestMixin, LoggingCaptureMixin, SimpleTestCase):
class NonHTMLResponseExceptionReporterFilter(ExceptionReportTestMixin, LoggingCaptureMixin, SimpleTestCase):
"""
Sensitive information can be filtered out of error reports.
Here we specifically test the plain text 500 debug-only error page served
when it has been detected the request was sent by JS code. We don't check
for (non)existence of frames vars in the traceback information section of
the response content because we don't include them in these error pages.
The plain text 500 debug-only error page is served when it has been
detected the request doesn't accept HTML content. Don't check for
(non)existence of frames vars in the traceback information section of the
response content because they're not included in these error pages.
Refs #14614.
"""
rf = RequestFactory(HTTP_X_REQUESTED_WITH='XMLHttpRequest')
rf = RequestFactory(HTTP_ACCEPT='application/json')
def test_non_sensitive_request(self):
"""
@ -1346,8 +1346,8 @@ class AjaxResponseExceptionReporterFilter(ExceptionReportTestMixin, LoggingCaptu
self.verify_unsafe_response(custom_exception_reporter_filter_view, check_for_vars=False)
@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls')
def test_ajax_response_encoding(self):
response = self.client.get('/raises500/', HTTP_X_REQUESTED_WITH='XMLHttpRequest')
def test_non_html_response_encoding(self):
response = self.client.get('/raises500/', HTTP_ACCEPT='application/json')
self.assertEqual(response['Content-Type'], 'text/plain; charset=utf-8')

View File

@ -111,11 +111,12 @@ class SetLanguageTests(TestCase):
def test_setlang_performs_redirect_for_ajax_if_explicitly_requested(self):
"""
The set_language view redirects to the "next" parameter for AJAX calls.
The set_language view redirects to the "next" parameter for requests
not accepting HTML response content.
"""
lang_code = self._get_inactive_language_code()
post_data = {'language': lang_code, 'next': '/'}
response = self.client.post('/i18n/setlang/', post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
response = self.client.post('/i18n/setlang/', post_data, HTTP_ACCEPT='application/json')
self.assertRedirects(response, '/')
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
with ignore_warnings(category=RemovedInDjango40Warning):
@ -123,12 +124,12 @@ class SetLanguageTests(TestCase):
def test_setlang_doesnt_perform_a_redirect_to_referer_for_ajax(self):
"""
The set_language view doesn't redirect to the HTTP referer header for
AJAX calls.
The set_language view doesn't redirect to the HTTP referer header if
the request doesn't accept HTML response content.
"""
lang_code = self._get_inactive_language_code()
post_data = {'language': lang_code}
headers = {'HTTP_REFERER': '/', 'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'}
headers = {'HTTP_REFERER': '/', 'HTTP_ACCEPT': 'application/json'}
response = self.client.post('/i18n/setlang/', post_data, **headers)
self.assertEqual(response.status_code, 204)
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
@ -137,11 +138,12 @@ class SetLanguageTests(TestCase):
def test_setlang_doesnt_perform_a_default_redirect_for_ajax(self):
"""
The set_language view returns 204 for AJAX calls by default.
The set_language view returns 204 by default for requests not accepting
HTML response content.
"""
lang_code = self._get_inactive_language_code()
post_data = {'language': lang_code}
response = self.client.post('/i18n/setlang/', post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
response = self.client.post('/i18n/setlang/', post_data, HTTP_ACCEPT='application/json')
self.assertEqual(response.status_code, 204)
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
with ignore_warnings(category=RemovedInDjango40Warning):
@ -149,11 +151,12 @@ class SetLanguageTests(TestCase):
def test_setlang_unsafe_next_for_ajax(self):
"""
The fallback to root URL for the set_language view works for AJAX calls.
The fallback to root URL for the set_language view works for requests
not accepting HTML response content.
"""
lang_code = self._get_inactive_language_code()
post_data = {'language': lang_code, 'next': '//unsafe/redirection/'}
response = self.client.post('/i18n/setlang/', post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
response = self.client.post('/i18n/setlang/', post_data, HTTP_ACCEPT='application/json')
self.assertEqual(response.url, '/')
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)