INTRODUCTION
------------
+
This package provided the Lisp side of the interface to Marc
Battyani's mod_lisp apache module (http://www.fractalconcept.com).
1. Apache 1.3.x
2. mod_lisp apache module (http://www.fractalconcept.com)
-3. cl-kmrcl library (http://files.b9.com/kmrcl)
-4. asdf
+3. kmrcl library (http://files.b9.com/kmrcl)
+4. asdf (http://www.sf.net/projects/cclan)
+
+
+SUPPORTED PLATFORMS
+-------------------
+ Allegro v6.2
+ Lispworks v4.2
+ SBCL 0.8.1 with sb-thread (multitasking)
+ CMUCL 18e
+
QUICKSTART
----------
-1. Install mod_lisp as described on the mod_lisp web site
+1. 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:
+ apt-get install libapache-mod-lisp cl-modlisp cl-kmrcl
+
+If you are not using Debian, you will need to download and install
+mod_lisp, cl-modlisp, and cl-kmrcl manually.
+
2. Add something like the below to httpd.conf and then restart apache
LispServer 127.0.0.1 20123 "localhost"
AddHandler lisp-handler .lsp
-3. Load cl-modlisp and cl-kmrcl
+
+3. Start your Lisp implementation and load cl-modlisp with
+ (asdf:operate 'asdf:load-op 'modlisp)
+
4. Start the server with
(ml:modlisp-start :port 20123))
+
5. Try some demostration pages
lynx http://localhost/fixed.lsp
lynx http://localhost/debug.lsp
+
6. Shutdown the all cl-modlisp servers with
(ml:modlisp-stop-all)
+
+
+USAGE
+-----
+
+Return to the demo.lisp file for some examples of using cl-modlisp.
;;;; Programmer: Kevin M. Rosenberg
;;;; Date Started: Dec 2002
;;;;
-;;;; $Id: base.lisp,v 1.9 2003/07/09 19:19:19 kevin Exp $
+;;;; $Id: base.lisp,v 1.10 2003/07/10 18:58:29 kevin Exp $
;;;; *************************************************************************
(in-package #:modlisp)
-(defun modlisp-start (&key (port +default-apache-port+)
- (processor 'demo-apache-command-processor)
+(defun modlisp-start (&key (port +default-modlisp-port+)
+ (processor 'demo-modlisp-command-processor)
(processor-args nil)
(catch-errors t))
(let ((listener (make-instance 'listener :port port
:base-name "modlisp"
- :function 'apache-command-issuer
+ :function 'modlisp-command-issuer
:function-args (cons processor processor-args)
:format :text
:wait nil
(defun modlisp-stop-all ()
(stop-all/listener))
+;; Internal functions
-(let ((*number-server-requests* 0)
- (*number-worker-requests* 0)
- (*close-apache-socket* t))
-
- (defun apache-command-issuer (*apache-socket* processor &rest args)
- "generates commands from apache, issues commands to processor-fun"
- (unwind-protect
- (progn
- (setq *number-worker-requests* 0)
- (do ((command (read-apache-command) (read-apache-command)))
+(defun modlisp-command-issuer (*modlisp-socket* processor &rest args)
+ "generates commands from modlisp, issues commands to processor-fun"
+ (unwind-protect
+ (progn
+ (let ((*number-worker-requests* 0)
+ (*close-modlisp-socket* t))
+ (do ((command (read-modlisp-command) (read-modlisp-command)))
((null command))
(apply processor command args)
- (force-output *apache-socket*)
+ (force-output *modlisp-socket*)
(incf *number-worker-requests*)
(incf *number-server-requests*)
- (when *close-apache-socket*
- (return))))
- (close-active-socket *apache-socket*)))
-
-
- (defun get-number-worker-requests ()
- *number-worker-requests*)
-
- (defun get-number-server-requests ()
- *number-server-requests*)
-
- (defun set-close-apache-socket (close?)
- (setq *close-apache-socket* close?))
+ (when *close-modlisp-socket*
+ (return)))))
+ (close-active-socket *modlisp-socket*)))
- ) ;; closure
-
(defun header-value (header key)
+ "Returns the value of a modlisp header"
(cdr (assoc key header :test #'string=)))
-(defun read-apache-command ()
+(defun read-modlisp-command ()
(ignore-errors
- (let* ((header (read-apache-header))
+ (let* ((header (read-modlisp-header))
(content-length (header-value header "content-length"))
(content (when content-length
(make-string
(parse-integer content-length :junk-allowed t)))))
(when content
- (read-sequence content *apache-socket*)
+ (read-sequence content *modlisp-socket*)
(push (cons "posted-content" content) header))
header)))
-(defun read-apache-line ()
+(defun read-modlisp-line ()
(kmrcl:string-right-trim-one-char
#\return
- (read-line *apache-socket* nil nil)))
+ (read-line *modlisp-socket* nil nil)))
-(defun read-apache-header ()
- (loop for key = (read-apache-line)
+(defun read-modlisp-header ()
+ (loop for key = (read-modlisp-line)
while (and key
(string-not-equal key "end")
(> (length key) 1))
- for value = (read-apache-line)
+ for value = (read-modlisp-line)
collect (cons key value)))
(defun write-header-line (key value)
- (write-string key *apache-socket*)
- (write-char #\NewLine *apache-socket*)
- (write-string value *apache-socket*)
- (write-char #\NewLine *apache-socket*))
+ (write-string key *modlisp-socket*)
+ (write-char #\NewLine *modlisp-socket*)
+ (write-string value *modlisp-socket*)
+ (write-char #\NewLine *modlisp-socket*))
* New version
- -- Kevin M. Rosenberg <kmr@debian.org> Tue, 8 Jul 2003 07:45:08 -0600
+ -- Kevin M. Rosenberg <kmr@debian.org> Thu, 10 Jul 2003 12:52:34 -0600
cl-modlisp (0.2-1) unstable; urgency=low
;;;; Programmer: Kevin M. Rosenberg
;;;; Date Started: Dec 2002
;;;;
-;;;; $Id: demo.lisp,v 1.2 2003/07/08 06:40:00 kevin Exp $
+;;;; $Id: demo.lisp,v 1.3 2003/07/10 18:58:29 kevin Exp $
;;;; *************************************************************************
(in-package #:modlisp)
-(defun demo-apache-command-processor (command)
- "Sample function to process an apache command"
+(defun demo-modlisp-command-processor (command)
+ "Sample function to process an modlisp command"
(let ((url (header-value command "url")))
(cond
((equal url "/fixed.lsp")
(write-string "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">
<html><head></head>
<body>
-<h1>mod_lisp debug page</h1>" *apache-socket*)
- (write-request-counts *apache-socket*)
+<h1>mod_lisp debug page</h1>" *modlisp-socket*)
+ (write-request-counts *modlisp-socket*)
(write-string "<table>
<thead><tr><th>Key</th><th>Value</th></tr></thead>
-<tbody>" *apache-socket*)
+<tbody>" *modlisp-socket*)
(loop for (key . value) in command do
- (format *apache-socket* "<tr><td>~a</td><td>~a</td></tr>" key value))
- (write-string "</tbody></table></body></html>" *apache-socket*))
+ (format *modlisp-socket* "<tr><td>~a</td><td>~a</td></tr>" key value))
+ (write-string "</tbody></table></body></html>" *modlisp-socket*))
(defun fixed-html-string ()
(write-string
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">
<html><head></head><body><h1>mod_lisp precomputed page</h1>
-<p>This is a precomputed string sent by mod_lisp</p>" *apache-socket*)
- (write-request-counts *apache-socket*)
- (write-string "</body></html>" *apache-socket*))
+<p>This is a precomputed string sent by mod_lisp</p>" *modlisp-socket*)
+ (write-request-counts *modlisp-socket*)
+ (write-string "</body></html>" *modlisp-socket*))
(defun write-request-counts (s)
(format s "<p>Number of server requests: ~D</p>"
- (get-number-server-requests))
+ *number-server-requests*)
(format s "<p>Number of worker requests for this socket: ~D</p>"
- (get-number-worker-requests)))
+ *number-worker-requests*))
;;;; Programmer: Kevin M. Rosenberg
;;;; Date Started: Dec 2002
;;;;
-;;;; $Id: package.lisp,v 1.3 2003/07/08 06:40:00 kevin Exp $
+;;;; $Id: package.lisp,v 1.4 2003/07/10 18:58:29 kevin Exp $
;;;; *************************************************************************
(in-package #:cl-user)
(:export
;; variables.lisp
- #:*apache-socket*
+ #:*modlisp-socket*
+ #:*number-worker-requests*
+ #:*number-server-requests*
;; base.lisp
#:modlisp-start
#:modlisp-stop-all
#:header-value
#:write-header-line
- #:get-number-worker-requests
- #:get-number-server-requests
- #:set-close-apache-socket
+ #:set-close-modlisp-socket
;; utils.lisp
#:output-html-page
;;;; Programmer: Kevin M. Rosenberg
;;;; Date Started: Dec 2002
;;;;
-;;;; $Id: utils.lisp,v 1.4 2003/07/08 08:34:23 kevin Exp $
+;;;; $Id: utils.lisp,v 1.5 2003/07/10 18:58:29 kevin Exp $
;;;; *************************************************************************
(in-package #:modlisp)
(write-header-line "Status" "200 OK")
(write-header-line "Content-Type" (format-string ,fmt))
(unless ,precomp
- (write-string "end" *apache-socket*)
- (write-char #\NewLine *apache-socket*))
+ (write-string "end" *modlisp-socket*)
+ (write-char #\NewLine *modlisp-socket*))
(setq ,outstr
(with-output-to-string (,stream)
- (let ((*apache-socket* (if ,precomp
+ (let ((*modlisp-socket* (if ,precomp
,stream
- *apache-socket*)))
+ *modlisp-socket*)))
(setq ,result (progn ,@body)))))
(cond
(,precomp
(write-header-line "Keep-Socket" "1")
(write-header-line "Keep-Alive" "timeout=15, max=99")
(write-header-line "Connection" "Keep-Alive")
- (write-string "end" *apache-socket*)
- (write-char #\NewLine *apache-socket*)
- (write-string ,outstr *apache-socket*)
- (force-output *apache-socket*)
- (set-close-apache-socket nil))
+ (write-string "end" *modlisp-socket*)
+ (write-char #\NewLine *modlisp-socket*)
+ (write-string ,outstr *modlisp-socket*)
+ (force-output *modlisp-socket*)
+ (setq *close-modlisp-socket* nil))
(t
- (set-close-apache-socket t)
- (finish-output *apache-socket*)))
+ (setq *close-modlisp-socket* t)
+ (finish-output *modlisp-socket*)))
,result)))
(defun redirect-to-location (url)
(write-header-line "Status" "302 Redirect")
(write-header-line "Location" url)
- (write-char #\NewLine *apache-socket*)
- (set-close-apache-socket t))
+ (write-char #\NewLine *modlisp-socket*)
+ (setq *close-modlisp-socket* t))
(defun output-ml-page (format html)
(write-header-line "Status" "200 OK")
(write-header-line "Keep-Socket" "1")
(write-header-line "Keep-Alive" "timeout=15, max=99")
(write-header-line "Connection" "Keep-Alive")
- (write-string "end" *apache-socket*)
- (write-char #\NewLine *apache-socket*)
- (write-string html *apache-socket*)
- (set-close-apache-socket nil))
+ (write-string "end" *modlisp-socket*)
+ (write-char #\NewLine *modlisp-socket*)
+ (write-string html *modlisp-socket*)
+ (setq *close-modlisp-socket* nil))
(defun output-html-page (str)
(output-ml-page :html str))
(defun output-xml-page (str)
(output-ml-page :xml str))
+;; Utility functions for library users
+
(defun posted-to-alist (posted-string)
- "Converts a posted string to an assoc list of variable names and values"
+ "Converts a posted string to an assoc list of keyword names and values,
+\"a=1&bc=demo\" => ((:a . \"1\") (:bc . \"demo\"))"
(when posted-string
(let ((alist '()))
(dolist (name=val (kmrcl:delimited-string-to-list posted-string #\&)
(nreverse alist))
(let ((name-val-list (kmrcl:delimited-string-to-list name=val #\=)))
- (when (= 2 (length name-val-list))
+ (if (= 2 (length name-val-list))
(destructuring-bind (name val) name-val-list
(push (cons (kmrcl:ensure-keyword name)
(kmrcl:decode-uri-query-string val))
- alist))))))))
-
-
-
-
-
+ alist))
+ (cmsg-c :debug "Invalid number of #\= in ~S" name-val-list)))))))
;;;; Programmer: Kevin M. Rosenberg
;;;; Date Started: Dec 2002
;;;;
-;;;; $Id: variables.lisp,v 1.7 2003/07/08 16:12:03 kevin Exp $
+;;;; $Id: variables.lisp,v 1.8 2003/07/10 18:58:29 kevin Exp $
;;;; *************************************************************************
(in-package #:modlisp)
-(defconstant +default-apache-port+ 20123
+(defconstant +default-modlisp-port+ 20123
"Default port for listen")
-(defvar *apache-socket* nil
- "the socket stream to apache")
+(defvar *modlisp-socket* nil
+ "the socket stream to modlisp")
-(defvar *number-server-requests* 0)
-(defvar *number-worker-requests* 0)
-(defvar *close-apache-socket* t)
+(defvar *number-server-requests* 0
+ "number of requests for the server")
+
+(defvar *number-worker-requests* 0
+ "number of requests for this worker process")
+
+(defvar *close-modlisp-socket* t
+ "whether to close the modlisp socket at the end of this request")