Fixed #23960 -- Removed http.fix_location_header

Thanks Carl Meyer for the report and Tim Graham for the review.
This commit is contained in:
Claude Paroz 2015-03-13 23:40:14 +01:00
parent 0339844b70
commit a0c2eb46dd
20 changed files with 127 additions and 156 deletions

View File

@ -23,7 +23,6 @@ logger = logging.getLogger('django.request')
class BaseHandler(object):
# Changes that are always applied to a response (in this order).
response_fixes = [
http.fix_location_header,
http.conditional_content_removal,
]

View File

@ -8,7 +8,7 @@ from django.http.response import (
HttpResponseNotFound, HttpResponseNotAllowed, HttpResponseGone,
HttpResponseServerError, Http404, BadHeaderError, JsonResponse,
)
from django.http.utils import fix_location_header, conditional_content_removal
from django.http.utils import conditional_content_removal
__all__ = [
'SimpleCookie', 'parse_cookie', 'HttpRequest', 'QueryDict',
@ -17,6 +17,6 @@ __all__ = [
'HttpResponsePermanentRedirect', 'HttpResponseNotModified',
'HttpResponseBadRequest', 'HttpResponseForbidden', 'HttpResponseNotFound',
'HttpResponseNotAllowed', 'HttpResponseGone', 'HttpResponseServerError',
'Http404', 'BadHeaderError', 'fix_location_header', 'JsonResponse',
'FileResponse', 'conditional_content_removal',
'Http404', 'BadHeaderError', 'JsonResponse', 'FileResponse',
'conditional_content_removal',
]

View File

@ -9,19 +9,6 @@ Functions that modify an HTTP request or response in some way.
# universally applicable.
def fix_location_header(request, response):
"""
Ensures that we always use an absolute URI in any location header in the
response. This is required by RFC 2616, section 14.30.
Code constructing response objects is free to insert relative paths, as
this function converts them to absolute paths.
"""
if 'Location' in response:
response['Location'] = request.build_absolute_uri(response['Location'])
return response
def conditional_content_removal(request, response):
"""
Removes the content of responses for HEAD requests, 1xx, 204 and 304

View File

@ -86,7 +86,7 @@ class CommonMiddleware(object):
if new_url == old_url:
# No redirects required.
return
if new_url[0]:
if new_url[0] != old_url[0]:
newurl = "%s://%s%s" % (
request.scheme,
new_url[0], urlquote(new_url[1]))

View File

@ -40,16 +40,12 @@ class LocaleMiddleware(object):
if path_valid:
script_prefix = get_script_prefix()
language_url = "%s://%s%s" % (
request.scheme,
request.get_host(),
# insert language after the script prefix and before the
# rest of the URL
request.get_full_path().replace(
script_prefix,
'%s%s/' % (script_prefix, language),
1
)
# Insert language after the script prefix and before the
# rest of the URL
language_url = request.get_full_path().replace(
script_prefix,
'%s%s/' % (script_prefix, language),
1
)
return self.response_redirect_class(language_url)

View File

@ -37,7 +37,9 @@ from django.test.utils import (
override_settings,
)
from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.deprecation import (
RemovedInDjango20Warning, RemovedInDjango21Warning,
)
from django.utils.encoding import force_text
from django.utils.six.moves.urllib.parse import (
unquote, urlparse, urlsplit, urlunsplit,
@ -249,11 +251,15 @@ class SimpleTestCase(unittest.TestCase):
TestClient to do a request (use fetch_redirect_response=False to check
such links without fetching them).
"""
if host is not None:
warnings.warn(
"The host argument is deprecated and no longer used by assertRedirects",
RemovedInDjango21Warning, stacklevel=2
)
if msg_prefix:
msg_prefix += ": "
e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url)
if hasattr(response, 'redirect_chain'):
# The request was a followed redirect
self.assertTrue(len(response.redirect_chain) > 0,
@ -295,10 +301,18 @@ class SimpleTestCase(unittest.TestCase):
" response code was %d (expected %d)" %
(path, redirect_response.status_code, target_status_code))
e_scheme = e_scheme if e_scheme else scheme or 'http'
e_netloc = e_netloc if e_netloc else host or 'testserver'
expected_url = urlunsplit((e_scheme, e_netloc, e_path, e_query,
e_fragment))
if url != expected_url:
# For temporary backwards compatibility, try to compare with a relative url
e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url)
relative_url = urlunsplit(('', '', e_path, e_query, e_fragment))
if url == relative_url:
warnings.warn(
"assertRedirects had to strip the scheme and domain from the "
"expected URL, as it was always added automatically to URLs "
"before Django 1.9. Please update your expected URLs by "
"removing the scheme and domain.",
RemovedInDjango21Warning, stacklevel=2)
expected_url = relative_url
self.assertEqual(url, expected_url,
msg_prefix + "Response redirected to '%s', expected '%s'" %

View File

@ -22,6 +22,10 @@ details on these changes.
* The ``assignment_tag`` helper will be removed.
* The ``host`` argument to ``assertsRedirects`` will be removed. The
compatibility layer which allows absolute URLs to be considered equal to
relative ones when the path is identical will also be removed.
.. _deprecation-removed-in-2.0:
2.0

View File

@ -824,8 +824,10 @@ types of HTTP responses. Like ``HttpResponse``, these subclasses live in
The first argument to the constructor is required -- the path to redirect
to. This can be a fully qualified URL
(e.g. ``'http://www.yahoo.com/search/'``) or an absolute path with no
domain (e.g. ``'/search/'``). See :class:`HttpResponse` for other optional
(e.g. ``'http://www.yahoo.com/search/'``), an absolute path with no domain
(e.g. ``'/search/'``), or even a relative path (e.g. ``'search/'``). In that
last case, the client browser will reconstruct the full URL itself
according to the current path. See :class:`HttpResponse` for other optional
constructor arguments. Note that this returns an HTTP status code 302.
.. attribute:: HttpResponseRedirect.url

View File

@ -266,6 +266,21 @@ a directory. Now, Django only silences the exception if the template source
does not exist. All other situations result in the original ``IOError`` being
raised.
HTTP redirects no longer forced to absolute URIs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Relative redirects are no longer converted to absolute URIs. :rfc:`2616`
required the ``Location`` header in redirect responses to be an absolute URI,
but it has been superseded by :rfc:`7231` which allows relative URIs in
``Location``, recognizing the actual practice of user agents, almost all of
which support them.
Consequently, the expected URLs passed to ``assertRedirects`` should generally
no longer include the scheme and domain part of the URLs. For example,
``self.assertRedirects(response, 'http://testserver/some-url/')`` should be
replaced by ``self.assertRedirects(response, '/some-url/')`` (unless the
redirection specifically contained an absolute URL, of course).
Miscellaneous
~~~~~~~~~~~~~

View File

@ -1398,7 +1398,7 @@ your test suite.
You can use this as a context manager in the same way as
:meth:`~SimpleTestCase.assertTemplateUsed`.
.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, host=None, msg_prefix='', fetch_redirect_response=True)
.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='', fetch_redirect_response=True)
Asserts that the response returned a ``status_code`` redirect status,
redirected to ``expected_url`` (including any ``GET`` data), and that the
@ -1408,14 +1408,6 @@ your test suite.
``target_status_code`` will be the url and status code for the final
point of the redirect chain.
The ``host`` argument sets a default host if ``expected_url`` doesn't
include one (e.g. ``"/bar/"``). If ``expected_url`` is an absolute URL that
includes a host (e.g. ``"http://testhost/bar/"``), the ``host`` parameter
will be ignored. Note that the test client doesn't support fetching external
URLs, but the parameter may be useful if you are testing with a custom HTTP
host (for example, initializing the test client with
``Client(HTTP_HOST="testhost")``.
If ``fetch_redirect_response`` is ``False``, the final page won't be
loaded. Since the test client can't fetch externals URLs, this is
particularly useful if ``expected_url`` isn't part of your Django app.
@ -1425,6 +1417,11 @@ your test suite.
the original request's scheme is used. If present, the scheme in
``expected_url`` is the one used to make the comparisons to.
.. deprecated:: 1.9
The ``host`` argument is deprecated, as redirections are no longer
forced to be absolute URLs.
.. method:: SimpleTestCase.assertHTMLEqual(html1, html2, msg=None)
Asserts that the strings ``html1`` and ``html2`` are equal. The comparison

View File

@ -87,7 +87,7 @@ class BasicFormTests(TestCase):
def test_post_data(self):
res = self.client.post('/contact/', {'name': "Me", 'message': "Hello"})
self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertRedirects(res, '/list/authors/')
class ModelFormMixinTests(TestCase):
@ -117,7 +117,7 @@ class CreateViewTests(TestCase):
res = self.client.post('/edit/authors/create/',
{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertRedirects(res, '/list/authors/')
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
def test_create_invalid(self):
@ -133,14 +133,14 @@ class CreateViewTests(TestCase):
{'name': 'Rene Magritte'})
self.assertEqual(res.status_code, 302)
artist = Artist.objects.get(name='Rene Magritte')
self.assertRedirects(res, 'http://testserver/detail/artist/%d/' % artist.pk)
self.assertRedirects(res, '/detail/artist/%d/' % artist.pk)
self.assertQuerysetEqual(Artist.objects.all(), ['<Artist: Rene Magritte>'])
def test_create_with_redirect(self):
res = self.client.post('/edit/authors/create/redirect/',
{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/edit/authors/create/')
self.assertRedirects(res, '/edit/authors/create/')
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
@ignore_warnings(category=RemovedInDjango20Warning)
@ -152,7 +152,7 @@ class CreateViewTests(TestCase):
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe>'])
self.assertEqual(res.status_code, 302)
pk = Author.objects.first().pk
self.assertRedirects(res, 'http://testserver/edit/author/%d/update/' % pk)
self.assertRedirects(res, '/edit/author/%d/update/' % pk)
# Also test with escaped chars in URL
res = self.client.post(
'/edit/authors/create/interpolate_redirect_nonascii/',
@ -160,7 +160,7 @@ class CreateViewTests(TestCase):
)
self.assertEqual(res.status_code, 302)
pk = Author.objects.get(name='John Doe').pk
self.assertRedirects(res, 'http://testserver/%C3%A9dit/author/{}/update/'.format(pk))
self.assertRedirects(res, '/%C3%A9dit/author/{}/update/'.format(pk))
def test_create_with_special_properties(self):
res = self.client.get('/edit/authors/create/special/')
@ -189,7 +189,7 @@ class CreateViewTests(TestCase):
res = self.client.post('/edit/authors/create/restricted/',
{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/accounts/login/?next=/edit/authors/create/restricted/')
self.assertRedirects(res, '/accounts/login/?next=/edit/authors/create/restricted/')
def test_create_view_with_restricted_fields(self):
@ -249,7 +249,7 @@ class UpdateViewTests(TestCase):
res = self.client.post('/edit/author/%d/update/' % a.pk,
{'name': 'Randall Munroe (xkcd)', 'slug': 'randall-munroe'})
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertRedirects(res, '/list/authors/')
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>'])
def test_update_invalid(self):
@ -269,7 +269,7 @@ class UpdateViewTests(TestCase):
res = self.client.post('/edit/artists/%d/update/' % a.pk,
{'name': 'Rene Magritte'})
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/detail/artist/%d/' % a.pk)
self.assertRedirects(res, '/detail/artist/%d/' % a.pk)
self.assertQuerysetEqual(Artist.objects.all(), ['<Artist: Rene Magritte>'])
def test_update_with_redirect(self):
@ -280,7 +280,7 @@ class UpdateViewTests(TestCase):
res = self.client.post('/edit/author/%d/update/redirect/' % a.pk,
{'name': 'Randall Munroe (author of xkcd)', 'slug': 'randall-munroe'})
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/edit/authors/create/')
self.assertRedirects(res, '/edit/authors/create/')
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (author of xkcd)>'])
@ignore_warnings(category=RemovedInDjango20Warning)
@ -296,7 +296,7 @@ class UpdateViewTests(TestCase):
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (author of xkcd)>'])
self.assertEqual(res.status_code, 302)
pk = Author.objects.first().pk
self.assertRedirects(res, 'http://testserver/edit/author/%d/update/' % pk)
self.assertRedirects(res, '/edit/author/%d/update/' % pk)
# Also test with escaped chars in URL
res = self.client.post(
'/edit/author/%d/update/interpolate_redirect_nonascii/' % a.pk,
@ -304,7 +304,7 @@ class UpdateViewTests(TestCase):
)
self.assertEqual(res.status_code, 302)
pk = Author.objects.get(name='John Doe').pk
self.assertRedirects(res, 'http://testserver/%C3%A9dit/author/{}/update/'.format(pk))
self.assertRedirects(res, '/%C3%A9dit/author/{}/update/'.format(pk))
def test_update_with_special_properties(self):
a = Author.objects.create(
@ -322,7 +322,7 @@ class UpdateViewTests(TestCase):
res = self.client.post('/edit/author/%d/update/special/' % a.pk,
{'name': 'Randall Munroe (author of xkcd)', 'slug': 'randall-munroe'})
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/detail/author/%d/' % a.pk)
self.assertRedirects(res, '/detail/author/%d/' % a.pk)
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (author of xkcd)>'])
def test_update_without_redirect(self):
@ -354,7 +354,7 @@ class UpdateViewTests(TestCase):
res = self.client.post('/edit/author/update/',
{'name': 'Randall Munroe (xkcd)', 'slug': 'randall-munroe'})
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertRedirects(res, '/list/authors/')
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>'])
@ -372,7 +372,7 @@ class DeleteViewTests(TestCase):
# Deletion with POST
res = self.client.post('/edit/author/%d/delete/' % a.pk)
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertRedirects(res, '/list/authors/')
self.assertQuerysetEqual(Author.objects.all(), [])
def test_delete_by_delete(self):
@ -380,14 +380,14 @@ class DeleteViewTests(TestCase):
a = Author.objects.create(**{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
res = self.client.delete('/edit/author/%d/delete/' % a.pk)
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertRedirects(res, '/list/authors/')
self.assertQuerysetEqual(Author.objects.all(), [])
def test_delete_with_redirect(self):
a = Author.objects.create(**{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
res = self.client.post('/edit/author/%d/delete/redirect/' % a.pk)
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/edit/authors/create/')
self.assertRedirects(res, '/edit/authors/create/')
self.assertQuerysetEqual(Author.objects.all(), [])
@ignore_warnings(category=RemovedInDjango20Warning)
@ -395,13 +395,13 @@ class DeleteViewTests(TestCase):
a = Author.objects.create(**{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
res = self.client.post('/edit/author/%d/delete/interpolate_redirect/' % a.pk)
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/edit/authors/create/?deleted=%d' % a.pk)
self.assertRedirects(res, '/edit/authors/create/?deleted=%d' % a.pk)
self.assertQuerysetEqual(Author.objects.all(), [])
# Also test with escaped chars in URL
a = Author.objects.create(**{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
res = self.client.post('/edit/author/{}/delete/interpolate_redirect_nonascii/'.format(a.pk))
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/%C3%A9dit/authors/create/?deleted={}'.format(a.pk))
self.assertRedirects(res, '/%C3%A9dit/authors/create/?deleted={}'.format(a.pk))
def test_delete_with_special_properties(self):
a = Author.objects.create(**{'name': 'Randall Munroe', 'slug': 'randall-munroe'})
@ -414,7 +414,7 @@ class DeleteViewTests(TestCase):
res = self.client.post('/edit/author/%d/delete/special/' % a.pk)
self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertRedirects(res, '/list/authors/')
self.assertQuerysetEqual(Author.objects.all(), [])
def test_delete_without_redirect(self):

View File

@ -3,10 +3,8 @@ from __future__ import unicode_literals
import gzip
import io
from django.http import (
HttpRequest, HttpResponse, HttpResponseRedirect, StreamingHttpResponse,
)
from django.http.utils import conditional_content_removal, fix_location_header
from django.http import HttpRequest, HttpResponse, StreamingHttpResponse
from django.http.utils import conditional_content_removal
from django.test import TestCase
@ -71,15 +69,3 @@ class HttpUtilTests(TestCase):
res = StreamingHttpResponse(['abc'])
conditional_content_removal(req, res)
self.assertEqual(b''.join(res), b'')
def test_fix_location_without_get_host(self):
"""
Tests that you can return an absolute redirect when the request
host is not in ALLOWED_HOSTS. Issue #20472
"""
request = HttpRequest()
def bomb():
self.assertTrue(False)
request.get_host = bomb
fix_location_header(request, HttpResponseRedirect('http://example.com'))

View File

@ -248,7 +248,7 @@ class URLRedirectWithoutTrailingSlashTests(URLTestCaseBase):
def test_en_redirect(self):
response = self.client.get('/account/register', HTTP_ACCEPT_LANGUAGE='en', follow=True)
# target status code of 301 because of CommonMiddleware redirecting
self.assertIn(('http://testserver/en/account/register/', 301), response.redirect_chain)
self.assertIn(('/en/account/register/', 301), response.redirect_chain)
self.assertRedirects(response, '/en/account/register/', 302)
response = self.client.get('/prefixed.xml', HTTP_ACCEPT_LANGUAGE='en', follow=True)

View File

@ -64,7 +64,7 @@ class CommonMiddlewareTest(TestCase):
request = self.rf.get('/slash')
r = CommonMiddleware().process_request(request)
self.assertEqual(r.status_code, 301)
self.assertEqual(r.url, 'http://testserver/slash/')
self.assertEqual(r.url, '/slash/')
@override_settings(APPEND_SLASH=True, DEBUG=True)
def test_append_slash_no_redirect_on_POST_in_DEBUG(self):
@ -106,7 +106,7 @@ class CommonMiddlewareTest(TestCase):
self.assertEqual(r.status_code, 301)
self.assertEqual(
r.url,
'http://testserver/needsquoting%23/')
'/needsquoting%23/')
@override_settings(APPEND_SLASH=False, PREPEND_WWW=True)
def test_prepend_www(self):
@ -174,7 +174,7 @@ class CommonMiddlewareTest(TestCase):
self.assertIsNotNone(r,
"CommonMiddlware failed to return APPEND_SLASH redirect using request.urlconf")
self.assertEqual(r.status_code, 301)
self.assertEqual(r.url, 'http://testserver/customurlconf/slash/')
self.assertEqual(r.url, '/customurlconf/slash/')
@override_settings(APPEND_SLASH=True, DEBUG=True)
def test_append_slash_no_redirect_on_POST_in_DEBUG_custom_urlconf(self):
@ -212,7 +212,7 @@ class CommonMiddlewareTest(TestCase):
self.assertEqual(r.status_code, 301)
self.assertEqual(
r.url,
'http://testserver/customurlconf/needsquoting%23/')
'/customurlconf/needsquoting%23/')
@override_settings(APPEND_SLASH=False, PREPEND_WWW=True)
def test_prepend_www_custom_urlconf(self):
@ -264,7 +264,7 @@ class CommonMiddlewareTest(TestCase):
request = self.rf.get('/slash')
r = CommonMiddleware().process_request(request)
self.assertEqual(r.status_code, 301)
self.assertEqual(r.url, 'http://testserver/slash/')
self.assertEqual(r.url, '/slash/')
self.assertIsInstance(r, HttpResponsePermanentRedirect)
def test_response_redirect_class_subclass(self):
@ -274,7 +274,7 @@ class CommonMiddlewareTest(TestCase):
request = self.rf.get('/slash')
r = MyCommonMiddleware().process_request(request)
self.assertEqual(r.status_code, 302)
self.assertEqual(r.url, 'http://testserver/slash/')
self.assertEqual(r.url, '/slash/')
self.assertIsInstance(r, HttpResponseRedirect)

View File

@ -176,40 +176,27 @@ class ClientTest(TestCase):
def test_redirect(self):
"GET a URL that redirects elsewhere"
response = self.client.get('/redirect_view/')
# Check that the response was a 302 (redirect) and that
# assertRedirect() understands to put an implicit http://testserver/ in
# front of non-absolute URLs.
# Check that the response was a 302 (redirect)
self.assertRedirects(response, '/get_view/')
host = 'django.testserver'
client_providing_host = Client(HTTP_HOST=host)
response = client_providing_host.get('/redirect_view/')
# Check that the response was a 302 (redirect) with absolute URI
self.assertRedirects(response, '/get_view/', host=host)
def test_redirect_with_query(self):
"GET a URL that redirects with given GET parameters"
response = self.client.get('/redirect_view/', {'var': 'value'})
# Check if parameters are intact
self.assertRedirects(response, 'http://testserver/get_view/?var=value')
self.assertRedirects(response, '/get_view/?var=value')
def test_permanent_redirect(self):
"GET a URL that redirects permanently elsewhere"
response = self.client.get('/permanent_redirect_view/')
# Check that the response was a 301 (permanent redirect)
self.assertRedirects(response, 'http://testserver/get_view/', status_code=301)
client_providing_host = Client(HTTP_HOST='django.testserver')
response = client_providing_host.get('/permanent_redirect_view/')
# Check that the response was a 301 (permanent redirect) with absolute URI
self.assertRedirects(response, 'http://django.testserver/get_view/', status_code=301)
self.assertRedirects(response, '/get_view/', status_code=301)
def test_temporary_redirect(self):
"GET a URL that does a non-permanent redirect"
response = self.client.get('/temporary_redirect_view/')
# Check that the response was a 302 (non-permanent redirect)
self.assertRedirects(response, 'http://testserver/get_view/', status_code=302)
self.assertRedirects(response, '/get_view/', status_code=302)
def test_redirect_to_strange_location(self):
"GET a URL that redirects to a non-200 page"
@ -217,12 +204,12 @@ class ClientTest(TestCase):
# Check that the response was a 302, and that
# the attempt to get the redirection location returned 301 when retrieved
self.assertRedirects(response, 'http://testserver/permanent_redirect_view/', target_status_code=301)
self.assertRedirects(response, '/permanent_redirect_view/', target_status_code=301)
def test_follow_redirect(self):
"A URL that redirects can be followed to termination."
response = self.client.get('/double_redirect_view/', follow=True)
self.assertRedirects(response, 'http://testserver/get_view/', status_code=302, target_status_code=200)
self.assertRedirects(response, '/get_view/', status_code=302, target_status_code=200)
self.assertEqual(len(response.redirect_chain), 2)
def test_redirect_http(self):
@ -364,7 +351,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response = self.client.get('/login_protected_view/')
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/login_protected_view/')
self.assertRedirects(response, '/accounts/login/?next=/login_protected_view/')
# Log in
login = self.client.login(username='testclient', password='password')
@ -380,7 +367,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response = self.client.get('/login_protected_method_view/')
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/login_protected_method_view/')
self.assertRedirects(response, '/accounts/login/?next=/login_protected_method_view/')
# Log in
login = self.client.login(username='testclient', password='password')
@ -396,7 +383,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response = self.client.get('/login_protected_view_custom_redirect/')
self.assertRedirects(response, 'http://testserver/accounts/login/?redirect_to=/login_protected_view_custom_redirect/')
self.assertRedirects(response, '/accounts/login/?redirect_to=/login_protected_view_custom_redirect/')
# Log in
login = self.client.login(username='testclient', password='password')
@ -434,7 +421,7 @@ class ClientTest(TestCase):
# Request a page that requires a login
response = self.client.get('/login_protected_view/')
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/login_protected_view/')
self.assertRedirects(response, '/accounts/login/?next=/login_protected_view/')
@override_settings(SESSION_ENGINE="django.contrib.sessions.backends.signed_cookies")
def test_logout_cookie_sessions(self):
@ -445,7 +432,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response = self.client.get('/permission_protected_view/')
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/permission_protected_view/')
self.assertRedirects(response, '/accounts/login/?next=/permission_protected_view/')
# Log in
login = self.client.login(username='testclient', password='password')
@ -453,7 +440,7 @@ class ClientTest(TestCase):
# Log in with wrong permissions. Should result in 302.
response = self.client.get('/permission_protected_view/')
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/permission_protected_view/')
self.assertRedirects(response, '/accounts/login/?next=/permission_protected_view/')
# TODO: Log in with right permissions and request the page again
@ -477,7 +464,7 @@ class ClientTest(TestCase):
# Get the page without logging in. Should result in 302.
response = self.client.get('/permission_protected_method_view/')
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/permission_protected_method_view/')
self.assertRedirects(response, '/accounts/login/?next=/permission_protected_method_view/')
# Log in
login = self.client.login(username='testclient', password='password')
@ -485,7 +472,7 @@ class ClientTest(TestCase):
# Log in with wrong permissions. Should result in 302.
response = self.client.get('/permission_protected_method_view/')
self.assertRedirects(response, 'http://testserver/accounts/login/?next=/permission_protected_method_view/')
self.assertRedirects(response, '/accounts/login/?next=/permission_protected_method_view/')
# TODO: Log in with right permissions and request the page again

View File

@ -18,7 +18,9 @@ from django.test import Client, TestCase, ignore_warnings, override_settings
from django.test.client import RedirectCycleError, RequestFactory, encode_file
from django.test.utils import ContextList, str_prefix
from django.utils._os import upath
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.deprecation import (
RemovedInDjango20Warning, RemovedInDjango21Warning,
)
from django.utils.translation import ugettext_lazy
from .models import CustomUser
@ -342,12 +344,12 @@ class AssertRedirectsTests(TestCase):
try:
self.assertRedirects(response, '/get_view/')
except AssertionError as e:
self.assertIn("Response redirected to 'http://testserver/get_view/?var=value', expected 'http://testserver/get_view/'", str(e))
self.assertIn("Response redirected to '/get_view/?var=value', expected '/get_view/'", str(e))
try:
self.assertRedirects(response, '/get_view/', msg_prefix='abc')
except AssertionError as e:
self.assertIn("abc: Response redirected to 'http://testserver/get_view/?var=value', expected 'http://testserver/get_view/'", str(e))
self.assertIn("abc: Response redirected to '/get_view/?var=value', expected '/get_view/'", str(e))
def test_incorrect_target(self):
"An assertion is raised if the response redirects to another target"
@ -380,7 +382,7 @@ class AssertRedirectsTests(TestCase):
status_code=302, target_status_code=200)
self.assertEqual(len(response.redirect_chain), 1)
self.assertEqual(response.redirect_chain[0], ('http://testserver/no_template_view/', 302))
self.assertEqual(response.redirect_chain[0], ('/no_template_view/', 302))
def test_multiple_redirect_chain(self):
"You can follow a redirect chain of multiple redirects"
@ -389,9 +391,9 @@ class AssertRedirectsTests(TestCase):
status_code=302, target_status_code=200)
self.assertEqual(len(response.redirect_chain), 3)
self.assertEqual(response.redirect_chain[0], ('http://testserver/redirects/further/', 302))
self.assertEqual(response.redirect_chain[1], ('http://testserver/redirects/further/more/', 302))
self.assertEqual(response.redirect_chain[2], ('http://testserver/no_template_view/', 302))
self.assertEqual(response.redirect_chain[0], ('/redirects/further/', 302))
self.assertEqual(response.redirect_chain[1], ('/redirects/further/more/', 302))
self.assertEqual(response.redirect_chain[2], ('/no_template_view/', 302))
def test_redirect_chain_to_non_existent(self):
"You can follow a chain to a non-existent view"
@ -507,21 +509,24 @@ class AssertRedirectsTests(TestCase):
def test_redirect_scheme(self):
"An assertion is raised if the response doesn't have the scheme specified in expected_url"
# Assure that original request scheme is preserved if no scheme specified in the redirect location
response = self.client.get('/redirect_view/', secure=True)
self.assertRedirects(response, 'https://testserver/get_view/')
# For all possible True/False combinations of follow and secure
for follow, secure in itertools.product([True, False], repeat=2):
# always redirects to https
response = self.client.get('/https_redirect_view/', follow=follow, secure=secure)
# no scheme to compare too, always succeeds
self.assertRedirects(response, '/secure_view/', status_code=302)
# the goal scheme is https
self.assertRedirects(response, 'https://testserver/secure_view/', status_code=302)
with self.assertRaises(AssertionError):
self.assertRedirects(response, 'http://testserver/secure_view/', status_code=302)
@ignore_warnings(category=RemovedInDjango21Warning)
def test_full_path_in_expected_urls(self):
"""
Test that specifying a full URL as assertRedirects expected_url still
work as backwards compatible behavior until Django 2.1.
"""
response = self.client.get('/redirect_view/')
self.assertRedirects(response, 'http://testserver/get_view/')
@override_settings(ROOT_URLCONF='test_client_regress.urls')
class AssertFormErrorTests(TestCase):
@ -852,7 +857,7 @@ class LoginTests(TestDataMixin, TestCase):
# At this points, the self.client isn't logged in.
# Check that assertRedirects uses the original client, not the
# default client.
self.assertRedirects(response, "http://testserver/get_view/")
self.assertRedirects(response, "/get_view/")
@override_settings(

View File

@ -32,7 +32,6 @@ urlpatterns = [
url(r'^accounts/logout/$', auth_views.logout),
# Special URLs for particular regression cases.
url('^中文/$', views.redirect),
url('^中文/target/$', views.index_page),
]

View File

@ -31,7 +31,7 @@ class I18NTests(TestCase):
for lang_code, lang_name in settings.LANGUAGES:
post_data = dict(language=lang_code, next='/')
response = self.client.post('/i18n/setlang/', data=post_data)
self.assertRedirects(response, 'http://testserver/')
self.assertRedirects(response, '/')
self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
def test_setlang_unsafe_next(self):
@ -42,7 +42,7 @@ class I18NTests(TestCase):
lang_code, lang_name = settings.LANGUAGES[0]
post_data = dict(language=lang_code, next='//unsafe/redirection/')
response = self.client.post('/i18n/setlang/', data=post_data)
self.assertEqual(response.url, 'http://testserver/')
self.assertEqual(response.url, '/')
self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], lang_code)
def test_setlang_reversal(self):
@ -76,13 +76,13 @@ class I18NTests(TestCase):
follow=True, HTTP_REFERER='/en/translated/'
)
self.assertEqual(self.client.session[LANGUAGE_SESSION_KEY], 'nl')
self.assertRedirects(response, 'http://testserver/nl/vertaald/')
self.assertRedirects(response, '/nl/vertaald/')
# And reverse
response = self.client.post(
'/i18n/setlang/', data={'language': 'en'},
follow=True, HTTP_REFERER='/nl/vertaald/'
)
self.assertRedirects(response, 'http://testserver/en/translated/')
self.assertRedirects(response, '/en/translated/')
def test_jsi18n(self):
"""The javascript_catalog can be deployed with language settings"""

View File

@ -11,17 +11,6 @@ class URLHandling(TestCase):
"""
redirect_target = "/%E4%B8%AD%E6%96%87/target/"
def test_combining_redirect(self):
"""
Tests that redirecting to an IRI, requiring encoding before we use it
in an HTTP response, is handled correctly. In this case the arg to
HttpRedirect is ASCII but the current request path contains non-ASCII
characters so this test ensures the creation of the full path with a
base non-ASCII part is handled correctly.
"""
response = self.client.get('/中文/')
self.assertRedirects(response, self.redirect_target)
def test_nonascii_redirect(self):
"""
Tests that a non-ASCII argument to HttpRedirect is handled properly.

View File

@ -6,9 +6,7 @@ import sys
from django.core.exceptions import PermissionDenied, SuspiciousOperation
from django.core.urlresolvers import get_resolver
from django.http import (
Http404, HttpResponse, HttpResponseRedirect, JsonResponse,
)
from django.http import Http404, HttpResponse, JsonResponse
from django.shortcuts import render, render_to_response
from django.template import TemplateDoesNotExist
from django.utils.log import getLogger
@ -71,13 +69,6 @@ class Http404View(View):
raise Http404("Testing class-based technical 404.")
def redirect(request):
"""
Forces an HTTP redirect.
"""
return HttpResponseRedirect("target/")
def view_exception(request, n):
raise BrokenException(except_args[int(n)])