Ticket #2548: session_middleware.19.diff

File session_middleware.19.diff, 12.2 KB (added by SmileyChris, 7 years ago)

Oh, the last patch also added a slight fix to the db session backend (but I missed a reference to .now() -- session times are now stored in UTC

  • django/contrib/sessions/middleware.py

     
    2626            if accessed:
    2727                patch_vary_headers(response, ('Cookie',))
    2828            if modified or settings.SESSION_SAVE_EVERY_REQUEST:
    29                 if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
     29                if request.session.get_expire_at_browser_close():
    3030                    max_age = None
    3131                    expires = None
    3232                else:
    33                     max_age = settings.SESSION_COOKIE_AGE
    34                     expires_time = time.time() + settings.SESSION_COOKIE_AGE
     33                    max_age = request.session.get_max_age()
     34                    expires_time = time.time() + max_age
    3535                    expires = cookie_date(expires_time)
    3636                # Save the seesion data and refresh the client cookie.
    3737                request.session.save()
  • django/contrib/sessions/tests.py

     
    8888
    8989>>> s.pop('some key', 'does not exist')
    9090'does not exist'
     91
     92#########################
     93# Custom session expiry #
     94#########################
     95
     96>>> from django.conf import settings
     97>>> from datetime import datetime, timedelta
     98
     99>>> td10 = timedelta(seconds=10)
     100
     101# A normal session has a max age equal to settings
     102>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
     103True
     104
     105# So does a custom session with an idle expiration time of 0 (but it'll expire
     106# at browser close)
     107>>> s.set_expiry(0)
     108>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
     109True
     110
     111# Custom session idle expiration time
     112>>> s.set_expiry(10)
     113>>> delta = s.get_expiry_date() - datetime.utcnow()
     114>>> delta.seconds in (9, 10)
     115True
     116>>> age = s.get_max_age()
     117>>> age in (9, 10)
     118True
     119
     120# Custom session fixed expiry date (timedelta)
     121>>> s.set_expiry(td10)
     122>>> delta = s.get_expiry_date() - datetime.utcnow()
     123>>> delta.seconds in (9, 10)
     124True
     125>>> age = s.get_max_age()
     126>>> age in (9, 10)
     127True
     128
     129# Custom session fixed expiry date (fixed datetime)
     130>>> s.set_expiry(datetime.utcnow() + td10)
     131>>> delta = s.get_expiry_date() - datetime.utcnow()
     132>>> delta.seconds in (9, 10)
     133True
     134>>> age = s.get_max_age()
     135>>> age in (9, 10)
     136True
     137
     138# Set back to default session age
     139>>> s.set_expiry(None)
     140>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
     141True
     142
     143# Allow to set back to default session age even if no alternate has been set
     144>>> s.set_expiry(None)
     145
     146
     147# We're changing the setting then reverting back to the original setting at the
     148# end of these tests.
     149>>> original_expire_at_browser_close = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
     150>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = False
     151
     152# Custom session age
     153>>> s.set_expiry(10)
     154>>> s.get_expire_at_browser_close()
     155False
     156
     157# Custom expire-at-browser-close
     158>>> s.set_expiry(0)
     159>>> s.get_expire_at_browser_close()
     160True
     161
     162# Default session age
     163>>> s.set_expiry(None)
     164>>> s.get_expire_at_browser_close()
     165False
     166
     167>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = True
     168
     169# Custom session age
     170>>> s.set_expiry(10)
     171>>> s.get_expire_at_browser_close()
     172False
     173
     174# Custom expire-at-browser-close
     175>>> s.set_expiry(0)
     176>>> s.get_expire_at_browser_close()
     177True
     178
     179# Default session age
     180>>> s.set_expiry(None)
     181>>> s.get_expire_at_browser_close()
     182True
     183
     184>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = original_expire_at_browser_close
    91185"""
    92186
    93187if __name__ == '__main__':
  • django/contrib/sessions/backends/base.py

     
    44import random
    55import sys
    66import time
     7from datetime import datetime, timedelta
    78from django.conf import settings
    89from django.core.exceptions import SuspiciousOperation
    910
     
    128129
    129130    _session = property(_get_session)
    130131
     132    def get_max_age(self):
     133        expiry = self.get('_session_expiry')
     134        if not expiry:   # Checks both None and 0 cases
     135            return settings.SESSION_COOKIE_AGE
     136        if not isinstance(expiry, datetime):
     137            return expiry
     138        delta = expiry - datetime.utcnow()
     139        return delta.days * 86400 + delta.seconds
     140
     141    def get_expiry_date(self):
     142        "Returns the expiry date (in UTC)"
     143        expiry = self.get('_session_expiry', settings.SESSION_COOKIE_AGE)
     144        if isinstance(expiry, datetime):
     145            return expiry
     146        return datetime.utcnow() + timedelta(seconds=expiry)
     147
     148    def set_expiry(self, value):
     149        """
     150        Sets a custom expiration for the session. ``value`` can be an integer, a
     151        Python ``datetime`` or ``timedelta`` object or ``None``.
     152
     153        If ``value`` is an integer, the session will expire after that many
     154        seconds of inactivity. If set to ``0`` then the session will expire on
     155        browser close.
     156
     157        If ``value`` is a ``datetime`` or ``timedelta`` object, the session
     158        will expire at that specific future time (``datetime`` objects should be
     159        UTC).
     160
     161        If ``value`` is ``None``, the session uses the global session expiry
     162        policy.
     163        """
     164        if value is None:
     165            # Remove any custom expiration for this session.
     166            try:
     167                del self['_session_expiry']
     168            except KeyError:
     169                pass
     170            return
     171        if isinstance(value, timedelta):
     172            value = datetime.utcnow() + value
     173        self['_session_expiry'] = value
     174
     175    def get_expire_at_browser_close(self):
     176        if self.get('_session_expiry') is None:
     177            return settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
     178        return self.get('_session_expiry') == 0
     179
    131180    # Methods that child classes must implement.
    132181
    133182    def exists(self, session_key):
  • django/contrib/sessions/backends/cache.py

     
    44
    55class SessionStore(SessionBase):
    66    """
    7     A cache-based session store. 
     7    A cache-based session store.
    88    """
    99    def __init__(self, session_key=None):
    1010        self._cache = cache
    1111        super(SessionStore, self).__init__(session_key)
    12        
     12
    1313    def load(self):
    1414        session_data = self._cache.get(self.session_key)
    1515        return session_data or {}
    1616
    1717    def save(self):
    18         self._cache.set(self.session_key, self._session, settings.SESSION_COOKIE_AGE)
     18        self._cache.set(self.session_key, self._session, self.get_max_age())
    1919
    2020    def exists(self, session_key):
    2121        if self._cache.get(session_key):
    2222            return True
    2323        return False
    24        
     24
    2525    def delete(self, session_key):
    2626        self._cache.delete(session_key)
     27 No newline at end of file
  • django/contrib/sessions/backends/db.py

     
    1010    """
    1111    def __init__(self, session_key=None):
    1212        super(SessionStore, self).__init__(session_key)
    13    
     13
    1414    def load(self):
    1515        try:
    1616            s = Session.objects.get(
    17                 session_key = self.session_key, 
    18                 expire_date__gt=datetime.datetime.now()
     17                session_key = self.session_key,
     18                expire_date__gt=datetime.datetime.utcnow()
    1919            )
    2020            return self.decode(s.session_data)
    2121        except (Session.DoesNotExist, SuspiciousOperation):
    22            
     22
    2323            # Create a new session_key for extra security.
    2424            self.session_key = self._get_new_session_key()
    2525            self._session_cache = {}
     
    2727            # Save immediately to minimize collision
    2828            self.save()
    2929            return {}
    30            
     30
    3131    def exists(self, session_key):
    3232        try:
    3333            Session.objects.get(session_key=session_key)
    3434        except Session.DoesNotExist:
    3535            return False
    3636        return True
    37            
     37
    3838    def save(self):
    3939        Session.objects.create(
    4040            session_key = self.session_key,
    4141            session_data = self.encode(self._session),
    42             expire_date = datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE)
     42            expire_date = self.get_expiry_date()
    4343        )
    44    
     44
    4545    def delete(self, session_key):
    4646        try:
    4747            Session.objects.get(session_key=session_key).delete()
  • AUTHORS

     
    327327    tstromberg@google.com
    328328    Makoto Tsuyuki <mtsuyuki@gmail.com>
    329329    tt@gurgle.no
    330     Amit Upadhyay
     330    Amit Upadhyay <http://www.amitu.com/blog/>
    331331    Geert Vanderkelen
    332332    I.S. van Oostveen <v.oostveen@idca.nl>
    333333    viestards.lists@gmail.com
  • docs/sessions.txt

     
    8080It implements the following standard dictionary methods:
    8181
    8282    * ``__getitem__(key)``
     83
    8384      Example: ``fav_color = request.session['fav_color']``
    8485
    8586    * ``__setitem__(key, value)``
     87
    8688      Example: ``request.session['fav_color'] = 'blue'``
    8789
    8890    * ``__delitem__(key)``
     91
    8992      Example: ``del request.session['fav_color']``. This raises ``KeyError``
    9093      if the given ``key`` isn't already in the session.
    9194
    9295    * ``__contains__(key)``
     96
    9397      Example: ``'fav_color' in request.session``
    9498
    9599    * ``get(key, default=None)``
     100
    96101      Example: ``fav_color = request.session.get('fav_color', 'red')``
    97102
    98103    * ``keys()``
     
    101106
    102107    * ``setdefault()`` (**New in Django development version**)
    103108
    104 It also has these three methods:
     109It also has these methods:
    105110
    106111    * ``set_test_cookie()``
    107112      Sets a test cookie to determine whether the user's browser supports
     
    118123    * ``delete_test_cookie()``
    119124      Deletes the test cookie. Use this to clean up after yourself.
    120125
     126    * ``set_expiry(value)``
     127
     128      **New in Django development version**
     129
     130      Sets a custom expiration for the session.
     131
     132      If ``value`` is an integer, the session will expire after that many
     133      seconds of inactivity. If set to ``0`` then the session will expire when
     134      the user's browser is closed.
     135
     136      If ``value`` is a ``datetime`` or ``timedelta`` object, the session will
     137      expire at that specific time (``datetime`` objects must be in UTC).
     138
     139      If ``value`` is ``None``, the session reverts to using the global session
     140      expiry policy.
     141
     142    * ``get_max_age()``
     143
     144      **New in Django development version**
     145
     146      Returns the number of seconds until this session expires. For sessions
     147      with no custom expiration (or those set to expire at browser close), this
     148      will equal ``settings.SESSION_COOKIE_AGE``.
     149
     150    * ``get_expiry_date()``
     151
     152      **New in Django development version**
     153
     154      Returns the date this session will expire. For sessions with no custom
     155      expiration (or those set to expire at browser close), this will equal the
     156      UTC date ``settings.SESSION_COOKIE_AGE`` seconds from now.
     157
     158    * ``get_expire_at_browser_close()``
     159
     160      **New in Django development version**
     161
     162      Returns either ``True`` or ``False``, depending on whether this session
     163      will expire when the user's browser is closed.
     164
    121165You can edit ``request.session`` at any point in your view. You can edit it
    122166multiple times.
    123167
     
    278322her browser. Use this if you want people to have to log in every time they open
    279323a browser.
    280324
     325**New in Django development version**
     326
     327This setting is a global default and can be overwritten by explicitly calling
     328``request.session.set_expiry()`` as described above in
     329`using sessions in views`_.
     330
    281331Clearing the session table
    282332==========================
    283333
Back to Top