Ticket #4476: 4476_follow_redirects.diff
File 4476_follow_redirects.diff, 14.3 KB (added by , 17 years ago) |
---|
-
django/test/client.py
1 1 import datetime 2 2 import sys 3 3 from cStringIO import StringIO 4 from urlparse import urlparse 4 from urlparse import urlparse, urlsplit 5 5 from django.conf import settings 6 6 from django.contrib.auth import authenticate, login 7 7 from django.core.handlers.base import BaseHandler 8 8 from django.core.handlers.wsgi import WSGIRequest 9 9 from django.core.signals import got_request_exception 10 10 from django.dispatch import dispatcher 11 from django.http import SimpleCookie, HttpRequest 11 from django.http import SimpleCookie, HttpRequest, QueryDict 12 12 from django.template import TemplateDoesNotExist 13 13 from django.test import signals 14 14 from django.utils.functional import curry … … 205 205 206 206 return response 207 207 208 def get(self, path, data={}, **extra):208 def get(self, path, data={}, follow=True, **extra): 209 209 "Request a response from the server using GET." 210 210 r = { 211 211 'CONTENT_LENGTH': None, … … 216 216 } 217 217 r.update(extra) 218 218 219 return self.request(**r) 219 response = self.request(**r) 220 if follow: 221 response = self._handle_redirects(response) 222 return response 220 223 221 def post(self, path, data={}, content_type=MULTIPART_CONTENT, **extra):224 def post(self, path, data={}, content_type=MULTIPART_CONTENT, follow=True, **extra): 222 225 "Request a response from the server using POST." 223 226 224 227 if content_type is MULTIPART_CONTENT: … … 235 238 } 236 239 r.update(extra) 237 240 238 return self.request(**r) 241 response = self.request(**r) 242 if follow: 243 response = self._handle_redirects(response) 244 return response 239 245 240 246 def login(self, **credentials): 241 247 """Set the Client to appear as if it has sucessfully logged into a site. … … 276 282 session = __import__(settings.SESSION_ENGINE, {}, {}, ['']).SessionStore() 277 283 session.delete(session_key=self.cookies['sessionid'].value) 278 284 self.cookies = SimpleCookie() 285 286 def _handle_redirects(self, response): 287 "Follows any redirects by requesting responses from the server using GET." 288 289 response.redirect_chain = [] 290 while response.status_code in (301, 302, 303, 307): 291 url = response['Location'] 292 scheme, netloc, path, query, fragment = urlsplit(url) 293 294 local_redirect_chain = response.redirect_chain 295 local_redirect_chain.append((url, response.status_code)) 296 297 # The test client doesn't handle external links, 298 # but since the situation is simulated in test_client, 299 # we fake things here by ignoring the netloc portion of the 300 # redirected URL. 301 response = self.get(path, QueryDict(query), follow=False) 302 response.redirect_chain = local_redirect_chain 303 304 # prevent any loops 305 if response.redirect_chain[-1] in response.redirect_chain[0:-1]: 306 break 307 308 return response 309 No newline at end of file -
django/test/testcases.py
2 2 import unittest 3 3 from urlparse import urlsplit, urlunsplit 4 4 5 from django.http import QueryDict6 5 from django.db import transaction 7 6 from django.core import mail 8 7 from django.core.management import call_command … … 74 73 super(TestCase, self).__call__(result) 75 74 76 75 def assertRedirects(self, response, expected_url, status_code=302, 77 target_status_code=200, host=None ):76 target_status_code=200, host=None, redirect_level=-1): 78 77 """Asserts that a response redirected to a specific URL, and that the 79 78 redirect URL can be loaded. 80 79 81 80 Note that assertRedirects won't work for external links since it uses 82 81 TestClient to do a request. 82 83 Note that assertRedirects only works properly if follow was set to true 84 in the request. 83 85 """ 84 self.assertEqual(response.status_code, status_code, 86 87 redirect_status_code = response.status_code 88 redirect_url = response.get('Location', '') 89 chain = response.__dict__.get('redirect_chain') 90 if chain: 91 redirect_url = chain[redirect_level][0] 92 redirect_status_code = chain[redirect_level][1] 93 94 self.assertEqual(redirect_status_code, status_code, 85 95 ("Response didn't redirect as expected: Response code was %d" 86 " (expected %d)" % (response.status_code, status_code))) 87 url = response['Location'] 88 scheme, netloc, path, query, fragment = urlsplit(url) 96 " (expected %d)" % (redirect_status_code, status_code))) 97 89 98 e_scheme, e_netloc, e_path, e_query, e_fragment = urlsplit(expected_url) 90 99 if not (e_scheme or e_netloc): 91 100 expected_url = urlunsplit(('http', host or 'testserver', e_path, 92 101 e_query, e_fragment)) 93 self.assertEqual( url, expected_url,94 "Response redirected to '%s', expected '%s'" % ( url, expected_url))102 self.assertEqual(redirect_url, expected_url, 103 "Response redirected to '%s', expected '%s'" % (redirect_url, expected_url)) 95 104 96 # Get the redirection page, using the same client that was used 97 # to obtain the original response. 98 redirect_response = response.client.get(path, QueryDict(query)) 99 self.assertEqual(redirect_response.status_code, target_status_code, 105 self.assertEqual(response.status_code, target_status_code, 100 106 ("Couldn't retrieve redirection page '%s': response code was %d" 101 107 " (expected %d)") % 102 ( path, redirect_response.status_code, target_status_code))108 (redirect_url, response.status_code, target_status_code)) 103 109 104 110 def assertContains(self, response, text, count=None, status_code=200): 105 111 """ -
docs/testing.txt
453 453 454 454 Once you have a ``Client`` instance, you can call any of the following methods: 455 455 456 ``get(path, data={} )``456 ``get(path, data={}, follow=True)`` 457 457 Makes a GET request on the provided ``path`` and returns a ``Response`` 458 object, which is documented below. 458 object, which is documented below, and will optionally ``follow`` any 459 server redirects. 459 460 460 461 The key-value pairs in the ``data`` dictionary are used to create a GET 461 462 data payload. For example:: … … 467 468 468 469 /customers/details/?name=fred&age=7 469 470 470 ``post(path, data={}, content_type=MULTIPART_CONTENT)`` 471 If any redirects occurred, the response will have a ``redirect_chain`` 472 attribute containing tuples of the intermediate urls and status codes. 473 If you had an url ``/redirect_me/`` that redirected to ``/final/``, this is 474 what you'd see: 475 476 >>> response = c.get('/redirect_me/') 477 >>> response.redirect_chain 478 [(u'/final/', 301)] 479 480 ``post(path, data={}, content_type=MULTIPART_CONTENT, follow=True)`` 471 481 Makes a POST request on the provided ``path`` and returns a ``Response`` 472 object, which is documented below. 482 object, which is documented below, and will optionally ``follow`` any 483 server redirects. 473 484 474 485 The key-value pairs in the ``data`` dictionary are used to submit POST 475 486 data. For example:: … … 501 512 502 513 {'choices': ('a', 'b', 'd')} 503 514 515 If any redirects occurred, the response will have a ``redirect_chain`` 516 attribute containing tuples of the intermediate urls and status codes. 517 If you had an url ``/redirect_me/`` that redirected to ``/final/``, this is 518 what you'd see: 519 520 >>> response = c.post('/redirect_me/', {'data': 'test'}) 521 >>> response.redirect_chain 522 [(u'/final/', 302)] 523 504 524 Submitting files is a special case. To POST a file, you need only provide 505 525 the file field name as a key, and a file handle to the file you wish to 506 526 upload as a value. For example:: … … 834 854 Asserts that the template with the given name was *not* used in rendering 835 855 the response. 836 856 837 ``assertRedirects(response, expected_url, status_code=302, target_status_code=200 )``857 ``assertRedirects(response, expected_url, status_code=302, target_status_code=200, redirect_level=-1)`` 838 858 Asserts that the response return a ``status_code`` redirect status, 839 it redirected to ``expected_url`` (including any GET data), and the subsequent859 it redirected to ``expected_url`` (including any GET data), and the final 840 860 page was received with ``target_status_code``. 861 862 If you're expecting multiple levels of redirects, you can specify to which 863 ``redirect_level`` the ``expected_url`` and ``status_code`` are matched against. 864 A value of -1 checks against the last redirect in the chain. 841 865 842 866 ``assertTemplateUsed(response, template_name)`` 843 867 Asserts that the template with the given name was used in rendering the -
tests/modeltests/test_client/models.py
114 114 115 115 def test_redirect_to_strange_location(self): 116 116 "GET a URL that redirects to a non-200 page" 117 response = self.client.get('/test_client/redirect_to_bad_view/') 118 119 # Check that the response was a 404 120 self.assertRedirects(response, 'http://testserver/test_client/bad_view/', target_status_code=404) 121 122 def test_chained_redirects(self): 123 "GET a URL that redirects more than once" 117 124 response = self.client.get('/test_client/double_redirect_view/') 118 125 119 # Check that the response was a 302, and that120 # the attempt to get the redirection location returned 301 when retrieved121 self.assertRedirects(response, 'http://testserver/test_client/ permanent_redirect_view/', target_status_code=301)126 # Check that there were two redirects, the first being a 302 and the second 301 127 self.assertRedirects(response, 'http://testserver/test_client/permanent_redirect_view/', status_code=302, redirect_level=0) 128 self.assertRedirects(response, 'http://testserver/test_client/get_view/', status_code=301, redirect_level=1) 122 129 123 130 def test_notfound_response(self): 124 131 "GET a URL that responds as '404:Not Found'" -
tests/modeltests/test_client/urls.py
9 9 (r'^redirect_view/$', views.redirect_view), 10 10 (r'^permanent_redirect_view/$', redirect_to, { 'url': '/test_client/get_view/' }), 11 11 (r'^double_redirect_view/$', views.double_redirect_view), 12 (r'^redirect_to_bad_view/$', views.redirect_to_bad_view), 13 (r'^infinite_redirect/$', views.redirect_to_self), 12 14 (r'^bad_view/$', views.bad_view), 13 15 (r'^form_view/$', views.form_view), 14 16 (r'^form_view_with_template/$', views.form_view_with_template), -
tests/modeltests/test_client/views.py
60 60 "A view that redirects all requests to a redirection view" 61 61 return HttpResponseRedirect('/test_client/permanent_redirect_view/') 62 62 63 def redirect_to_bad_view(request): 64 "A view that redirects all requests to 404 page" 65 return HttpResponseRedirect('/test_client/bad_view/') 66 67 def redirect_to_self(request): 68 "A view that redirects to itself (bad thing!)" 69 return HttpResponseRedirect('/test_client/infinite_redirect/') 70 63 71 def bad_view(request): 64 72 "A view that returns a 404 with some error content" 65 73 return HttpResponseNotFound('Not found!. This page contains some MAGIC content') -
tests/regressiontests/test_client_regress/models.py
132 132 133 133 def test_target_page(self): 134 134 "An assertion is raised if the response redirect target cannot be retrieved as expected" 135 response = self.client.get('/test_client/ double_redirect_view/')135 response = self.client.get('/test_client/redirect_to_bad_view/') 136 136 try: 137 # The redirect target responds with a 301 code, not 200138 self.assertRedirects(response, 'http://testserver/test_client/ permanent_redirect_view/')137 # The redirect target responds with a 404 code, not 200 (simulated case.) 138 self.assertRedirects(response, 'http://testserver/test_client/bad_view/') 139 139 except AssertionError, e: 140 self.assertEquals(str(e), "Couldn't retrieve redirection page ' /test_client/permanent_redirect_view/': response code was 301(expected 200)")140 self.assertEquals(str(e), "Couldn't retrieve redirection page 'http://testserver/test_client/bad_view/': response code was 404 (expected 200)") 141 141 142 def test_infinite_loop_redirect(self): 143 "An exception is raised if an URL contains a loop in the redirect chain" 144 145 # Check that the test client breaks out of infinite redirect loops 146 response = self.client.get('/test_client/infinite_redirect/') 147 try: 148 self.assertRedirects(response, 'http://testserver/test_client/infinite_redirect/') 149 except AssertionError, e: 150 self.assertEquals(str(e), "Couldn't retrieve redirection page 'http://testserver/test_client/infinite_redirect/': response code was 302 (expected 200)") 151 152 # For educational purposes: how to tell that you encountered a loop 153 self.assertTrue(response.redirect_chain[-1] in response.redirect_chain[0:-1]) 154 142 155 class AssertFormErrorTests(TestCase): 143 156 def test_unknown_form(self): 144 157 "An assertion is raised if the form name is unknown"