Refs #30997 -- Removed HttpRequest.is_ajax() usage.
This commit is contained in:
parent
5d654e1e71
commit
7fa0fa45c5
|
@ -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.
|
the values returned from sys.exc_info() and friends.
|
||||||
"""
|
"""
|
||||||
reporter = get_exception_reporter_class(request)(request, exc_type, exc_value, tb)
|
reporter = get_exception_reporter_class(request)(request, exc_type, exc_value, tb)
|
||||||
if request.is_ajax():
|
if request.accepts('text/html'):
|
||||||
text = reporter.get_traceback_text()
|
|
||||||
return HttpResponse(text, status=status_code, content_type='text/plain; charset=utf-8')
|
|
||||||
else:
|
|
||||||
html = reporter.get_traceback_html()
|
html = reporter.get_traceback_html()
|
||||||
return HttpResponse(html, status=status_code, content_type='text/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()
|
@functools.lru_cache()
|
||||||
|
|
|
@ -33,7 +33,7 @@ def set_language(request):
|
||||||
"""
|
"""
|
||||||
next_url = request.POST.get('next', request.GET.get('next'))
|
next_url = request.POST.get('next', request.GET.get('next'))
|
||||||
if (
|
if (
|
||||||
(next_url or not request.is_ajax()) and
|
(next_url or request.accepts('text/html')) and
|
||||||
not url_has_allowed_host_and_scheme(
|
not url_has_allowed_host_and_scheme(
|
||||||
url=next_url,
|
url=next_url,
|
||||||
allowed_hosts={request.get_host()},
|
allowed_hosts={request.get_host()},
|
||||||
|
|
|
@ -388,6 +388,11 @@ Miscellaneous
|
||||||
Django 3.1, the first request to any previously cached template fragment will
|
Django 3.1, the first request to any previously cached template fragment will
|
||||||
be a cache miss.
|
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
|
* The compatibility imports of ``django.core.exceptions.EmptyResultSet`` in
|
||||||
``django.db.models.query``, ``django.db.models.sql``, and
|
``django.db.models.query``, ``django.db.models.sql``, and
|
||||||
``django.db.models.sql.datastructures`` are removed.
|
``django.db.models.sql.datastructures`` are removed.
|
||||||
|
|
|
@ -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
|
redirecting the user to the URL from the ``Referer`` header or, if it is not
|
||||||
set, to ``/``, depending on the nature of the request:
|
set, to ``/``, depending on the nature of the request:
|
||||||
|
|
||||||
* For AJAX requests, the fallback will be performed only if the ``next``
|
* If the request accepts HTML content (based on its ``Accept`` HTTP header),
|
||||||
parameter was set. Otherwise a 204 status code (No Content) will be returned.
|
the fallback will always be performed.
|
||||||
* For non-AJAX requests, 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:
|
Here's example HTML template code:
|
||||||
|
|
||||||
|
|
|
@ -159,11 +159,11 @@ Use the ``django.test.Client`` class to make requests.
|
||||||
|
|
||||||
>>> c = Client()
|
>>> c = Client()
|
||||||
>>> c.get('/customers/details/', {'name': 'fred', 'age': 7},
|
>>> 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
|
...will send the HTTP header ``HTTP_ACCEPT`` to the details view, which
|
||||||
details view, which is a good way to test code paths that use the
|
is a good way to test code paths that use the
|
||||||
:meth:`django.http.HttpRequest.is_ajax()` method.
|
:meth:`django.http.HttpRequest.accepts()` method.
|
||||||
|
|
||||||
.. admonition:: CGI specification
|
.. admonition:: CGI specification
|
||||||
|
|
||||||
|
|
|
@ -1247,7 +1247,7 @@ class ExceptionReporterFilterTests(ExceptionReportTestMixin, LoggingCaptureMixin
|
||||||
response = self.client.get(
|
response = self.client.get(
|
||||||
'/raises500/',
|
'/raises500/',
|
||||||
HTTP_SECRET_HEADER='super_secret',
|
HTTP_SECRET_HEADER='super_secret',
|
||||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
HTTP_ACCEPT='application/json',
|
||||||
)
|
)
|
||||||
self.assertNotIn(b'super_secret', response.content)
|
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.
|
Sensitive information can be filtered out of error reports.
|
||||||
|
|
||||||
Here we specifically test the plain text 500 debug-only error page served
|
The plain text 500 debug-only error page is served when it has been
|
||||||
when it has been detected the request was sent by JS code. We don't check
|
detected the request doesn't accept HTML content. Don't check for
|
||||||
for (non)existence of frames vars in the traceback information section of
|
(non)existence of frames vars in the traceback information section of the
|
||||||
the response content because we don't include them in these error pages.
|
response content because they're not included in these error pages.
|
||||||
Refs #14614.
|
Refs #14614.
|
||||||
"""
|
"""
|
||||||
rf = RequestFactory(HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
rf = RequestFactory(HTTP_ACCEPT='application/json')
|
||||||
|
|
||||||
def test_non_sensitive_request(self):
|
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)
|
self.verify_unsafe_response(custom_exception_reporter_filter_view, check_for_vars=False)
|
||||||
|
|
||||||
@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls')
|
@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls')
|
||||||
def test_ajax_response_encoding(self):
|
def test_non_html_response_encoding(self):
|
||||||
response = self.client.get('/raises500/', HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
response = self.client.get('/raises500/', HTTP_ACCEPT='application/json')
|
||||||
self.assertEqual(response['Content-Type'], 'text/plain; charset=utf-8')
|
self.assertEqual(response['Content-Type'], 'text/plain; charset=utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -111,11 +111,12 @@ class SetLanguageTests(TestCase):
|
||||||
|
|
||||||
def test_setlang_performs_redirect_for_ajax_if_explicitly_requested(self):
|
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()
|
lang_code = self._get_inactive_language_code()
|
||||||
post_data = {'language': lang_code, 'next': '/'}
|
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.assertRedirects(response, '/')
|
||||||
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
|
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
|
||||||
with ignore_warnings(category=RemovedInDjango40Warning):
|
with ignore_warnings(category=RemovedInDjango40Warning):
|
||||||
|
@ -123,12 +124,12 @@ class SetLanguageTests(TestCase):
|
||||||
|
|
||||||
def test_setlang_doesnt_perform_a_redirect_to_referer_for_ajax(self):
|
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
|
The set_language view doesn't redirect to the HTTP referer header if
|
||||||
AJAX calls.
|
the request doesn't accept HTML response content.
|
||||||
"""
|
"""
|
||||||
lang_code = self._get_inactive_language_code()
|
lang_code = self._get_inactive_language_code()
|
||||||
post_data = {'language': lang_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)
|
response = self.client.post('/i18n/setlang/', post_data, **headers)
|
||||||
self.assertEqual(response.status_code, 204)
|
self.assertEqual(response.status_code, 204)
|
||||||
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
|
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):
|
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()
|
lang_code = self._get_inactive_language_code()
|
||||||
post_data = {'language': lang_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(response.status_code, 204)
|
||||||
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
|
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
|
||||||
with ignore_warnings(category=RemovedInDjango40Warning):
|
with ignore_warnings(category=RemovedInDjango40Warning):
|
||||||
|
@ -149,11 +151,12 @@ class SetLanguageTests(TestCase):
|
||||||
|
|
||||||
def test_setlang_unsafe_next_for_ajax(self):
|
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()
|
lang_code = self._get_inactive_language_code()
|
||||||
post_data = {'language': lang_code, 'next': '//unsafe/redirection/'}
|
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(response.url, '/')
|
||||||
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
|
self.assertEqual(self.client.cookies[settings.LANGUAGE_COOKIE_NAME].value, lang_code)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue