[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 -
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 + +
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 - -
-
-(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 -
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 - -
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 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. }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}>) -