Session storage

Sessioning provides a persistant storage for arbitrary data between user requests. Typically the user is sent a cookie containing a randomly generated identification string in the response to the first request to the WSGI application. This session cookie is used to identify the browser session and Pesto makes a data store available in the variable request.session that is persistent between requests in the same session.

A middleware layer must be added to the application that deals with setting and checking the session cookie.

As an alternative to using cookies the session identfier may also be passed around in the querystring portion of the URL, however this requires special care when writing the application to include the session identifier in every URL generated by your application.

Here’s an example application using sessions:

from pesto import DispatcherApp
app = DispatcherApp()

@app.match('/login', 'POST')
def login(request):

    username = request.get('username')
    password = request.get('password')

    if is_valid(username, password):
        request.session['username'] = username
        request.session['logged_in'] = True


@app.match('/secure-area', 'GET')
def secure_area(request):

    if not request.session.get('logged_in'):
        return response.redirect(login.url())

    return ["Welcome to the secure area, %s" % request.session['username']]


from pesto.session.filesessionmanager import FileSessionManager

# Create a file based sessioning middleware, that runs a purge every 600s
# for sessions older than 1800s..
sessioning = pesto.session_middleware(
    FileSessionManager('/path/to/session/store'),
    auto_purge_every=600,
    auto_purge_olderthan=1800
)

app = sessioning(app)

Sessioning needs some kind of data storage backend. The two backends available in Pesto are memory and file backed storage.

File backend

Synopsis:

from pesto.session.filesessionmanager import FileSessionManager
app = pesto.session_middleware(FileSessionManager('/path/to/session/store'))(app)

This backend is the most generally useful storage backend. Session data is stored in one file per session, using Python’s pickle module to store and retrieve data from disk. The application must have access to a writable directory, which for security reasons should not be readable by other users.

Memory backend

Synopsis:

from pesto.session.memorysessionmanager import MemorySessionManager
app = pesto.session_middleware(MemorySessionManager())(app)

This implementation stores data directly in a python data structure stored in memory. Session data can’t be shared between processes and is lost when the process finishes, so it is not useful for CGI or architectures that do not use long-running processes or architectures that split requests between multiple processes. In general it is recommended to use the file backend which does not suffer from these problems.

Preserving state between requests

There are two built in methods for associating a session with a user request, using either HTTP cookies or the URI querystring.

Querystring persistence

To set up a pesto application with querystring based persistence:

app = pesto.session_middleware(
        FileSessionManager('/path/to/session/store'),
        persist='querystring'
)(app)

When querystrings are used it is necessary for all links generated by the application to contain a reference to the session id. Thus code to generate a link would typically look like this (this example uses the Genshi page template syntax):

<a href="/some-page?pesto_session=${request.session.session_id}">...</a>

Pesto doesn’t contain any code to support rewriting links output by your application, it is up to you to ensure the querystring is always present in links.

Any GET requests that do not contain a session id will be redirected by the session middleware to a URL containing a fresh session identifier if one is not already present.

pesto.session API documention

Web session management.

pesto.session.base.session_middleware(session_manager, auto_purge_every=60, auto_purge_olderthan=1800, persist='cookie', cookie_path=None, cookie_domain=None)

WSGI middleware application for sessioning.

Synopsis:

>>> from pesto.session.memorysessionmanager import MemorySessionManager
>>> def my_wsgi_app(environ, start_response):
...     session = environ['pesto.session']
... 
>>> app = session_middleware(MemorySessionManager())(my_wsgi_app)
>>> 
session_manager
An implementation of pesto.session.base.SessionManagerBase
auto_purge_every
If non-zero, a separate thread will be launched which will purge expired sessions every auto_purge_every seconds. In a CGI environment (or equivalent, detected via, environ['wsgi.run_once']) the session manager will be purged after every request.
auto_purge_olderthan
Auto purge sessions older than auto_purge_olderthan seconds.
persist

Either cookie or querystring. If set to cookie then sessions will be automatically persisted via a session cookie.

If querystring then the session-id will be read from the querystring. However it is up to the underlying application to ensure that the session-id is embedded into all links generated by the application.

cookie_path
The path to use when setting cookies. If None this will be taken from the SCRIPT_NAME variable.
cookie_domain
The domain to use when setting cookies. If None this will not be set and the browser will default to the domain used for the request.

pesto.session.memorysessionmanager

Store request sessions in memory

Usage:

>>> from pesto.session import session_middleware
>>> from pesto.session.memorysessionmanager import MemorySessionManager
>>> def my_app(environ, start_response):
...     start_response('200 OK', [('Content-Type', 'text/html')])
...     yield "<html>Whoa nelly!</html>"
...
>>> manager = MemorySessionManager()
>>> app = session_middleware(manager)(my_app)
class pesto.session.memorysessionmanager.MemorySessionManager(cache_size=200)

An in-memory session manager.

Synopsis:

>>> from pesto.session import session_middleware
>>> from pesto.session.memorysessionmanager import MemorySessionManager
>>> manager = MemorySessionManager()
>>> def app(environ, start_response):
...     "WSGI application code here"
...
>>> app = session_middleware(manager)(app)
>>>
cache_size
The maximum number of session objects to store. If zero this will be unlimited, otherwise, a least recently used cache mechanism will be used to store only up to cache_size objects.

pesto.session.filesessionmanager

Store request sessions in flat files.

Usage:

>>> from pesto.session import session_middleware
>>> from pesto.session.filesessionmanager import FileSessionManager
>>> def my_app(environ, start_response):
...     start_response('200 OK', [('Content-Type', 'text/html')])
...     yield "<html>Whoa nelly!</html>"
...
>>> manager = FileSessionManager('./sessions')
>>> app = session_middleware(manager)(my_app)
class pesto.session.filesessionmanager.FileSessionManager(directory)

A File-backed session manager.

Synopsis:

>>> from pesto.session import session_middleware
>>> from pesto.session.filesessionmanager import FileSessionManager
>>> manager = FileSessionManager('/tmp/sessions')
>>> def app(environ, start_response):
...     "WSGI application code here"
...
>>> app = session_middleware(manager)(app)
>>>
directory
Path to directory in which session files will be stored.
acquire_lock(session_id=None)

Acquire lock for the storage

get_access_time(session_id)

Return the time the given session was last accessed. Note that this uses the underlying filesystem’s atime attribute, so will not work on filesystems mounted with noatime

get_path(session_id)

Return the path to the file where session data is stored.

Synopsis:

>>> from pesto.session.base import Session
>>> fsm = FileSessionManager(directory='/tmp')
>>> session = Session(fsm, 'abcdefgh', True)
>>> fsm.get_path(session.session_id)
'/tmp/_pesto_sessions/ab/abcdefgh'
release_lock(session_id=None)

Release lock for the storage

store(session)

Store session to a file

update_access_time(session_id)

Update session access time, by calling os.utime on the session file.