| 390 | from django.test import TestCase |
| 391 | from django.http import HttpRequest, HttpResponse |
| 392 | from django.contrib.sessions.middleware import SessionMiddleware |
| 393 | from django.conf import settings |
| 394 | |
| 395 | class SessionTest(TestCase): |
| 396 | def generic_view(self, request): |
| 397 | request.session["seen_this_user_before"] = 1 |
| 398 | return HttpResponse("") |
| 399 | |
| 400 | def cycle_view(self, request): |
| 401 | request.session.cycle_key() |
| 402 | request.session["login_key"] = 1 |
| 403 | return HttpResponse("") |
| 404 | |
| 405 | def flush_view(self, request): |
| 406 | request.session.flush() |
| 407 | request.session["login_key"] = 1 |
| 408 | return HttpResponse("") |
| 409 | |
| 410 | def ajax_view(self, request): |
| 411 | self.assertEqual(request.session.get("login_key", None), None) |
| 412 | return HttpResponse("") |
| 413 | |
| 414 | def still_logged_in_view(self, request): |
| 415 | self.assertEqual(request.session.get("login_key"), 1) |
| 416 | return HttpResponse("") |
| 417 | |
| 418 | @staticmethod |
| 419 | def run_view(view, client_cookies, session_cookie_override = None): |
| 420 | request_cookies = client_cookies.copy() |
| 421 | if session_cookie_override is not None: |
| 422 | request_cookies[settings.SESSION_COOKIE_NAME] = session_cookie_override |
| 423 | |
| 424 | request = HttpRequest() |
| 425 | request.COOKIES = request_cookies |
| 426 | |
| 427 | mid = SessionMiddleware() |
| 428 | mid.process_request(request) |
| 429 | response = view(request) |
| 430 | mid.process_response(request, response) |
| 431 | |
| 432 | for cookie in response.cookies.itervalues(): |
| 433 | client_cookies[cookie.key] = cookie.value |
| 434 | return response |
| 435 | |
| 436 | def _test_session_race(self, flush): |
| 437 | # This test will fail if settings.SESSION_SAVE_EVERY_REQUEST is set. |
| 438 | if settings.SESSION_SAVE_EVERY_REQUEST: |
| 439 | return |
| 440 | |
| 441 | # This dict simulates the cookie store on a user client. |
| 442 | cookies = {} |
| 443 | |
| 444 | # The user logs in, and receives a session cookie for a login key. |
| 445 | # The user accesses the site, and receives a session cookie. |
| 446 | response = self.run_view(self.generic_view, cookies) |
| 447 | original_session_cookie = response.cookies.get(settings.SESSION_COOKIE_NAME, False) |
| 448 | self.assertNotEqual(original_session_cookie, False) |
| 449 | |
| 450 | # The user logs into the site, triggering session.flush, and receives a new session cookie. |
| 451 | if flush: |
| 452 | response = self.run_view(self.flush_view, cookies) |
| 453 | else: |
| 454 | response = self.run_view(self.cycle_view, cookies) |
| 455 | new_session_cookie = response.cookies.get(settings.SESSION_COOKIE_NAME, False) |
| 456 | self.assertNotEqual(new_session_cookie, False) |
| 457 | self.assertNotEqual(new_session_cookie.value, original_session_cookie.value) |
| 458 | |
| 459 | # A delayed AJAX request comes in using the original session. The request should use |
| 460 | # the old session and not set a session. The user is not logged in during this request. |
| 461 | response = self.run_view(self.ajax_view, cookies, original_session_cookie.value) |
| 462 | unset_session_cookie = response.cookies.get(settings.SESSION_COOKIE_NAME, False) |
| 463 | self.assertEqual(unset_session_cookie, False) |
| 464 | |
| 465 | # The user should still be logged in. |
| 466 | response = self.run_view(self.still_logged_in_view, cookies) |
| 467 | |
| 468 | def test_session_race_with_flush(self): |
| 469 | self._test_session_race(True) |
| 470 | |
| 471 | def test_session_race_with_cycle(self): |
| 472 | self._test_session_race(False) |
| 473 | |