[hunchentoot-devel] Middleware with Hunchentoot

Zach Beane xach at xach.com
Fri Jul 20 10:19:53 UTC 2007


On Thu, Jul 19, 2007 at 10:11:58PM -0600, Robert Uhl wrote:
> >From Python's WSGI I've gotten the idea of middleware--that is, stuff
> which runs around user-defined code in some user-defined order.  A
> null-effect middleware function might be defined like this:
> 
>   (defun null-effect (request next)
>     (when next
>       (funcall next request)))
> 
> One can see how a middleware function could set things up for the
> user-defined handler, could decide whether or not to call the user's
> handler and could override whatever that handler returns.
> 
> A convenience macro def-middleware might make it possible to write the
> null-effect function like this:
> 
>   (def-middleware null-effect (request)
>     (call-next-middleware))
> 
> And the user might be able to create a dispatcher thus:
> 
>   (create-regex-dispatcher "/foo/bar?baz" (null-effect #'my-handler))
> 
> Obviously middleware could be chained:
> 
>   (create-regex-dispatcher "/foo/bar?baz"
>                            (authentication (caching #'my-handler)))
> 
> Question: does this seem like a reasonable way to handle middleware,
> particularly authentication/authorisation mechanisms?  I'm fairly new to
> Lisp, but it _seems_ like it's a fairly Lispy way to go about things.
> 
> Thoughts?

These are called "closures".

Here's a function I use in several places:

  (defun call-with-protection (&key username password realm function)
    "Return a closure that calls FUNCTION if the remote username and
  password match USERNAME and PASSWORD, or returns an authorization
  required response otherwise."
    (lambda ()
      (multiple-value-bind (web-username web-password)
	  (authorization)
	(if (and web-username web-password
		 (string= web-username username)
		 (string= web-password password))
	    (funcall function)
	    (require-authorization realm)))))

Here's an example use;

  (wf:serve-function (wf:call-with-protection :username "blubba"
					      :password "frink"
					      :realm "roflbot"
					      :function 'recent-page)
		     "/roflbot/recent")

The FUNCTION argument to CALL-WITH-PROTECTION could be another closure
generator, and these could be chained as much or as little as you
like.

Zach



More information about the Tbnl-devel mailing list