X-Git-Url: http://git.kpe.io/?p=cl-modlisp.git;a=blobdiff_plain;f=utils.lisp;h=bab76c36b97e199c4b35e941c7ad54da85c53949;hp=97f6f76a76e1330a1b794084266c066c7ecee300;hb=HEAD;hpb=f63edd12886a0ed33be55f49c3284acca5db4797 diff --git a/utils.lisp b/utils.lisp index 97f6f76..bab76c3 100644 --- a/utils.lisp +++ b/utils.lisp @@ -7,98 +7,77 @@ ;;;; Programmer: Kevin M. Rosenberg ;;;; Date Started: Dec 2002 ;;;; -;;;; $Id: utils.lisp,v 1.7 2003/07/16 20:40:43 kevin Exp $ +;;;; $Id$ ;;;; ************************************************************************* (in-package #:modlisp) -(defun format-string (fmt) +(defun format->string (fmt) (case fmt (:html "text/html") (:xml "text/xml") (:text "text/plain") (otherwise fmt))) - + +(defun format-string (fmt headers) + `(("Content-Type" . + ,(format->string fmt)) + . ,headers)) + +(defmacro write-response ((&key headers len (status "200 OK")) &body body) + (let ((result (gensym "RES-"))) + `(progn + (write-header-line "Status" ,status) + (dolist (hdr ,headers) + (write-header-line (car hdr) (cdr hdr))) + ,@(and len + `((write-header-line "Content-Length" ,len) + (write-header-line "Keep-Socket" "1") + (write-header-line "Connection" "Keep-Alive"))) + (write-string "end" *modlisp-socket*) + (write-char #\NewLine *modlisp-socket*) + (let ((,result (progn ,@body))) + (,(if len 'force-output 'finish-output) *modlisp-socket*) + (setq *close-modlisp-socket* ,(not len)) + ,result)))) + (defmacro with-ml-page ((&key (format :html) (precompute t) headers) - &body body) - (let ((fmt (gensym "FMT-")) - (precomp (gensym "PRE-")) - (result (gensym "RES-")) - (outstr (gensym "STR-")) - (stream (gensym "STRM-")) - (hdr (gensym "HDR-"))) - `(let ((,fmt ,format) - (,precomp ,precompute) - ,result ,outstr ,stream) - (declare (ignorable ,stream)) - (write-header-line "Status" "200 OK") - (write-header-line "Content-Type" (format-string ,fmt)) - (dolist (,hdr ,headers) - (write-header-line (car ,hdr) (cdr ,hdr))) - (unless ,precomp - (write-string "end" *modlisp-socket*) - (write-char #\NewLine *modlisp-socket*)) - (setq ,outstr - (with-output-to-string (,stream) - (let ((*modlisp-socket* (if ,precomp - ,stream - *modlisp-socket*))) - (setq ,result (progn ,@body))))) - (cond - (,precomp - (write-header-line "Content-Length" - (write-to-string (length ,outstr))) - (write-header-line "Keep-Socket" "1") - (write-header-line "Connection" "Keep-Alive") - (write-string "end" *modlisp-socket*) - (write-char #\NewLine *modlisp-socket*) - (write-string ,outstr *modlisp-socket*) - (finish-output *modlisp-socket*) - (setq *close-modlisp-socket* nil)) - (t - (finish-output *modlisp-socket*) - (setq *close-modlisp-socket* t))) - ,result))) + &body body) + (if precompute + `(output-ml-page ,format (with-output-to-string (*modlisp-socket*) ,@body) :headers ,headers) + `(write-response (:headers (format-string ,format ,headers)) ,@body))) (defun redirect-to-location (url) - (write-header-line "Status" "302 Redirect") - (write-header-line "Location" url) - (write-string "end" *modlisp-socket*) - (write-char #\NewLine *modlisp-socket*) - (force-output *modlisp-socket*) - (setq *close-modlisp-socket* t)) + (write-response (:status "307 Temporary Redirect" :headers `(("Location" . ,url))))) -(defun output-ml-page (format html) - (write-header-line "Status" "200 OK") - (write-header-line "Content-Type" (format-string format)) - (write-header-line "Content-Length" (format nil "~d" (length html))) - (write-header-line "Keep-Socket" "1") - (write-header-line "Connection" "Keep-Alive") - (write-string "end" *modlisp-socket*) - (write-char #\NewLine *modlisp-socket*) - (write-string html *modlisp-socket*) - (force-output *modlisp-socket*) - (setq *close-modlisp-socket* nil)) +(defmacro output-ml-page (format html &key headers) + (let ((str (gensym "STR-"))) + `(let ((,str ,html)) + (write-response (:len (format nil "~d" (length ,str)) + :headers (format-string ,format ,headers)) + (write-string ,str *modlisp-socket*))))) -(defun output-html-page (str) - (output-ml-page :html str)) +(defun output-html-page (str &key headers) + (output-ml-page :html str :headers headers)) -(defun output-xml-page (str) - (output-ml-page :xml str)) +(defun output-xml-page (str &key headers) + (output-ml-page :xml str :headers headers)) ;; Utility functions for library users -(defun query-to-alist (posted-string) +(defun query-to-alist (posted-string &key (keyword t)) "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 #\=))) - (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)) - (cmsg-c :debug "Invalid number of #\= in ~S" name-val-list))))))) + (nreverse alist)) + (let ((name-val-list (kmrcl:delimited-string-to-list name=val #\=))) + (if (= 2 (length name-val-list)) + (destructuring-bind (name val) name-val-list + (push (cons (if keyword + (kmrcl:ensure-keyword name) + name) + (kmrcl:decode-uri-query-string val)) + alist)) + (cmsg-c :debug "Invalid number of #\= in ~S" name-val-list)))))))