Code

Ticket #7770: 7770.2.diff

File 7770.2.diff, 4.5 KB (added by SmileyChris, 4 years ago)
Line 
1diff --git a/django/http/__init__.py b/django/http/__init__.py
2index e585a71..7c096fc 100644
3--- a/django/http/__init__.py
4+++ b/django/http/__init__.py
5@@ -1,5 +1,7 @@
6+import datetime
7 import os
8 import re
9+import time
10 from Cookie import BaseCookie, SimpleCookie, CookieError
11 from pprint import pformat
12 from urllib import urlencode
13@@ -12,6 +14,7 @@ except ImportError:
14 
15 from django.utils.datastructures import MultiValueDict, ImmutableList
16 from django.utils.encoding import smart_str, iri_to_uri, force_unicode
17+from django.utils.http import cookie_date
18 from django.http.multipartparser import MultiPartParser
19 from django.conf import settings
20 from django.core.files import uploadhandler
21@@ -373,11 +376,27 @@ class HttpResponse(object):
22 
23     def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
24                    domain=None, secure=False):
25+        """
26+        Sets a cookie.
27+
28+        ``expires`` can be a string in the correct format or a datetime object
29+        (either datetime.datetime or datetime.timedelta) in UTC. If ``expires``
30+        is a datetime object then ``max_age`` will be calculated.
31+        """
32         self.cookies[key] = value
33-        if max_age is not None:
34-            self.cookies[key]['max-age'] = max_age
35         if expires is not None:
36+            if isinstance(expires, (datetime.datetime, datetime.timedelta)):
37+                if isinstance(expires, datetime.datetime):
38+                    expires = expires - expires.utcnow()
39+                    # Add one second so the date matches exactly (a fraction of
40+                    # time gets lost between converting to a timedelta and
41+                    # then the date string).
42+                    expires = expires + datetime.timedelta(seconds=1)
43+                max_age = max(0, expires.days * 86400 + expires.seconds)
44+                expires = cookie_date(time.time() + max_age)
45             self.cookies[key]['expires'] = expires
46+        if max_age is not None:
47+            self.cookies[key]['max-age'] = max_age
48         if path is not None:
49             self.cookies[key]['path'] = path
50         if domain is not None:
51diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
52index bf984f4..400bf0b 100644
53--- a/docs/ref/request-response.txt
54+++ b/docs/ref/request-response.txt
55@@ -512,10 +512,13 @@ Methods
56     Sets a cookie. The parameters are the same as in the `cookie Morsel`_
57     object in the Python standard library.
58 
59+        * ``expires`` should either be a string in the format
60+          ``"Wdy, DD-Mon-YY HH:MM:SS GMT"`` or a ``datetime`` object
61+          (either ``datetime.datetime`` in UTC or ``datetime.timedelta``).
62+          If ``expires`` is either type of ``datetime`` object, the ``max_age``
63+          will be calculated.
64         * ``max_age`` should be a number of seconds, or ``None`` (default) if
65           the cookie should last only as long as the client's browser session.
66-        * ``expires`` should be a string in the format
67-          ``"Wdy, DD-Mon-YY HH:MM:SS GMT"``.
68         * Use ``domain`` if you want to set a cross-domain cookie. For example,
69           ``domain=".lawrence.com"`` will set a cookie that is readable by
70           the domains www.lawrence.com, blogs.lawrence.com and
71diff --git a/tests/regressiontests/requests/tests.py b/tests/regressiontests/requests/tests.py
72index 1615a73..f6c2c6d 100644
73--- a/tests/regressiontests/requests/tests.py
74+++ b/tests/regressiontests/requests/tests.py
75@@ -1,5 +1,5 @@
76 """
77->>> from django.http import HttpRequest
78+>>> from django.http import HttpRequest, HttpResponse
79 >>> print repr(HttpRequest())
80 <HttpRequest
81 GET:{},
82@@ -44,4 +44,23 @@ https://www.example.com/asdf
83 >>> request.path = ''
84 >>> print request.build_absolute_uri(location="/path/with:colons")
85 http://www.example.com/path/with:colons
86+
87+
88+# Test cookie datetime expiration logic
89+>>> from datetime import datetime, timedelta
90+>>> delta = timedelta(seconds=10)
91+>>> response = HttpResponse()
92+>>> response.set_cookie('datetime', expires=datetime.utcnow()+delta)
93+>>> response.set_cookie('delta', expires=delta)
94+>>> datetime_cookie = response.cookies['datetime']
95+>>> timedelta_cookie = response.cookies['datetime']
96+>>> datetime_cookie['max-age']
97+10
98+>>> datetime_cookie['max-age'] == timedelta_cookie['max-age']
99+True
100+>>> datetime_cookie['expires'] == timedelta_cookie['expires']
101+True
102+>>> response.set_cookie('datetime', expires=datetime(2028, 1, 1, 4, 5, 6))
103+>>> response.cookies['datetime']['expires']
104+'Sat, 01-Jan-2028 04:05:06 GMT'
105 """