diff --git a/README.markdown b/README.markdown index e870f77..07096f8 100644 --- a/README.markdown +++ b/README.markdown @@ -87,6 +87,12 @@ session data might be lost at any time! If cookie-only sessions have not been disabled, then small sessions will still be stored in cookies (this is faster than memcache). +If you want to exclude certain URLs from session generation use the `ignore_paths` +parameter, which should contain a regular expression. Not generating Cookies is +important in certian HTTP caching scenarios. E.g. + + app = SessionMiddleware(app, cookie_key=COOKIE_KEY, ignore_paths='^/images/.*$') + You will also want to create a cronjob to periodically remove expired sessions from the datastore. You can find the [example cronjob](http://github.com/dound/gae-sessions/tree/master/demo/cron.yaml) and @@ -135,8 +141,8 @@ for authentication Here's a few lines of example code too: session.regenerate_id() -_Author_: [David Underhill](http://www.dound.com) -_Updated_: 2011-Jul-03 (v1.07) +_Author_: [David Underhill](http://www.dound.com) +_Updated_: 2011-Jul-03 (v1.07) _License_: Apache License Version 2.0 For more information, please visit the [gae-sessions webpage](http://wiki.github.com/dound/gae-sessions/). diff --git a/gaesessions/__init__.py b/gaesessions/__init__.py index 01caf6f..9d03095 100644 --- a/gaesessions/__init__.py +++ b/gaesessions/__init__.py @@ -7,6 +7,7 @@ import logging import pickle import os +import re import threading import time @@ -446,16 +447,19 @@ class SessionMiddleware(object): memcache/datastore latency which is critical for small sessions. Larger sessions are kept in memcache+datastore instead. Defaults to 10KB. """ - def __init__(self, app, cookie_key, lifetime=DEFAULT_LIFETIME, no_datastore=False, cookie_only_threshold=DEFAULT_COOKIE_ONLY_THRESH): + def __init__(self, app, cookie_key, lifetime=DEFAULT_LIFETIME, no_datastore=False, cookie_only_threshold=DEFAULT_COOKIE_ONLY_THRESH, ignore_paths=None): self.app = app self.lifetime = lifetime self.no_datastore = no_datastore self.cookie_only_thresh = cookie_only_threshold self.cookie_key = cookie_key + self.ignore_paths = ignore_paths if not self.cookie_key: raise ValueError("cookie_key MUST be specified") if len(self.cookie_key) < 32: raise ValueError("RFC2104 recommends you use at least a 32 character key. Try os.urandom(64) to make a key.") + if self.ignore_paths: + self.ignore_paths = re.compile(self.ignore_paths) def __call__(self, environ, start_response): # initialize a session for the current user @@ -463,10 +467,13 @@ def __call__(self, environ, start_response): # create a hook for us to insert a cookie into the response headers def my_start_response(status, headers, exc_info=None): - _tls.current_session.save() # store the session if it was changed - for ch in _tls.current_session.make_cookie_headers(): - headers.append(('Set-Cookie', ch)) - return start_response(status, headers, exc_info) + if self.ignore_paths and self.ignore_paths.match(environ['PATH_INFO']): + return start_response(status, headers, exc_info) + else: + _tls.current_session.save() # store the session if it was changed + for ch in _tls.current_session.make_cookie_headers(): + headers.append(('Set-Cookie', ch)) + return start_response(status, headers, exc_info) # let the app do its thing return self.app(environ, my_start_response)