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