Created
January 25, 2013 16:43
-
-
Save timewald/4635904 to your computer and use it in GitHub Desktop.
Sample of refactored Ring session middleware to separate request pre-processing and response post-processing for use with async HTTP processing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ns ring.middleware.session | |
"Session manipulation." | |
(:require [ring.middleware.cookies :as cookies] | |
[ring.middleware.session.store :as store] | |
[ring.middleware.session.memory :as mem])) | |
(defn session-options | |
[options] | |
{:store (options :store (mem/memory-store)) | |
:cookie-name (options :cookie-name "ring-session") | |
:cookie-attrs (merge {:path "/"} | |
(options :cookie-attrs) | |
(if-let [root (options :root)] | |
{:path root}))}) | |
(defn session-request | |
"Reads current HTTP session map and adds it to :session key of the request." | |
[request & [{:keys [store cookie-name]}]] | |
(let [req-key (get-in request [:cookies cookie-name :value]) | |
session (store/read-session store req-key) | |
session-key (if session req-key)] | |
(merge request {:session (or session {}) | |
:session/key session-key}))) | |
(defn session-response | |
"Updates session based on :session key in response." | |
[{session-key :session/key :as response} & [{:keys [store cookie-name cookie-attrs]}]] | |
(let [new-session-key (when (contains? response :session) | |
(if-let [session (response :session)] | |
(store/write-session store session-key session) | |
(when session-key | |
(store/delete-session store session-key)))) | |
response (dissoc response :session) | |
cookie {cookie-name | |
(merge cookie-attrs | |
(response :session-cookie-attrs) | |
{:value new-session-key})}] | |
(if (and new-session-key (not= session-key new-session-key)) | |
(assoc response :cookies (merge (response :cookies) cookie)) | |
response))) | |
(defn wrap-session | |
"Reads in the current HTTP session map, and adds it to the :session key on | |
the request. If a :session key is added to the response by the handler, the | |
session is updated with the new value. If the value is nil, the session is | |
deleted. | |
The following options are available: | |
:store | |
An implementation of the SessionStore protocol in the | |
ring.middleware.session.store namespace. This determines how the | |
session is stored. Defaults to in-memory storage | |
(ring.middleware.session.store.MemoryStore). | |
:root | |
The root path of the session. Any path above this will not be able to | |
see this session. Equivalent to setting the cookie's path attribute. | |
Defaults to \"/\". | |
:cookie-name | |
The name of the cookie that holds the session key. Defaults to | |
\"ring-session\" | |
:cookie-attrs | |
A map of attributes to associate with the session cookie. Defaults | |
to {}." | |
([handler] | |
(wrap-session handler {})) | |
([handler options] | |
(let [options (session-options options)] | |
(cookies/wrap-cookies | |
(fn [request] | |
(let [new-request (session-request request options) | |
session-key (:session/key new-request) | |
response (-> new-request | |
handler | |
(assoc :session/key session-key))] | |
(when (seq (dissoc response :session/key)) | |
(session-response response options)))))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment