[cursory once-over for approximate correctness dan**20031109032717] { hunk ./doc/PLAN 10 -** Exporting servers - -** Exporting handlers and how they get matched to requests +** Adding listeners hunk ./doc/PLAN 12 -** URL accessors +** Installing handlers and how they get matched to requests hunk ./doc/PLAN 15 + +** URL accessors addfile ./doc/example.lisp hunk ./doc/example.lisp 1 +(defpackage "MY-ARANEIDA-EXAMPLE" + (:use "CL" "ARANEIDA")) +(in-package :my-araneida-example) + +(eval-when (:compile-toplevel :load-toplevel :execute) + ;; This is for using Araneida behind a reverse-proxying + ;; Apache (or other HTTP proxy) server. You may need to alter the + ;; configuration for your local setup + #+nil (pushnew :araneida-uses-proxy *features*) + ;; if you have a threaded SBCL, and want to, you can use the (new, + ;; whizzy) thread-based server instead of the (older, better tested) + ;; SERVE-EVENT thing + #+(and nil sb-thread) (pushnew :araneida-uses-threads *features*)) + +(defvar *demo-url* + ;; if you have a reverse proxy that can bind to port 80, you might + ;; want to change the port number here. Otherwise, you probably + ;; don't want to run araneida as root, so leave this > 1024 unless + ;; you have some spiffy way of letting non-root apps get + ;; hold of privileged ports. + (make-url :scheme "http" :host (long-site-name) :port 8000)) + +#-araneida-uses-proxy +(defvar *listener* + (make-instance #+araneida-uses-threads 'threaded-http-listener + #-araneida-uses-threads 'serve-event-http-listener + :port (url-port *demo-url*))) + +#+araneida-uses-proxy +(defvar *listener* + (make-instance #+araneida-uses-threads 'threaded-http-listener + #-araneida-uses-threads 'serve-event-http-listener + :address #(127 0 0 1) + :port (+ 8000 (url-port *demo-url*)))) + +#+araneida-uses-proxy +(install-handler (http-listener-handler *listener*) + (make-instance 'reverse-proxy-handler + :external-url *demo-url*) + (format nil "http://localhost:~D/" + (+ 8000 (url-port *demo-url*))) + nil) + +(defclass hello-handler (handler) + ((hits :initform 0 :accessor hello-hits))) +(defclass reset-handler (handler) + ((hello :initarg :hello :initform (error "missing required argument") + :reader reset-hello))) + + +(defmethod handle-request-response ((handler hello-handler) method request) + (let ((hits (incf (hello-hits handler)))) + (when (zerop (mod hits 7)) + (signal 'araneida::http-payment-required "Game Over. Insert coin")) + (request-send-headers request) + (html-stream + (request-stream request) + `(html (head (title "Hello world")) + (body (h1 "Hello") + (p "There have been " ,hits + " accesses to this page since the last " + ((a :href "reset") "reset"))))))) + +(defmethod handle-request-response ((handler reset-handler) method request) + (let ((hello (reset-hello handler))) + (setf (hello-hits hello) 0) + (request-redirect request "hello") + t)) + +(let ((hello (make-instance 'hello-handler))) + (install-handler (http-listener-handler *listener*) + hello + (urlstring (merge-url *demo-url* "/hello")) t) + (install-handler (http-listener-handler *listener*) + (make-instance 'reset-handler :hello hello) + (urlstring (merge-url *demo-url* "/reset")) t)) + + +;;; if we're going to serve static files, we should configure the known +;;; MIME types to something useful +(setf *content-types* (read-mime-types "/etc/mime.types")) + +;;; point the root url at a static view of the Araneida sources +(let* ((pn (or *load-pathname* *default-pathname-defaults*)) + (dir (merge-pathnames (make-pathname :name nil :type nil) pn))) + (install-handler (http-listener-handler *listener*) + (make-instance 'static-file-handler :pathname dir) + (urlstring *demo-url*) nil)) + +;;; ready to rock? +#| +(start-listening *listener*) +|# + hunk ./doc/examples.html 11 -CL-on-Unix free resources link farm +CL-on-Unix free resources link farm. The same software is also used +on the ALU Wiki hunk ./doc/examples.html 14 -
  • metacircles, CL ad SBCL +
  • metacircles, CL and SBCL hunk ./doc/examples.html 16 + +
  • Stargreen Box Office: gig +listings and online ticket booking for London/UK pop and rock concerts. hunk ./doc/handlers.html 23 -

    When you have a suitable handler class, you need to install an -instance of it into the URL space somewhere. For example, +

    An http-listener points at a +dispatching-handler (which is usually created along with the listener); +typically you install your handlers as child handlers of that root. + +For example, hunk ./doc/handlers.html 30 -(install-handler *root-handler* +(install-handler (http-listener-handler *my-listener*) hunk ./doc/handlers.html 34 -installs a STATIC-FILE-HANDLER into the system, to answer requests -starting with http://ww.noetbook.telent.net/tmp/logo +installs a STATIC-FILE-HANDLER to answer requests starting with +http://ww.noetbook.telent.net/tmp/logo hunk ./doc/handlers.html 40 -Again, CLiki is the best example of doing this in practice. +CLiki is a real-world example of this technique. hunk ./doc/handlers.html 44 -

    When a request comes in, the *root-handler*'s handle-request method -is invoked on it. *root-handler* is a dispatching-handler, so calls -whichever appropriate subhandler you've installed for the URL. If you -install more dispatching-handlers, the dispatch will happen again. +

    When a request comes in, the http-listener's root handler's +handle-request method is invoked on it. This is usually a +dispatching-handler, so calls whichever appropriate subhandler you've +installed for the URL. If you install more dispatching-handlers, the +dispatch will happen again. hunk ./doc/handlers.html 70 + +

    Errors

    + +

    HTTP errors (e.g. 404, 500) can be signalled with SIGNAL; see the +example. For a list of condition names, +see http-errors.lisp. hunk ./doc/handlers.html 151 -

    Look at static-file-handler.lisp and redirect-handler.lisp for a -couple of examples. To see more complicated stuff, grab the -source for CLiki and poke -around in there. +

    Look at example.lisp for "Hello World", +then static-file-handler.lisp and redirect-handler.lisp in the +source distribution for some slightly more complex examples. To see +really interesting stuff, grab the source for CLiki and poke around in there. hunk ./doc/index.html 9 -sit behind a proxying Apache. +sit behind a proxying Apache but also capable of being run standalone. hunk ./doc/index.html 66 -$Date: 2003/06/16 16:26:19 $

    Daniel Barlow
    +$Date: 2003/11/09 03:27:17 $
    Daniel Barlow
    hunk ./doc/installation.html 71 -then cut and paste the following into a file and load it - -
    -(defpackage "MY-ARANEIDA-EXAMPLE"
    -   (:use "CL" "ARANEIDA"))
    -(in-package :my-araneida-example)
    -
    -;;; we need to tell araneida about one or more servers first
    -(defvar *araneida-site-name* "my.host.name.example.com")
    -(defvar *araneida-url* 
    -   (make-instance 'http-url :host *araneida-site-name*
    -                            :port 8000))
    -(defvar *araneida-server*
    -  (make-instance 'server
    -                 :name *araneida-site-name*
    -                 :base-url *araneida-url* :port 8000))
    -(export-server *araneida-server*)
    -
    -;;; if we're going to serve static files, we could configure the known
    -;;; MIME types to something useful
    -(setf *content-types* (read-mime-types "/etc/mime.types"))
    -
    -;;; At any time after Araneida knows about the
    -;;; my.host.name.example.com site, we can install handlers that
    -;;; refer to it.  For example, 
    -
    -(install-handler *root-handler* 
    -                 (make-instance 'static-file-handler 
    - 	                        :pathname #p"/var/www/html/") 
    -                 "http://my.host.name.example.com:8000/static-files/" 
    -                 nil) ;T - exact matches only, NIL - also match URLs
    -                      ;that this is a prefix for
    -
    -;;; ready to rock?  Set up threads or SERVE-EVENT handlers (depending
    -;;; on what's available and/or personal preference) to handle requests
    -;;; in the background
    -
    -#+sb-threads (install-thread-handlers)
    -#-sb-threads (install-serve-event-handlers)
    -
    -
    - -

    Point your browser at http://my.host.name.example.com:8000/ to test - -

    Use with a proxy

    - -

    -

  • You need *araneida-url* (the external published URL of the site) -to refer to the hostname and port of the proxy instead of the actual -Araneida server. - -
    -(defvar *araneida-url* 
    -   (make-instance 'http-url :host *araneida-site-name*))
    -
    -;;; then export a server using this url, as previously 
    -
    -;;; now make araneida write out some file for Apache to include
    -(with-open-file (conf "/etc/apache.conf.include"
    -                      :direction :output
    -                      :if-does-not-exist :create)
    -  (output-apache-conf conf))
    +then compile and load doc/example.lisp in
    +the source distribution.  For more information, study that file
    +carefully and read the rest of this documentation.
    hunk ./doc/installation.html 76
    -
  • Now prepare an Apache installation with proxy support. Configure it -to include /etc/apache.conf.include or whatever file you -wrote out above. +

    Point your browser at http://your.host.name:8000/ to test hunk ./doc/installation.html 78 -

    Configuring Apache is Outside The Scope of these instructions, but -as a start, here are the relevant lines from my Debian laptop: +

    If you want to use Araneida mod_proxy (generally recommended), you +have to configure that too. Configuring Apache is Outside The Scope +of these instructions, but as a start, here are the relevant lines +from my Debian laptop: hunk ./doc/installation.html 87 - -

  • Start or restart Apache - -
  • Fire up a web browser. Browse. - -
  • Observe that the toplevel also still works - -
  • Look at the Handlers documentation to -see how to write your own handlers - -
  • Send me mail and tell me how -badly broken these instructions are. And, ideally, in what ways. hunk ./doc/installation.html 89 - hunk ./doc/reference.html 3 -Araneida: a free CMUCL-based web server +Araneida: a free SBCL-based web server hunk ./doc/reference.html 11 -
  • Exporting servers +
  • HTTP Listeners hunk ./doc/reference.html 20 + hunk ./doc/troubleshooting.html 8 +

    Handler debugging

    + +

    The special variable *BREAK-ON-HANDLER-ERRORS* governs whether +errors signalled during handler execution should drop you into the +debugger or not. If it's NIL, you just get a backtrace on +*trace-output* and processing continues as normal. Obviously this is +recommended for production sites. + +

    The THREADED-HTTP-LISTENER also has a timeout for responses: any +thread spending more than *HANDLER-TIMEOUT* seconds in a response will +be automatically timed out and made to select the ABORT-RESPONSE +restart so that it can answer another request. The default timeout is +60, which is probably too short in all situations that it is not too long. + hunk ./doc/troubleshooting.html 24 -

    The thread support has not been tested particularly hard, and +

    The thread support has not been hammered on very hard, and hunk ./doc/troubleshooting.html 26 -particularly hard. Note in particular that the number of worker -threads is fixed where it should really be adjusted dynamically to -cope with load. If you run into weird threading bugs, (a) I'd like to +particularly hard. If you run into weird threading bugs, (a) I'd like to hunk ./doc/troubleshooting.html 37 -

    +

    Note that a thread in the debugger will eventually be reset by the +timeout mechanism (see above). hunk ./doc/troubleshooting.html 40 - -CL-USER(16): (araneida::install-handlers) -(18770 18769 18768 18767 18766) -CL-USER(19): -debugger invoked on condition of type UNBOUND-VARIABLE: - The variable ARANEIDA::HEADERS is unbound. - - -Thread 18766 suspended -CL-USER(19): :fo 18766 -Focusing on next thread waiting waiting for the debugger -restarts (invokable by number or by possibly-abbreviated name): - 0: [DESTROY-THREAD] Destroy this thread (18766) -(ARANEIDA::READ-HEADERS #<FILE-STREAM for "descriptor 7" {9D37E91}>) -

    - -Note that a thread in the debugger will eventually timeout and return -to handling requests. The timeout (in seconds) is given by -*handler-timeout* and the default value of 60 is probably -wrong for just about everything. }