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. .. testsetup:: * from pesto.session.memorysessionmanager import MemorySessionManager from pesto.testing import TestApp import pesto from pesto import Response @pesto.to_wsgi def app(request): return Response(["Whoa Nelly!"]) original_app = app def FakeFileSessionManager(path): return MemorySessionManager() Here's an example application using sessions: .. testcode:: 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: .. testcode:: 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: .. testcode:: 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. Cookie persistence ------------------ This is the default method and is usually preferred as it is transparent both to users and the application developer. However not all browsers accept cookies and cookies cannot easily be passed between applications running on different domains, for these reasons you may still prefer the querystring based approach. Cookie based persistence is the default method so no extra code is required to enable this: .. testcode:: app = pesto.session_middleware(FileSessionManager('/path/to/session/store'))(app) Setting the cookie path and domain ``````````````````````````````````` When using cookie based persistence cookies are by default tied to the path and domain on which the application is running. To override this, you can specify the cookie path and domain when constructing the session middleware: .. testcode:: :hide: app = original_app FileSessionManager = FakeFileSessionManager .. testcode:: app = pesto.session_middleware( FileSessionManager('/path/to/session/store'), cookie_path='/', cookie_domain='.example.org', )(app) .. testcode:: :hide: response = TestApp(app).get('/foo', SCRIPT_NAME='/foo') print response.get_headers('Set-Cookie') .. testoutput:: :hide: ...Domain=.example.org;Path=/... If you are using the ``filesessionmanager`` this could be used to share session state between WSGI applications running on the same server mounted on different subdomains or paths. Querystring persistence ------------------------ To set up a pesto application with querystring based persistence: .. testcode:: :hide: app = original_app FileSessionManager = FakeFileSessionManager .. testcode:: app = pesto.session_middleware( FileSessionManager('/path/to/session/store'), persist='querystring' )(app) .. testcode:: :hide: response = TestApp(app).get('/foo', SCRIPT_NAME='/foo') print response.get_headers('Location') .. testoutput:: :hide: .../foo?pesto_session=... 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):: ... 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 ------------------------------- .. automodule:: pesto.session.base :members: .. automodule:: pesto.session.memorysessionmanager :members: .. automodule:: pesto.session.filesessionmanager :members: