Merge pull request #2580 from pallets/session-attrs
improve documentation for session attributes
This commit is contained in:
commit
26f413e1e5
2 changed files with 47 additions and 27 deletions
|
|
@ -10,6 +10,7 @@
|
||||||
"""
|
"""
|
||||||
import hashlib
|
import hashlib
|
||||||
import warnings
|
import warnings
|
||||||
|
from collections import MutableMapping
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from itsdangerous import BadSignature, URLSafeTimedSerializer
|
from itsdangerous import BadSignature, URLSafeTimedSerializer
|
||||||
|
|
@ -19,43 +20,55 @@ from flask.helpers import is_ip, total_seconds
|
||||||
from flask.json.tag import TaggedJSONSerializer
|
from flask.json.tag import TaggedJSONSerializer
|
||||||
|
|
||||||
|
|
||||||
class SessionMixin(object):
|
class SessionMixin(MutableMapping):
|
||||||
"""Expands a basic dictionary with an accessors that are expected
|
"""Expands a basic dictionary with session attributes."""
|
||||||
by Flask extensions and users for the session.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _get_permanent(self):
|
@property
|
||||||
|
def permanent(self):
|
||||||
|
"""This reflects the ``'_permanent'`` key in the dict."""
|
||||||
return self.get('_permanent', False)
|
return self.get('_permanent', False)
|
||||||
|
|
||||||
def _set_permanent(self, value):
|
@permanent.setter
|
||||||
|
def permanent(self, value):
|
||||||
self['_permanent'] = bool(value)
|
self['_permanent'] = bool(value)
|
||||||
|
|
||||||
#: this reflects the ``'_permanent'`` key in the dict.
|
#: Some implementations can detect whether a session is newly
|
||||||
permanent = property(_get_permanent, _set_permanent)
|
#: created, but that is not guaranteed. Use with caution. The mixin
|
||||||
del _get_permanent, _set_permanent
|
# default is hard-coded ``False``.
|
||||||
|
|
||||||
#: some session backends can tell you if a session is new, but that is
|
|
||||||
#: not necessarily guaranteed. Use with caution. The default mixin
|
|
||||||
#: implementation just hardcodes ``False`` in.
|
|
||||||
new = False
|
new = False
|
||||||
|
|
||||||
#: for some backends this will always be ``True``, but some backends will
|
#: Some implementations can detect changes to the session and set
|
||||||
#: default this to false and detect changes in the dictionary for as
|
#: this when that happens. The mixin default is hard coded to
|
||||||
#: long as changes do not happen on mutable structures in the session.
|
#: ``True``.
|
||||||
#: The default mixin implementation just hardcodes ``True`` in.
|
|
||||||
modified = True
|
modified = True
|
||||||
|
|
||||||
#: the accessed variable indicates whether or not the session object has
|
#: Some implementations can detect when session data is read or
|
||||||
#: been accessed in that request. This allows flask to append a `Vary:
|
#: written and set this when that happens. The mixin default is hard
|
||||||
#: Cookie` header to the response if the session is being accessed. This
|
#: coded to ``True``.
|
||||||
#: allows caching proxy servers, like Varnish, to use both the URL and the
|
|
||||||
#: session cookie as keys when caching pages, preventing multiple users
|
|
||||||
#: from being served the same cache.
|
|
||||||
accessed = True
|
accessed = True
|
||||||
|
|
||||||
|
|
||||||
class SecureCookieSession(CallbackDict, SessionMixin):
|
class SecureCookieSession(CallbackDict, SessionMixin):
|
||||||
"""Base class for sessions based on signed cookies."""
|
"""Base class for sessions based on signed cookies.
|
||||||
|
|
||||||
|
This session backend will set the :attr:`modified` and
|
||||||
|
:attr:`accessed` attributes. It cannot reliably track whether a
|
||||||
|
session is new (vs. empty), so :attr:`new` remains hard coded to
|
||||||
|
``False``.
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: When data is changed, this is set to ``True``. Only the session
|
||||||
|
#: dictionary itself is tracked; if the session contains mutable
|
||||||
|
#: data (for example a nested dict) then this must be set to
|
||||||
|
#: ``True`` manually when modifying that data. The session cookie
|
||||||
|
#: will only be written to the response if this is ``True``.
|
||||||
|
modified = False
|
||||||
|
|
||||||
|
#: When data is read or written, this is set to ``True``. Used by
|
||||||
|
# :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie``
|
||||||
|
#: header, which allows caching proxies to cache different pages for
|
||||||
|
#: different users.
|
||||||
|
accessed = False
|
||||||
|
|
||||||
def __init__(self, initial=None):
|
def __init__(self, initial=None):
|
||||||
def on_update(self):
|
def on_update(self):
|
||||||
|
|
@ -63,8 +76,6 @@ class SecureCookieSession(CallbackDict, SessionMixin):
|
||||||
self.accessed = True
|
self.accessed = True
|
||||||
|
|
||||||
super(SecureCookieSession, self).__init__(initial, on_update)
|
super(SecureCookieSession, self).__init__(initial, on_update)
|
||||||
self.modified = False
|
|
||||||
self.accessed = False
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
self.accessed = True
|
self.accessed = True
|
||||||
|
|
|
||||||
|
|
@ -221,12 +221,21 @@ def test_endpoint_decorator(app, client):
|
||||||
def test_session(app, client):
|
def test_session(app, client):
|
||||||
@app.route('/set', methods=['POST'])
|
@app.route('/set', methods=['POST'])
|
||||||
def set():
|
def set():
|
||||||
|
assert not flask.session.accessed
|
||||||
|
assert not flask.session.modified
|
||||||
flask.session['value'] = flask.request.form['value']
|
flask.session['value'] = flask.request.form['value']
|
||||||
|
assert flask.session.accessed
|
||||||
|
assert flask.session.modified
|
||||||
return 'value set'
|
return 'value set'
|
||||||
|
|
||||||
@app.route('/get')
|
@app.route('/get')
|
||||||
def get():
|
def get():
|
||||||
return flask.session['value']
|
assert not flask.session.accessed
|
||||||
|
assert not flask.session.modified
|
||||||
|
v = flask.session.get('value', 'None')
|
||||||
|
assert flask.session.accessed
|
||||||
|
assert not flask.session.modified
|
||||||
|
return v
|
||||||
|
|
||||||
assert client.post('/set', data={'value': '42'}).data == b'value set'
|
assert client.post('/set', data={'value': '42'}).data == b'value set'
|
||||||
assert client.get('/get').data == b'42'
|
assert client.get('/get').data == b'42'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue