Fixed #33562 -- Made HttpResponse.set_cookie() support timedelta for the max_age argument.

This commit is contained in:
Luke Plant 2022-03-04 12:57:10 +00:00 committed by Mariusz Felisiak
parent 1882f6567d
commit ae2da5ba65
5 changed files with 29 additions and 4 deletions

View File

@ -227,6 +227,10 @@ class HttpResponseBase:
- a naive ``datetime.datetime`` object in UTC,
- an aware ``datetime.datetime`` object in any time zone.
If it is a ``datetime.datetime`` object then calculate ``max_age``.
``max_age`` can be:
- int/float specifying seconds,
- ``datetime.timedelta`` object.
"""
self.cookies[key] = value
if expires is not None:
@ -246,6 +250,8 @@ class HttpResponseBase:
else:
self.cookies[key]["expires"] = ""
if max_age is not None:
if isinstance(max_age, datetime.timedelta):
max_age = max_age.total_seconds()
self.cookies[key]["max-age"] = int(max_age)
# IE requires expires, so set it if hasn't been already.
if not expires:

View File

@ -853,9 +853,15 @@ Methods
Sets a cookie. The parameters are the same as in the
:class:`~http.cookies.Morsel` cookie object in the Python standard library.
* ``max_age`` should be an integer number of seconds, or ``None`` (default)
if the cookie should last only as long as the client's browser session.
If ``expires`` is not specified, it will be calculated.
* ``max_age`` should be a :class:`~datetime.timedelta` object, an integer
number of seconds, or ``None`` (default) if the cookie should last only
as long as the client's browser session. If ``expires`` is not specified,
it will be calculated.
.. versionchanged:: 4.1
Support for ``timedelta`` objects was added.
* ``expires`` should either be a string in the format
``"Wdy, DD-Mon-YY HH:MM:SS GMT"`` or a ``datetime.datetime`` object
in UTC. If ``expires`` is a ``datetime`` object, the ``max_age``

View File

@ -281,7 +281,8 @@ Models
Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~
* ...
* :meth:`.HttpResponse.set_cookie` now supports :class:`~datetime.timedelta`
objects for the ``max_age`` argument.
Security
~~~~~~~~

View File

@ -71,6 +71,11 @@ class SetCookieTests(SimpleTestCase):
response.set_cookie("max_age", max_age=10.6)
self.assertEqual(response.cookies["max_age"]["max-age"], 10)
def test_max_age_timedelta(self):
response = HttpResponse()
response.set_cookie("max_age", max_age=timedelta(hours=1))
self.assertEqual(response.cookies["max_age"]["max-age"], 3600)
def test_httponly_cookie(self):
response = HttpResponse()
response.set_cookie("example", httponly=True)

View File

@ -62,6 +62,13 @@ class SignedCookieTest(SimpleTestCase):
with self.assertRaises(signing.SignatureExpired):
request.get_signed_cookie("c", max_age=timedelta(seconds=10))
def test_set_signed_cookie_max_age_argument(self):
response = HttpResponse()
response.set_signed_cookie("c", "value", max_age=100)
self.assertEqual(response.cookies["c"]["max-age"], 100)
response.set_signed_cookie("d", "value", max_age=timedelta(hours=2))
self.assertEqual(response.cookies["d"]["max-age"], 7200)
@override_settings(SECRET_KEY=b"\xe7")
def test_signed_cookies_with_binary_key(self):
response = HttpResponse()