[new 'examples' subdirectory dan**19991223015144 new 'examples' subdirectory new doc directory which will eventually have useful documentation in it ] { adddir ./doc addfile ./doc/index.html hunk ./doc/index.html 1 +Araneida + +Araneida: a free CMUCL-based web server + + +

Araneida: a free CMUCL-based web server

+ +

Araneida is the third version of a small extensible CL-based web +server that I wrote as a project to learn CL. That's a +circumlocutious way to say that it may not be a really great body of +code to learn Lisp style from. + +

Features/non-features

+ + +

What you need

+ + + + +

Where to get it

+ +

Here + +

Individual files for the current CVS version are also near that +URL, if you can guess their names. Directory listings for the flat +file server are, I guess, in the next version... + +

How to install it

+ +

Nobody has really got nice clean installation sorted out for CL +programs, afaics. I tend to take the view that exposing people to the +gritty Lisp details is probably more constructive than wrapping it all +up in shell scripts that don't work on anyone else's system. So, +installation takes a bit of fiddling. +

    + +
  1. Make your defsystem know how to find araneida.system. This +probably means putting it into the current directory or a directory in +your *central-registry* list (see mk-defsystem docs) + +
  2. In the examples/ directory, copy +loaclhost-telent-net.lisp to the appropriate name for your computer: +usually this is the FQDN with #\. replaced by #\_) but if you +get the wrong name it will stop and ask when you try to build the thing. + +
  3. Prepare an Apache installation with proxy support. Configure it +to include /tmp/apache.cf.inc or whatever you specified for +*apache-config-segment* above. + +

    Configuring Apache is Outside The Scope of these instructions, but +as a start, here's what I do on my Debian laptop: +

    +LoadModule proxy_module /usr/lib/apache/1.3/libproxy.so
    +NameVirtualHost localhost
    +Include /tmp/apache.cf.inc
    +
    +(localhost should be the machine's actual hostname usually, +but this thing has to run both standalone and on two different +networks, and it's too much of a headache to make it behave entirely +reasonably) + +
  4. (make:compile-system 'araneida) + +
  5. (araneida::install-serve-event-handlers) ;; start serving + +
  6. Fire up a web browser + +
  7. (araneida::remove-serve-event-handlers) ;; stop serving + +
  8. Read ../examples/main.lisp +to see how it works +
adddir ./examples addfile ./examples/defpackage.lisp hunk ./examples/defpackage.lisp 1 +(in-package :user) +(defpackage "TELENTWEB" + (:use "MAKE" "COMMON-LISP" "ARANEIDA" "USER")) addfile ./examples/loaclhost-telent-net.lisp hunk ./examples/loaclhost-telent-net.lisp 1 +(in-package :telentweb) + +(defvar *static-pages-directory* "/usr/local/doc/telent/htdocs/") +(defvar *lisp-source-directory* "/usr/local/doc/telent/") +(defvar *telent-site-name* "loaclhost.telent.net") +(defvar *apache-config-segment* "/tmp/apache.cf.inc") addfile ./examples/main.lisp hunk ./examples/main.lisp 1 +(in-package :telentweb) + +(defvar *home-page-hits* 0) +(defun another-hit () + (princ-to-string (incf *home-page-hits*))) + +(defvar *telent-url* (make-instance 'http-url :host *telent-site-name*)) +(defvar *telent-server* + (make-instance 'server + :name *telent-site-name* + :base-url *telent-url* :port 8000)) +(export-server *telent-server*) + + +(defun counter-handler (request rest-of-url) + (http-server:request-send-headers request) + (princ + (html + `(html + (head ((link :rel "stylesheet" :href "/dan.css")) + (title "Telent Netowrks")) + (body + (h1 "Telent Netowrks") + (p ,(urlstring (request-url request))) + (p (i "Networking solutions for poor typists")) + (p ,(another-hit) " hits to this page since I last restarted Lisp")))) + (request-stream request))) + +(export-handler (merge-url *telent-url* "/counter") + 'counter-handler :match :prefix :method t :stage :response) + +(export-handler *telent-url* + `(file-request-handler ,*static-pages-directory*) + :method t) + +(export-handler (merge-url *telent-url* "/code/") + `(file-request-handler ,*lisp-source-directory*) + :method t) + +(export-handler (merge-url *telent-url* "/wait") + (lambda (r rest) + (httpsrv:request-send-headers r :content-type "text/plain") + (sleep 15) + (princ "done" (request-stream r))) + :match :exact) + +(export-handler (merge-url *telent-url* "/lisp/") + (lambda (r rest) + (format t "Logging ~A~%" (request-url r))) + :stage :log) + +(export-handler (merge-url *telent-url* "/error") + (lambda (r rest) (/ 1 0))) + +(export-handler *telent-url* + (lambda (r rest) + (format t "Error: ~A~%" (request-condition r)) + (request-send-error r 500 + (format nil "~A" (request-condition r)))) + :stage :error) + + +(defun run () + (discard-errors + 'httpsrv:server-start)) + + +;; OK, let's roll + +(with-open-file (conf *apache-config-segment* + :direction :output + :if-does-not-exist :create) + (output-apache-conf conf)) + +(format t "Bits of apache config file are to be found in \"~A\" +Evaluate (RUN) to start up" + *apache-config-segment*) + + + addfile ./examples/search.lisp hunk ./examples/search.lisp 1 +(in-package :telentweb) + +(defun search-handler (request rest-of-url) + (http-server:request-send-headers request) + (let ((term (url-query-param (request-url request) "TERM" ))) + (/ 1 0) + (princ + (html + `(html + (head (title "Search")) + (body + (h1 "Search results") + ((form :action ,(urlstring (request-original-url request))) + ((input :type text :name term :value ,term))) + (hr) + (ol (li "foo")))))))) + +(export-handler "*" "/search" 'search-handler) addfile ./examples/tninkpad-telent-net.lisp hunk ./examples/tninkpad-telent-net.lisp 1 - +(in-package :telentweb) + +(defvar *static-pages-directory* "/home/dan/doc/telent/htdocs/") +(defvar *telent-site-name* "tninkpad.telent.net") +(defvar *apache-config-segment* "/tmp/apache.cf.inc") +;; NB: trailing / on the following is significant +(defvar *lisp-source-directory* "/home/dan/src/telent/") }