Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

http.session.store

import http.session.store

http lifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelled http.session.store.* needs import http.session.store.

What a session store is, and the error every one of them raises.

A store is the only part of a session that touches durable state. It never sees a session identifier, only the key derived from one, and it never sees the session’s contents, only the opaque string the session layer serialised them into. That split is what lets a store be swapped without the rest of the stack knowing, and what lets a leaked store - a directory listing, a database dump, a backup tape - hand over nothing that can be replayed as a cookie.

Implementing one means five methods: read(), write(), destroy(), gc(), and optionally touch(), which has a working default built on the first two.

class RedisStore < session.SessionStore {
  @new(client) {
    self._client = client
  }

  read(key) {
    return self._client.get('session:' + key)
  }

  write(key, payload, expires_at) {
    var ttl = (expires_at - time()).ceil()

    self._client.set_with_ttl('session:' + key, payload, ttl)
  }

  destroy(key) {
    self._client.remove('session:' + key)
  }

  gc(now) {
    # Redis expires keys itself.
    return 0
  }
}

Functions

storage_key()

http.session.storage_key(id: string) -> string

The key a store files a session under: the SHA-256 of the session identifier, as 64 lowercase hex characters.

Storing the digest rather than the identifier means the contents of a store cannot be turned back into cookies. Someone who reads the directory, the table, or a backup of either learns what is in the sessions but cannot resume one, because the value the browser presents is the preimage.

It also settles the shape of a key once and for all: 64 hex characters make a safe filename and a fixed-width primary key, whatever a client put in its cookie.

Parameters

  • id (string)

Returns string

Classes

SessionError

class http.session.SessionError < HttpError

Raised when a session cannot be read, written or configured: a storage directory that cannot be created or is open to other users on the machine, a payload larger than the configured ceiling, an unknown option, or a store method an implementation forgot.

It is an HttpError, so a server already catching those catches this as well.

  • printable — has a @to_string(), so echo and print() show something useful

SessionError.to_string()

http.session.SessionError.to_string()

SessionStore

class http.session.SessionStore

What every session store implements.

The methods here raise SessionError, so a store that forgets one fails where the gap is rather than somewhere further down.

Every timestamp is epoch seconds, as time() reports them.

Fields

FieldTypeDescription
gc_probabilitynumberThe chance, between 0 and 1, that a write also sweeps expired sessions.

SessionStore.read()

http.session.SessionStore.read(key: string) -> ?string

The payload stored under key, or nil when there is none or the one there has expired.

A store that finds an expired entry removes it rather than leaving it for the sweep.

Parameters

  • key (string)

Returns ?string

SessionStore.write()

http.session.SessionStore.write(key: string, payload: string, expires_at: number)

Stores payload under key, replacing whatever was there, and records when it stops being valid.

Parameters

  • key (string)
  • payload (string)
  • expires_at (number)

SessionStore.touch()

http.session.SessionStore.touch(key: string, expires_at: number)

Moves the expiry of an existing entry without rewriting its contents, which is what a rolling idle timeout does on a request that only read the session.

The default reads the payload and writes it back. A store whose backend can change the expiry on its own - a single-column UPDATE, a TTL command - overrides this with that.

Parameters

  • key (string)
  • expires_at (number)

Returns — bool: whether an entry was there to touch

SessionStore.destroy()

http.session.SessionStore.destroy(key: string)

Removes the entry stored under key. Removing one that is not there is not an error.

Parameters

  • key (string)

SessionStore.gc()

http.session.SessionStore.gc(now: number)

Removes every entry that expired on or before now.

Parameters

  • now (number)

Returns — number: how many entries were removed

SessionStore.maybe_gc()

http.session.SessionStore.maybe_gc()

Runs gc() with probability gc_probability, and otherwise does nothing. A store calls this from its own write().

A sweep that fails raises out of the write that triggered it: a store that cannot sweep is a store that will not be able to write for much longer either, and swallowing that hides a full disk or a dead connection until the next outage.

Returns — bool: whether a sweep ran

SessionStore.close()

http.session.SessionStore.close()

Releases whatever the store holds open. The default does nothing, which is right for a store that holds nothing.


2026, Richard Ore and Zuri contributors