Question about clack.middleware.session

59 views
Skip to first unread message

Karl Heinrichmeyer

unread,
Jun 20, 2012, 5:46:04 AM6/20/12
to clac...@googlegroups.com
Hi,

I'm working at a small webapp build with caveman and so far I really like
the design and idea behind clack and caveman. Reading the sources
I could need a little help to understand the clack session middleware:

There is one thing I don't quite get: The clack.middleware.session:commit method uses the :id
key in the session hash table to identify the id which should be remove from
the store but I can't figure out how the id gets in the session hash table in the first place.
Am I getting this wrong? Is this something that still has to be implemented or is it just not documented?
In the latter case I could add some documentation if somebody explains the design to me :)

Another and related question is how to control the session middleware. For example, what is the
intended way to expire the current session? Just set the key in the clack.session.options
(I currently play around with caveman and modifying the environment directly is a little painful
and doesn't feel right)?

Oh, and I wrote a middleware to handle postmodern connections similar to the clsql middleware.
I could integrate it into clack and send a pull request or patch if there is interest (After I have done some
polishing :) ).

Best regards,

Karl Heinrichmeyer

Annotated source:

(defmethod call ((this <clack-middleware-session>) env)

  (multiple-value-bind (id session) (extract this env)
    (setf (getf env :clack.session) session)
    (let ((options (make-hash-table :test #'equal)))
      (setf (gethash :id options) id)
      (setf (getf env :clack.session.options) options))

    (let ((res (call-next this env)))
      (finalize this env res))))

(defmethod extract ((this <clack-middleware-session>) env)
  "Extract session id and state."
  (let* ((id (extract-id (state this) env))
         (session (when id
                    (fetch (store this) id))))
    (values (or id (generate-id (state this) env))
            (or session (make-hash-table :test #'equal)))))  ;; if the session can not be found then initialize it as a new and empty hash table.

(defmethod finalize ((this <clack-middleware-session>) env res)
  (let ((options (getf env :clack.session.options)))
    (unless (gethash :no-store options)
      (commit this env))
    (if (gethash :expire options)
        (expire this (gethash :id options) res env)
        (save-state this (gethash :id options) res env)))) 

(defmethod commit ((this <clack-middleware-session>) env)
  (let ((session (getf env :clack.session))
        (options (getf env :clack.session.options)))
    (cond
      ((gethash :expire options)
       (remove-session (store this) (gethash :id session)))  ;; get the id from the session hash table, but how does the :id get in there?
      ((gethash :change-id options)
       (remove-session (store this) (gethash :id session))  ;; here it is the same
       (setf (gethash :id options) (generate-id (state this) env))
       (store-session (store this) (gethash :id options) session))
      (t
       (store-session (store this) (gethash :id options) session)))))

Eitarow Fukamachi

unread,
Jun 21, 2012, 6:28:59 AM6/21/12
to clac...@googlegroups.com
Hi, Karl.
I'm Eitarow, a developer of Clack and Caveman.

> There is one thing I don't quite get: The clack.middleware.session:commit
> method uses the :id
> key in the session hash table to identify the id which should be remove from
> the store but I can't figure out how the id gets in the session hash table
> in the first place.
> Am I getting this wrong? Is this something that still has to be implemented
> or is it just not documented?
> In the latter case I could add some documentation if somebody explains the
> design to me :)

You mean, where does clack.middleware.session generate a random key
for a session?
clack.middleware.session uses clack.session.state:generate-id and it
also uses clack.util:generate-random-id.
You can change how to generate an id by setting (slot-value
{clack.session.state instance} :sid-generator) or make your own state
class inheriting clack.middleware.state.

> Another and related question is how to control the session middleware. For
> example, what is the
> intended way to expire the current session? Just set the key in the
> clack.session.options
> (I currently play around with caveman and modifying the environment directly
> is a little painful
> and doesn't feel right)?

It seems (setf (gethash :expire (getf env clack.session.options)) t)
is the only way to expire the current session.
I never realized it, but, indeed. This is painful.
I will consider better way (or you will? :) )

> Oh, and I wrote a middleware to handle postmodern connections similar to the
> clsql middleware.
> I could integrate it into clack and send a pull request or patch if there is
> interest (After I have done some
> polishing :) ).

Wow, thanks. This is probably the first time that I heard someone
wrote a Clack middleware.
Send me a pull request later.

Best Regards,
Eitarow Fukamachi

Karl Heinrichmeyer

unread,
Jun 22, 2012, 11:23:46 AM6/22/12
to clac...@googlegroups.com
Hi Eitarow,

First let me thank you for the quick reply.

Am Donnerstag, 21. Juni 2012 12:28:59 UTC+2 schrieb fukamachi:
Hi, Karl.
I'm Eitarow, a developer of Clack and Caveman.

> There is one thing I don't quite get: The clack.middleware.session:commit
> method uses the :id
> key in the session hash table to identify the id which should be remove from
> the store but I can't figure out how the id gets in the session hash table
> in the first place.
> Am I getting this wrong? Is this something that still has to be implemented
> or is it just not documented?
> In the latter case I could add some documentation if somebody explains the
> design to me :)

You mean, where does clack.middleware.session generate a random key
for a session?
 
No, I mean that i could not find any place in the source code where the :id key
in this hash table is actually set. This may be a bug. And expiring the session seems
buggy too: The session/expire method passes a p-list as last argument to state/expire
which expects a hash table at this place. I'll write a bug report and/or fix it.

clack.middleware.session uses clack.session.state:generate-id and it
also uses clack.util:generate-random-id.
You can change how to generate an id by setting (slot-value
{clack.session.state instance} :sid-generator) or make your own state
class inheriting clack.middleware.state.

> Another and related question is how to control the session middleware. For
> example, what is the
> intended way to expire the current session? Just set the key in the
> clack.session.options
> (I currently play around with caveman and modifying the environment directly
> is a little painful
> and doesn't feel right)?

It seems (setf (gethash :expire (getf env clack.session.options)) t)
is the only way to expire the current session.
I never realized it, but, indeed. This is painful.
I will consider better way (or you will? :) )
 
Maybe a some simple helper functions like (clack.session:expire env)
or (clack.session:expire-session env)? Since this is even worse in caveman (you have to
unpack env from the request) I also would suggest a helper function to access env conveniently (like context).
This is the solution I use at the moment in my application:

(defun env (&optional key)
  (if key
      (getf (clack.request:env *request*) key)
      (clack.request:env *request*)))

(defun set-env (key-or-val &optional val)
  (with-slots ((env-slot clack.request:env)) *request*
    (if val
    (setf (getf env-slot key-or-val) val)
    (setf env-slot key-or-val))))

(defsetf env set-env)
 
This helper is setf-able too. Again, if you are interested I'll write a patch (it may take a while till
if have some spare time).


> Oh, and I wrote a middleware to handle postmodern connections similar to the
> clsql middleware.
> I could integrate it into clack and send a pull request or patch if there is
> interest (After I have done some
> polishing :) ).

Wow, thanks. This is probably the first time that I heard someone
wrote a Clack middleware.
Send me a pull request later.
 
Consider it done, but again, it might take a while. 


Best Regards,
Eitarow Fukamachi


Best Regards,

Karl
 
Reply all
Reply to author
Forward
0 new messages