# session module

## Synopsis

The `session` module provides way to group HTTP requests into "sessions" so that information can be maintained between an individual user's requests to various parts of a web site - for example, so that a user can "log in" to the web site and their username remembered as they navigate the site.

## Usage

The base `Session` class is not used directly, since it has no way of storing the data associated with a session. Instead, one of the classes derived from it are used. The choice of subclass determines what storage method is used - the module provides `FileSession` and `GenericSQLSession`, or you can write your own.

To store data in the session, you simply use it as a mapping. For example:

`if "basket" in self.session:
self.session["basket"].append(newitem)
else:
self.session["basket"] = [newitem]`

Sessions are identified by a unique 8-character hexadecimal string, which is usually generated randomly. This is paired with another 8-character hexadecimal string which is a keyed hash generated using the identifier and a secret key unique to the individual web site. The hash simply makes it a bit more difficult for an attacker to guess a valid session identifier. The id and hash are stored in the session under the keys `id` and `hash`, so don't try to use these keys for storing your own data.

The session identifier and hash are passed from request to request using cookies. Note that some users disable cookies in their browsers, so site code will need to detect this situation and either cope without sessions, or show the user an error message.

This module used to provide a method for embedding the session identifier in the URL, but this has now been deprecated.

To create and maintain the session, a session class should be instantiated at the start of processing a request, and its `save` method called at the end of processing.

Example:

`class Handler(wt.Handler):
def process(self, req):
self.session = session.FileSession(req, "s3cr3t")
if not self.session.relocated:
wt.Handler.process(self, req)
self.session.save()`

## class: Error(Exception)

The base class for all exceptions defined by the `session` module.

## class: Session(dict)

`Session` objects manage the session as well as providing a container to store data associated with the session. This class is not used directly, but is subclassed depending on what method is being used to store the session data.

### Public Instance Variables

#### `created`

The number of seconds since the epoch (i.e. `time.time()` value) when this session was created.

#### `new`

`new` references a true value if the session was created during this request (i.e. there was no pre-existing session).

### Public Methods

#### `__init__(self, req, secret, cookie="jonsid", root="",
sid=None, shash=None, secure=0, domain=None, create=True)`

`req`: `cgi.Request` instance
`secret`: string
`cookie`: string
`root`: string
`sid`: string
`shash`: string
`secure`: true or false value
`domain`: string
`create`: true or false value

This method may be overridden by subclasses. It creates a new `Session` instance. `secret` is a secret key (i.e. any arbitrary string that you do not disclose) which is used for keying the hash used to verify session identifiers (see `_make_hash`). This value should be unique for each web site, unless you are deliberately trying to share session identifiers between sites.

`cookie` is the name of the session cookie which is used to store the session identifier. There is usually no need to change this from the default of `jonsid`. If `secure` is true then the 'secure' flag of the cookie will be set, which tells browsers not to send the cookie if the connection is not encrypted. If `domain` is set then this will be used as the 'domain' parameter for the cookie. `root` is used as the 'path' parameter for the cookie, with a `/` appended.

If you wish to identify the session in some other way than cookies, you can set `cookie` to `None` and then pass in the session identifier in `sid`. You may optionally also pass in the identifier hash in `shash` - if you do then the session identifier will be ignored and a new session created if the hash does not match the identifier. If you omit the `shash` parameter then the identifier will be assumed correct.

After initialisation has completed, the session dictionary contains the session identifier under key `id`, the identifier hash under key `hash`, and if the session was not new, any stored information from previous requests.

If `create` is false then the session will not be created if an existing session cannot be found. In this case, the session identifier in key `id` will be `None`. A new session may then be manually created by calling the `create` method.

#### `create(self)`

This method creates a new session. If the `cookie` parameter to `__init__` was not `None` then a `Set-Cookie` header will be created.

#### `save(self)`

This method may be overridden by subclasses. It stores the information from the current session's dictionary so that it may be retrieved in later requests. The default implementation does nothing.

### Public Static Methods

#### `tidy()`

This method may be overridden by subclasses. It is used to delete session information that has expired, and should therefore be called periodically, perhaps from a `cron` job. Subclass versions of this method may require different parameters to the function - you cannot call this method without knowing the particulars of the particular subclass being used. The default implementation does nothing.

### Protected Instance Variables

#### `_req`

The `cgi.Request` instance passed to the session's `__init__` method.

### Protected Methods

#### `_make_hash(self, sid, secret)`

`sid`: string
`secret`: string
Returns: string

This method may be overridden by subclasses. It returns the 8-character hexadecimal string which is a keyed hash of the session identifier `sid` and the secret key `secret`. The default implementation uses HMAC-SHA, and should not usually need to be overridden.

#### `_create(self, secret)`

`secret`: string

This method may be overridden by subclasses. It creates a new unique 8-character hexadecimal session identifier and initialises it in whatever storage system is being used. `self["id"]` should be set to the session identifier. Optionally, `self["hash"]` may also be set to the identifier hash. If the hash is not set then `_make_hash` will be called subsequently to determine it. The default implementation simply sets `self["id"]` to a random identifier.

#### `_load(self)`

This method may be overridden by subclasses. It updates the session's dictionary with whatever information the storage system has recorded about the session with identifier `self["id"]`. It should return `1` if the session identifier was located in the storage system, or `0` if it was not (in which case a new session will be created). The default implementation simply returns `1`.

Note that this method should only return `0` if the session information could not be located because it did not exist. If any other error occurs (e.g. an I/O error while searching for the session), then an exception should be raised as usual.

## class: FileSession(Session)

The `FileSession` class is a subclass of `Session` that uses the filesystem to store session data.

### Public Methods

#### `__init__(self, req, secret, basedir=None, **kwargs)`

`req`: `cgi.Request` instance
`secret`: string
`basedir`: string

Creates a new FileSession instance. Session data will be stored using individual files in the filesystem, under the `basedir` directory. If `basedir` is not specified then the environment variable `TMPDIR` is used instead, or if there is no such environment variable then `/tmp` is used. A directory is created under this named `jon-sessions-%d` where `%d` is the current user id. If this directory already exists then it must be owned by the current user. `req`, `secret`, and `kwargs` are passed to the base class's `__init__` method.

#### `save(self)`

The session's dictionary is written to the filesystem.

### Public Static Methods

#### `tidy(max_idle=0, max_age=0, basedir=None)`

`max_idle`: integer
`max_age`: integer
`basedir`: string

Deletes session files that have expired. If `max_idle` is non-zero then it is the maximum number of seconds old a file's modification time may be before it is deleted. If `max_age` is non-zero then it is the maximum number of seconds old a session may be (since it was created) before it is deleted.

### Protected Methods

#### `_create(self, secret)`

`secret`: string

Creates the session identifier and its associated file.

#### `_load(self)`

Updates the session's dictionary with the stored information from the session's file. Returns `0` if the file did not exist, otherwise `1`.

## class: GenericSQLSession(Session)

The `GenericSQLSession` class is a subclass of `Session` that uses an SQL database to store session data.

### Public Methods

#### `__init__(self, req, secret, dbc, table="sessions", **kwargs)`

`req`: `cgi.Request` instance
`secret`: string
`dbc`: Python DB API `Cursor` instance
`table`: string

Creates a new GenericSQLSession instance. Session data will be stored using rows in an SQL table. The database is accessed via the `Cursor` instance `dbc` and the table name `table`. `req`, `secret`, and `kwargs` are passed to the base class's `__init__` method.

The table must have at least the following fields:

`CREATE TABLE sessions (
ID CHAR(8) NOT NULL,
hash CHAR(8) NOT NULL,
data BLOB NOT NULL,
created INT NOT NULL,
updated INT NOT NULL,
PRIMARY KEY (ID)
);`

This class has only been tested with MySQL, although the intention is that it should work with any DB API database.

#### `save(self)`

The session's dictionary is written to the database.

### Public Static Methods

#### `tidy(dbc, table="sessions", max_idle=0, max_age=0)`

`dbc`: Python DB API `Cursor` instance
`table`: string
`max_idle`: integer
`max_age`: integer

Deletes session rows that have expired. If `max_idle` is non-zero then it is the maximum number of seconds old a session's `updated` time may be before it is deleted. If `max_age` is non-zero then it is the maximum number of seconds old a session's `created` time may be before it is deleted.

### Protected Methods

#### `_create(self, secret)`

`secret`: string

Creates the session identifier and its associated table row.

#### `_load(self)`

Updates the session's dictionary with the stored information from the session's database row. Returns `0` if the row was not found, otherwise `1`.

$Id: session.html,v 0416d65875b7 2014/03/05 17:37:06 jon $