test_cookie.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import time
  2. from datetime import datetime, timedelta
  3. from http import cookies
  4. from django.http import HttpResponse
  5. from django.test import SimpleTestCase
  6. from django.test.utils import freeze_time
  7. from django.utils.http import http_date
  8. from django.utils.timezone import utc
  9. class SetCookieTests(SimpleTestCase):
  10. def test_near_expiration(self):
  11. """Cookie will expire when a near expiration time is provided."""
  12. response = HttpResponse()
  13. # There's a timing weakness in this test; The expected result for
  14. # max-age requires that there be a very slight difference between the
  15. # evaluated expiration time and the time evaluated in set_cookie(). If
  16. # this difference doesn't exist, the cookie time will be 1 second
  17. # larger. The sleep guarantees that there will be a time difference.
  18. expires = datetime.now(tz=utc).replace(tzinfo=None) + timedelta(seconds=10)
  19. time.sleep(0.001)
  20. response.set_cookie("datetime", expires=expires)
  21. datetime_cookie = response.cookies["datetime"]
  22. self.assertEqual(datetime_cookie["max-age"], 10)
  23. def test_aware_expiration(self):
  24. """set_cookie() accepts an aware datetime as expiration time."""
  25. response = HttpResponse()
  26. expires = datetime.now(tz=utc) + timedelta(seconds=10)
  27. time.sleep(0.001)
  28. response.set_cookie("datetime", expires=expires)
  29. datetime_cookie = response.cookies["datetime"]
  30. self.assertEqual(datetime_cookie["max-age"], 10)
  31. def test_create_cookie_after_deleting_cookie(self):
  32. """Setting a cookie after deletion clears the expiry date."""
  33. response = HttpResponse()
  34. response.set_cookie("c", "old-value")
  35. self.assertEqual(response.cookies["c"]["expires"], "")
  36. response.delete_cookie("c")
  37. self.assertEqual(
  38. response.cookies["c"]["expires"], "Thu, 01 Jan 1970 00:00:00 GMT"
  39. )
  40. response.set_cookie("c", "new-value")
  41. self.assertEqual(response.cookies["c"]["expires"], "")
  42. def test_far_expiration(self):
  43. """Cookie will expire when a distant expiration time is provided."""
  44. response = HttpResponse()
  45. response.set_cookie("datetime", expires=datetime(2038, 1, 1, 4, 5, 6))
  46. datetime_cookie = response.cookies["datetime"]
  47. self.assertIn(
  48. datetime_cookie["expires"],
  49. # assertIn accounts for slight time dependency (#23450)
  50. ("Fri, 01 Jan 2038 04:05:06 GMT", "Fri, 01 Jan 2038 04:05:07 GMT"),
  51. )
  52. def test_max_age_expiration(self):
  53. """Cookie will expire if max_age is provided."""
  54. response = HttpResponse()
  55. set_cookie_time = time.time()
  56. with freeze_time(set_cookie_time):
  57. response.set_cookie("max_age", max_age=10)
  58. max_age_cookie = response.cookies["max_age"]
  59. self.assertEqual(max_age_cookie["max-age"], 10)
  60. self.assertEqual(max_age_cookie["expires"], http_date(set_cookie_time + 10))
  61. def test_max_age_int(self):
  62. response = HttpResponse()
  63. response.set_cookie("max_age", max_age=10.6)
  64. self.assertEqual(response.cookies["max_age"]["max-age"], 10)
  65. def test_max_age_timedelta(self):
  66. response = HttpResponse()
  67. response.set_cookie("max_age", max_age=timedelta(hours=1))
  68. self.assertEqual(response.cookies["max_age"]["max-age"], 3600)
  69. def test_httponly_cookie(self):
  70. response = HttpResponse()
  71. response.set_cookie("example", httponly=True)
  72. example_cookie = response.cookies["example"]
  73. self.assertIn(
  74. "; %s" % cookies.Morsel._reserved["httponly"], str(example_cookie)
  75. )
  76. self.assertIs(example_cookie["httponly"], True)
  77. def test_unicode_cookie(self):
  78. """HttpResponse.set_cookie() works with Unicode data."""
  79. response = HttpResponse()
  80. cookie_value = "清風"
  81. response.set_cookie("test", cookie_value)
  82. self.assertEqual(response.cookies["test"].value, cookie_value)
  83. def test_samesite(self):
  84. response = HttpResponse()
  85. response.set_cookie("example", samesite="None")
  86. self.assertEqual(response.cookies["example"]["samesite"], "None")
  87. response.set_cookie("example", samesite="Lax")
  88. self.assertEqual(response.cookies["example"]["samesite"], "Lax")
  89. response.set_cookie("example", samesite="strict")
  90. self.assertEqual(response.cookies["example"]["samesite"], "strict")
  91. def test_invalid_samesite(self):
  92. msg = 'samesite must be "lax", "none", or "strict".'
  93. with self.assertRaisesMessage(ValueError, msg):
  94. HttpResponse().set_cookie("example", samesite="invalid")
  95. class DeleteCookieTests(SimpleTestCase):
  96. def test_default(self):
  97. response = HttpResponse()
  98. response.delete_cookie("c")
  99. cookie = response.cookies["c"]
  100. self.assertEqual(cookie["expires"], "Thu, 01 Jan 1970 00:00:00 GMT")
  101. self.assertEqual(cookie["max-age"], 0)
  102. self.assertEqual(cookie["path"], "/")
  103. self.assertEqual(cookie["secure"], "")
  104. self.assertEqual(cookie["domain"], "")
  105. self.assertEqual(cookie["samesite"], "")
  106. def test_delete_cookie_secure_prefix(self):
  107. """
  108. delete_cookie() sets the secure flag if the cookie name starts with
  109. __Host- or __Secure- (without that, browsers ignore cookies with those
  110. prefixes).
  111. """
  112. response = HttpResponse()
  113. for prefix in ("Secure", "Host"):
  114. with self.subTest(prefix=prefix):
  115. cookie_name = "__%s-c" % prefix
  116. response.delete_cookie(cookie_name)
  117. self.assertIs(response.cookies[cookie_name]["secure"], True)
  118. def test_delete_cookie_secure_samesite_none(self):
  119. # delete_cookie() sets the secure flag if samesite='none'.
  120. response = HttpResponse()
  121. response.delete_cookie("c", samesite="none")
  122. self.assertIs(response.cookies["c"]["secure"], True)
  123. def test_delete_cookie_samesite(self):
  124. response = HttpResponse()
  125. response.delete_cookie("c", samesite="lax")
  126. self.assertEqual(response.cookies["c"]["samesite"], "lax")