Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Allow setting HttpResponse cookie expiry times with datetime objects.

Patch from SmileyChris. Fixed #7770.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@13809 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 2d4da641a6ee6c96f38336d8dc6786c07e7b3a1f 1 parent 7c07544
Malcolm Tredinnick authored September 12, 2010
28  django/http/__init__.py
... ...
@@ -1,5 +1,7 @@
  1
+import datetime
1 2
 import os
2 3
 import re
  4
+import time
3 5
 from Cookie import BaseCookie, SimpleCookie, CookieError
4 6
 from pprint import pformat
5 7
 from urllib import urlencode
@@ -12,6 +14,7 @@
12 14
 
13 15
 from django.utils.datastructures import MultiValueDict, ImmutableList
14 16
 from django.utils.encoding import smart_str, iri_to_uri, force_unicode
  17
+from django.utils.http import cookie_date
15 18
 from django.http.multipartparser import MultiPartParser
16 19
 from django.conf import settings
17 20
 from django.core.files import uploadhandler
@@ -373,11 +376,32 @@ def get(self, header, alternate):
373 376
 
374 377
     def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
375 378
                    domain=None, secure=False):
  379
+        """
  380
+        Sets a cookie.
  381
+
  382
+        ``expires`` can be a string in the correct format or a 
  383
+        ``datetime.datetime`` object in UTC. If ``expires`` is a datetime
  384
+        object then ``max_age`` will be calculated.
  385
+        """
376 386
         self.cookies[key] = value
  387
+        if expires is not None:
  388
+            if isinstance(expires, datetime.datetime):
  389
+                delta = expires - expires.utcnow()
  390
+                # Add one second so the date matches exactly (a fraction of
  391
+                # time gets lost between converting to a timedelta and
  392
+                # then the date string).
  393
+                delta = delta + datetime.timedelta(seconds=1)
  394
+                # Just set max_age - the max_age logic will set expires.
  395
+                expires = None
  396
+                max_age = max(0, delta.days * 86400 + delta.seconds)
  397
+            else:
  398
+                self.cookies[key]['expires'] = expires
377 399
         if max_age is not None:
378 400
             self.cookies[key]['max-age'] = max_age
379  
-        if expires is not None:
380  
-            self.cookies[key]['expires'] = expires
  401
+            # IE requires expires, so set it if hasn't been already.
  402
+            if not expires:
  403
+                self.cookies[key]['expires'] = cookie_date(time.time() +
  404
+                                                           max_age) 
381 405
         if path is not None:
382 406
             self.cookies[key]['path'] = path
383 407
         if domain is not None:
7  docs/ref/request-response.txt
@@ -529,8 +529,11 @@ Methods
529 529
 
530 530
         * ``max_age`` should be a number of seconds, or ``None`` (default) if
531 531
           the cookie should last only as long as the client's browser session.
532  
-        * ``expires`` should be a string in the format
533  
-          ``"Wdy, DD-Mon-YY HH:MM:SS GMT"``.
  532
+          If ``expires`` is not specified, it will be calculated.
  533
+        * ``expires`` should either be a string in the format
  534
+          ``"Wdy, DD-Mon-YY HH:MM:SS GMT"`` or a ``datetime.datetime`` object
  535
+          in UTC. If ``expires`` is a ``datetime`` object, the ``max_age``
  536
+          will be calculated.
534 537
         * Use ``domain`` if you want to set a cross-domain cookie. For example,
535 538
           ``domain=".lawrence.com"`` will set a cookie that is readable by
536 539
           the domains www.lawrence.com, blogs.lawrence.com and
25  tests/regressiontests/requests/tests.py
... ...
@@ -1,5 +1,5 @@
1 1
 """
2  
->>> from django.http import HttpRequest
  2
+>>> from django.http import HttpRequest, HttpResponse
3 3
 >>> print repr(HttpRequest())
4 4
 <HttpRequest
5 5
 GET:{},
@@ -44,4 +44,27 @@
44 44
 >>> request.path = ''
45 45
 >>> print request.build_absolute_uri(location="/path/with:colons")
46 46
 http://www.example.com/path/with:colons
  47
+
  48
+
  49
+# Test cookie datetime expiration logic
  50
+>>> from datetime import datetime, timedelta
  51
+>>> delta = timedelta(seconds=10)
  52
+>>> response = HttpResponse()
  53
+>>> response.set_cookie('datetime', expires=datetime.utcnow()+delta)
  54
+>>> datetime_cookie = response.cookies['datetime']
  55
+>>> datetime_cookie['max-age']
  56
+10
  57
+>>> response.set_cookie('datetime', expires=datetime(2028, 1, 1, 4, 5, 6))
  58
+>>> response.cookies['datetime']['expires']
  59
+'Sat, 01-Jan-2028 04:05:06 GMT'
  60
+
  61
+# Test automatically setting cookie expires if only max_age is provided 
  62
+>>> response.set_cookie('max_age', max_age=10)
  63
+>>> max_age_cookie = response.cookies['max_age']
  64
+>>> max_age_cookie['max-age']
  65
+10
  66
+>>> from django.utils.http import cookie_date
  67
+>>> import time
  68
+>>> max_age_cookie['expires'] == cookie_date(time.time()+10)
  69
+True
47 70
 """

0 notes on commit 2d4da64

Please sign in to comment.
Something went wrong with that request. Please try again.