To store data client-side, put it in a cookie. Cookies have a name and a value. There are some restrictions on what the name can be: stick with just alphabet characters and you'll be okay.
First, you have to send the cookie to the client:
(defmethod handle-request-response ((handler intro-handler) method request) (request-send-headers request :set-cookie (cookie-string "cookiename" "cookievalue")) (html-stream (request-stream request) `(html (body (p "Cookie set.")))))
Afterwards, this cookie value will be available via a call to REQUEST-COOKIE.
(defmethod handle-request-response ((handler show-cookie) method request) (request-send-headers request) (html-stream (request-stream request) `(html (body (p "The cookie value is: " ,(request-cookie request "cookiename"))))))
To set a new value for the cookie, re-send the cookie as above.
There are more parameters to cookie-string than shown here, they are all keyword parameters. To have the above be a session cookie (deleted when the browser is closed):
(cookie-string "cookiename" "cookievalue" :max-age 0)
To see the full parameter list:
(documentation 'cookie1:cookie-string 'function)
It is possible for another website to send your site a cookie without you being aware of it. If dan.example.com set a cookie like so:
(cookie-string "bad" "cookie" :domain ".example.com")
and your website was ann.example.com, you would receive that cookie.
If your web app does not use domain cookies, it's best to ignore them - which would ignore the above cookie.
(request-safe-cookie request "my" nil)
If you do use domain cookies, it's best to specify the domains you will accept explicitly.
(request-safe-cookie request "my" ".example.com")
This will not stop all instances, but it's a good start.
When you request a specific cookie, there is the possibility that it won't be found. Sometimes it's easier to assume the cookie is found, and set up a signal handler for when it isn't.
The REQUEST-COOKIE and REQUEST-SAFE-COOKIE methods take a keyword parameter that can enable signaling an error.
(handler-case (request-cookie request "mycookie" :on-fail :signal-condition) (cookie-not-found (condition) (format *trace-output* "Cookie not found! ~A" condition)))
By default the methods return nil.