;;; -*- Mode: Lisp -*- (in-package #:lml2) (html-file-page ("readme") (html (:head (:title "cl-modlisp readme") ((:meta :http-equiv "Content-Type" :content "text/html; charset=iso-8859-1")) ((:meta :name "Copyright" :content "Kevin Rosenberg 2002 ")) ((:meta :name "description" :content "cl-modlisp documentation")) ((:meta :name "author" :content "Kevin Rosenberg")) ((:meta :name "keywords" :content "Common Lisp, mod_lisp, cl-modlisp, apache"))) (:body (:h1 "cl-modlisp Documentation") (:h2 "Overview") (:p "cl-modlisp provides the Lisp side of the interface to Marc Battyani's mod_lisp apache module (" ((:a :href "http://www.fractalconcept.com") "http://www.fractalconcept.com") ").") (:h2 "Features") (:ul (:li "support for AllegroCL, CMUCL, SBCL with sb-thread, and Lispworks.") (:li "listener and worker socket/process management so that shutting down the listener closes all related open sockets and terminates all related proceses.") (:li "support for running multiple command processors on multiple ports.") (:li "transparent support for precomputing the HTML or XML response to take advantage of HTTP/1.1's Keep-Alive feature. This is switchable with a single keyword argument to the macro " (:tt "with-ml-page") ".") (:li "Optional timeout of worker processes") (:li "Two process models for flexibility") (:li "Demonstration processor included")) (:h2 "Prerequisites") (:ul (:li "Apache 1.3.x") (:li "mod_lisp apache module (" ((:a :href "http://www.fractalconcept.com") "http://www.fractalconcept.com") ").") (:li "kmrcl library (" ((:a :href "http://files.kpe.io/kmrcl") "http://files.kpe.io/kmrcl") ").") (:li "asdf (" ((:a :href "http://www.sf.net/projects/cclan") "http://www.sf.net/projects/cclan") ").")) (:h2 "Supported Platforms") (:ul (:li "Allegro v6.2") (:li "CMUCL 18e") (:li "Lispworks v4.2") (:li "SBCL 0.8.1 with sb-thread (multi-threading)")) (:h2 "Quickstart") (:ul (:li "The easiest way to install is to use the Debian GNU/Linux operating system. Using the testing or unstable distributions, you can give the command:" (:div (:tt "apt-get install libapache-mod-lisp cl-modlisp cl-kmrcl")) (:div "If you are not using Debian, you will need to download and install mod_lisp, cl-modlisp, and cl-kmrcl manually.")) (:li "Add something like the below to httpd.conf and then restart apache" (:div (:tt "LispServer 127.0.0.1 20123 \"localhost\"")) (:div (:tt "AddHandler lisp-handler .lsp"))) (:li "Start your Lisp implementation and load cl-modlisp with" (:div (:tt "(asdf:operate 'asdf:load-op 'modlisp)"))) (:li "Start the server with" (:div (:tt "(ml:modlisp-start :port 20123)"))) (:li "Try some demostration pages" (:div (:tt "links http://localhost/fixed.lsp")) (:div (:tt "links http://localhost/debug.lsp"))) (:li "Shutdown the all cl-modlisp servers with" (:div (:tt "(ml:modlisp-stop-all)")))) (:h2 "Process Models") (:p "There are two process models") (:ul (:li (:div (:b "Each connection spawns a new thread")) (:div "This is the default model. Each new connection to listener socket spawns a new connection. This allows for an arbitrary number of concurrent connections. This has advantages if the workers require a long execution time.")) (:li (:div (:b "Fixed pool of workers")) (:div "This model is selected by passing the number of worker processes to " (:tt "init/listener") " with the keyword " (:tt "number-fixed-workers") ". This model has a lower overhead since new processes are not created and destroyed with each connection. It has advantages when the workers have a short execution time."))) (:h2 "Usage") (:p "The demo.lisp file for examples of using cl-modlisp.") ) (:ul) (:li (:div (:strong "Overview")) (:div "cl-modlisp is a multi-threaded handler for HTTP requests forwarded by Marc Battyani's (http://www.fractalconcept.com) mod_lisp Apache module.")) (:li (:div (:strong "Design Goals")) (:div "cl-modlisp is designed as a thin layer to dispatch a mod_lisp request with multi-platform compatibility. Currently, cl-modlisp supports SBCL [multithreaded], CMUCL, AllegroCL, and Lispworks.")) (:li (:div (:strong "Dispatch model")) (:div "Extremely simple: All requests are forwarded to a single processor that is passed as a parameter to cl-modlisp's start-up function.")) (:li (:div (:strong "Configuration")) (:div "All configuration is set by passing keyword arguments to modlisp-start") (:ul (:li "port number - a number") (:li "processor - function designator which will receive all requests") (:li "processor-args - list of extra arguments to be passed to processor") (:li "timeout - NIL means never timeout otherwise number of seconds") (:li "catch-errors - non-NIL means to catch errors") (:li "number-fixed-workers - NIL means to spawn a new worker process for each request") (:li "remote-host-checker - optional function designator to check the remote host IP address. Used for filtering requests."))) (:li (:div (:strong "Processor function")) (:div "This function receives an argument of the 'command' alist and any other arguments passed to modlisp-start as the :processor-args. The 'command' alist is an associative list of keys and values received from modlisp. No preprocessing is done except that keys are converted from strings to keywords forced to the default implementation case.")) (:li (:div (:strong "Default Processor")) (:div "The default processor is a simple demo command processor not intended for end-user.")) (:li (:div "URI Processing") (:div "None. The raw URL is the value of the :url key in the command alist.")) (:li (:div "Responses") (:div "Responses are written to modlisp:*modlisp-socket*. The raw HTTP/1.1 header needs to be generated by the application.")) (:li (:div "Utility functions") (:div "A few utility functions are provided") (:ul (:li (:div "with-ml-page") (:div "Outputs the body of the macro along with the HTTP/1.1 headers. Supports both precomputing responses with keep-alive connections and also outputing response to socket as it is generated. The latter is useful for lengthye reponses in time or length. Also support setting the content-type (default \"text/html\") and arbitrary list of headers.")) (:li (:div "query-to-alist") (:div "Converts posted query to an alist. Doesn't handle multipart forms.")) (:li (:div "redirect-to-location")))) (:li (:div (:strong "Known issues")) (:ul (:li "This application has been most tested on AllegroCL.") (:li (:p "By design, is not practical an application platform. It is should have an API package wrapped around this library which supports useful features like processing URIs, dispatches, cookies, and querys [URI and single/multipart POSTs]") (:p "Rather than adding these features to cl-modlisp, I've been working on a library which uses a session-id and dispatch model based on Franz's webactions library. It also integrates my portable version of Franz's URI module and adds query processing similar on AllegroServer's request-query functions. This library can used with both cl-modlisp and AllegroServe as connectors. However, as this library has grown, it looks more and more like AllegroServe, I've begun to question the value of using this library compared to just using Portable AllegroServe with just my webactions-like session-id and dispatch processors. In my mind, the greatest advantage of using this library is that it is a much smaller task maintaining cross-implementation compatibility with the cl-modlisp connector version maintaining such compatibility with paserve. The disadvantage of this library is that I dislike cloning AllegroServe's query and cookie processing. I do so, though, because I think their API is quite reasonable. This library is currently driving http://umlisp.kpe.io/") )))))