New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not clear on how to implement custom session handling #135

Closed
ckonstanski opened this Issue Mar 2, 2018 · 5 comments

Comments

Projects
None yet
2 participants
@ckonstanski
Copy link

ckonstanski commented Mar 2, 2018

This isn't a bug report or anything. I'm just seeking help understanding something in the docs regarding custom session handling.
The docs say:
"The other way to customize Hunchentoot's sessions is to completely replace them. This is actually pretty easy: Create your own class to store state (which doesn't have to and probably shouldn't inherit from SESSION) and implement methods for SESSION-VERIFY and SESSION-COOKIE-VALUE - that's it."
I looked at these two methods. One is a method that specializes on request' and the other specializes on session'. I'm trying to understand what exactly is meant by "mplement methods for SESSION-VERIFY and SESSION-COOKIE-VALUE". Those two methods already exist. Do I do something like the following?

  • Write new methods that look like the existing ones do -- that is, they specialize on hunchentoot::request' and hunchentoot:session'. I'll have to shadow those method symbols because they are exported. Or I'll have to enter the hunchentoot package and define these methods there. But then there will be two identically-named methods with the same specialization. How will hunchentoot know to run mine instead of its own? Is it just because mine will be compiled later and therefore overwrite the original ones?

I feel like I'm not getting it. This scenario isn't playing out cleanly at all. What am I not getting?

@hanshuebner

This comment has been minimized.

Copy link
Member

hanshuebner commented Mar 2, 2018

You need to understand the difference between a generic function and its method. The generic functions SESSION-VERIFY and SESSION-COOKIE-VALUE already exist, and they have methods that are specialized for Hunchentoot's own SESSION class. What you need to do is define your own session class and define methods that specialize SESSION-VERIFY and SESSION-COOKIE-VALUE for its instances. Hunchentoot will call the generic functions and if the session that it finds in the request is an instance of your own session class, Common Lisp will invoke the method that is specialized on that class.

The manual does not attempt to explain generic dispatch in Common Lisp. The Practical Common Lisp book by Peter Seibel has a chapter on generic functions that may help you understand it better.

@ckonstanski

This comment has been minimized.

Copy link

ckonstanski commented Mar 2, 2018

That bit "if the session that it finds in the request is an instance of your own session class" is critical to understanding the call tree, at least in part. I do understand generics, and that is why I was wondering how hunchentoot would know to specialize on my session class. I could write session classes all day, but if hunchentoot is not made aware of them somehow, they would just sit there idle. I still need to figure out how to get my session object into the request, but this is a great headstart.

That solves half the problem. session-verify' is still an issue. It does not specialize on session', but rather request'. I'll poke around and see if I can figure out how I will insinuate my version of session-verify' into the call tree given that I am not writing my own `request' class.

I wonder if I will discover that session-verify' is the thing that puts my session' into the request? Rhetorical question. I'll find out soon enough. The weekend is almost here.

@hanshuebner

This comment has been minimized.

Copy link
Member

hanshuebner commented Mar 2, 2018

A quick peek into the source reveals this docstring:

(defgeneric session-verify (request)
  (:documentation "Tries to get a session identifier from the cookies
\(or alternatively from the GET parameters) sent by the client (see
SESSION-COOKIE-NAME and SESSION-COOKIE-VALUE).  This identifier is
then checked for validity against the REQUEST object REQUEST.  On
success the corresponding session object \(if not too old) is returned
\(and updated).  Otherwise NIL is returned.

A default method is provided and you only need to write your own one
if you want to maintain your own sessions."))

@hanshuebner hanshuebner closed this Mar 2, 2018

@ckonstanski

This comment has been minimized.

Copy link

ckonstanski commented Mar 2, 2018

I'm in the source code, thanks. Comments are nice but the code is what matters. You will notice that this generic specializes on REQUEST. Now look at the INITIALIZE-INSTANCE method for REQUEST. You will see this inside:

(setq session (session-verify request)

How do I make the hunchentoot REQUEST object's constructor call my SESSION-VERIFY method? I am not supplying a different REQUEST class. This is the hunchentoot REQUEST class all the way. If SESSION-VERIFY specialized on SESSION then I would see a way forward. But it doesn't.

@hanshuebner

This comment has been minimized.

Copy link
Member

hanshuebner commented Mar 3, 2018

Think about it and read the source:

https://github.com/edicl/hunchentoot/blob/master/acceptor.lisp#L408

      (make-instance (acceptor-request-class acceptor)
                     :acceptor acceptor
                     :local-addr local-addr
                     :local-port local-port
                     :remote-addr remote-addr
                     :remote-port remote-port
                     :headers-in headers-in
                     :content-stream content-stream
                     :method method
                     :uri uri
                     :server-protocol server-protocol))))

The request class is a parameter of the acceptor. You'll need your own request class as well, that is the way how you can specialize SESSION-VERIFY to return your own session class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment