Salient features
Note: SBCL and CMUCL are confirmed to work as of araneida-0.9-a3. The others are believed to work, but are not currently in the test suite. Updates appreciated.
Download ASDF package from http://common-lisp.net/project/araneida/release/araneida-latest.tar.gz
Alan Shields maintains a current Araneida linked here. Darcs repository and (some) older versions available for download.
It is not currently active. Latest patch to source tree is from january 2006. Seems that hunchentoot stole the show from araneida.
The last version of Araneida released by Daniel Barlow is maintained in the Darcs repository located at http://verisons.telent.net/araneida, and the sources can be browsed at http://verisons.telent.net/cgi-bin/darcs.cgi.
You may find references to documentation at araneida.telent.net, but that site is no more. Docs are in the doc/ sub-directory of the source tree.
The easiest place to figure out how to start serving pages with Araneida is the example file in doc/example.lisp. A pretty syntax highlighted version of this can be served via Lisppaste, which is served via Araneida.
Discussion about Araneida takes place in the lispweb mailing list.
Fare Rideau is maintaining a CLiki installation; it depends on a slight patch to araneida, that is available on the Tunes CVS site.
FWIW, to use SLIME to debug Araneida request handlers, I use :sigio and the following method:(from Thomas F. Burdick on comp.lang.lisp, article id xcv3c0p6nhn.fsf@conquest.OCF.Berkeley.EDU)(defmethod handle-request :around ((handler my-handler) request) (if *debug* (let ((*debugger-hook* 'swank:swank-debugger-hook)) (handler-bind ((error #'invoke-debugger)) (call-next-method))) (call-next-method)))
Because Araneida blocks any other serve-event handlers from running while it's handling a request, it doesn't mix well with :fd-handler if you try to invoke the SLIME debugger.
Also see this paste
Araneida was originally designed to run behind a reverse-proxying Apache server, and still works best that way. I (Brian Mastenbrook) have also found that the Pound reverse proxying server works well. Here is my pound.cfg:
ListenHTTP *,3580 UrlGroup "favicon" EndGroup UrlGroup ".*" BackEnd 127.0.0.1,3500,1 EndGroup
This filters out the silly favicon.ico requests which are inevitably a 404. It's possibly by using the UrlGroup regexp syntax to redirect requests for static content to an Apache on the same host as well. Though I haven't tested it, Pound does HTTPS too.
First, remove the :external-format argument from listener-accept-stream in compat-clisp.lisp and make it look like:
(defun listener-accept-stream (listener)
(socket:socket-accept (http-listener-socket listener)
:buffered nil
:element-type 'character))
The default format will be sufficient, and previously hard-coded iso-8859-1 doesn't permit use of UTF-8.
Second, make urlstring-unescape in url.lisp conditionally evaluated:
#-(or unicode sb-unicode allegro)
(defun urlstring-unescape (url-string)
(do* ((n 0 (+ n 1))
(out '()))
((not (< n (length url-string))) (coerce (reverse out) 'string ))
(let ((c (elt url-string n)))
(setf out
(cond ((eql c #\%)
(progn (setf n (+ 2 n))
(cons (code-char
(or (parse-integer
url-string :start (- n 1)
:end (+ n 1)
:junk-allowed t
:radix 16) 32))
out)))
((eql c #\+)
(cons #\Space out))
(t (cons c out)))))))
#+clisp
(defun baityvstroku (baity)
(ext:convert-string-from-bytes baity CUSTOM:*DEFAULT-FILE-ENCODING*))
#+sb-unicode
(defun baityvstroku (baity)
(sb-ext:octets-to-string (coerce baity '(vector (unsigned-byte 8)))))
#+allegro
(defun baityvstroku (baity)
(octets-to-string
(coerce baity '(array (unsigned-byte 8) (*))) :external-format :utf-8))
#+(or unicode sb-unicode allegro)
(defun urlstring-unescape (url-string)
(do* ((n 0 (+ n 1))
(out nil) (len (length url-string)))
((not (< n len))
(baityvstroku (apply #'vector (nreverse out))))
(let ((c (elt url-string n)))
(cond ((eql c #\%)
(progn
(setf n (+ 2 n))
(if (< n len)
(push (or (parse-integer
url-string :start (- n 1)
:end (+ n 1)
:junk-allowed t
:radix 16) 32)
out))))
((eql c #\+)
(push (char-code #\Space) out))
(t (push (char-code c) out))))))
Again, this change will allow use of UTF-8 (or any other encoding) in get and post parameters.
I (Richard Newman) just implemented URIQA on top of Wilbur and Araneida.
The Araneida request class has a body for POST requests. read-request-from-stream parses the HTTP body into an assoc list with the following line (line 27, daemon.lisp):
(parsed-body (if body (parse-body body '(#\&) len) nil))
This is perfectly sane behaviour for x-www-form-urlencoded POST bodies (e.g. first=value&second=value). However, for all other bodies it is destructive and nonsensical (particularly XML, which uses = for attributes). Unfortunately, I'm working with those other bodies e.g. application/rdf+xml.
My initial hack was to put in a simple test on the Content-Type header:
(parsed-body (if body
;; Use member on the raw assoc list to make sure we catch requests
;; with multiple Content-Types.
(if (member "application/x-www-form-urlencoded"
(cdr (assoc :content-type headers)) :test #'string=)
(parse-body body '(#\&) len)
body)
nil))
i.e. only parse the body if we have form-encoded data; otherwise just use the body string (one could also url-unencode the body string). This split has the unfortunate side effect that for some requests (request-body request) will return an assoc list, and for others a string. I don't know what consequences this would have on existing code. (stringp) is one remedy; another would be to provide body-data and body-parsed (or similar names) slots on request, rather than just body. I would think that if Araneida-based applications are using the parsed data (and it's valid/correct) then their clients must be sending the correct headers (e.g. wget sends x-www-form-urlencoded by default), so putting this check in wouldn't break anything, but I might be wrong.
Thoughts, anyone?
Well, both the parsed and uparsed bodies seem to be passed in as part of your request. Access the one you need. Although it woulud seem quite possible to invoke different parsing methods via a quick lookup of the content-type in the header - which has already been parsed at this stage. I think I'm looking at a different version to you. The code is no longer on line 27.
I (Arnaud Diederen) have been using Araneida to set up a webservice that receives XML requests (based on OGC specs). To parse the XML I'm using CXML, that accepts a byte stream.
Therefore, I hacked araneida a tad so it doesn't parse it's body content anymore but rather provides the byte stream instead of parsed data. I actually don't think it is be a bad idea to have an access to the raw stream. (Still, I built a set of tools to build 'helpers' on top of the request (basically, the request's content-type defines what helper to build)).
.. but I keep wondering if I should go on using araneida to do that kind of work, or rather use another web server.
Arnaud Diederen, 12 July 2005
((defun convert-address (address)
"Convert IP address to string."
(etypecase address
(string address)
(vector (format nil "~{~d.~^~}" (map 'list #'identity address)))))
(defparameter *default-backlog* 10)
(defun host-make-listener-socket (address port)
(socket:socket-server port :backlog *default-backlog*
:interface (convert-address address)))
defun host-serve-events-once (&optional block)
"one-shot duplicate of host-serve-events. Returns integer."
(aif (mapcar #'car *fd-handlers*)
(loop for i in *fd-handlers*
for j in (socket:socket-status it (if block nil 0))
do (if j
(funcall (cdr i) (car i))))) 0)
; Uncomment this to handle connections while in repl
; (setf readline:event-hook #'araneida::host-serve-events-once)
Few further notes:
Tomas Zellerin, 11 January 2006
Page in this topic: Fract
Also linked from: Alan Shields Brian Cully Changes In Winter 2000-2001 chavatar cirCLe Task List CL-AJAX cl-blog CLiki CLiki Installation CLiki News Common String Current recommended libraries Daniel Barlow Elephant Geiriadur Gentoo HTML-from-sexpr Javascript Lisp newbie Lisppaste LSP Marko Kocic scribble TBNL Texticl web yaclml
CLiki pages can be edited by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively