r5277: *** empty log message ***
[cl-modlisp.git] / utils.lisp
1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; Base: 10; Package: modlisp -*-
2 ;;;; *************************************************************************
3 ;;;; FILE IDENTIFICATION
4 ;;;;
5 ;;;; Name:          utils.lisp
6 ;;;; Purpose:       Utility functions for modlisp package
7 ;;;; Programmer:    Kevin M. Rosenberg
8 ;;;; Date Started:  Dec 2002
9 ;;;;
10 ;;;; $Id: utils.lisp,v 1.6 2003/07/11 02:38:00 kevin Exp $
11 ;;;; *************************************************************************
12
13 (in-package #:modlisp)
14
15 (defun format-string (fmt)
16   (case fmt
17     (:html "text/html")
18     (:xml "text/xml")
19     (:text "text/plain")
20     (otherwise fmt)))
21                            
22 (defmacro with-ml-page ((&key (format :html) (precompute t)) &body body)
23   (let ((fmt (gensym))
24         (precomp (gensym))
25         (result (gensym))
26         (outstr (gensym))
27         (stream (gensym)))
28     `(let ((,fmt ,format)
29            (,precomp ,precompute)
30            ,result ,outstr)
31        (write-header-line "Status" "200 OK")
32        (write-header-line "Content-Type" (format-string ,fmt))
33        (unless ,precomp
34          (write-string "end" *modlisp-socket*)
35          (write-char #\NewLine *modlisp-socket*))
36        (setq ,outstr
37          (with-output-to-string (,stream)
38            (let ((*modlisp-socket* (if ,precomp
39                                       ,stream
40                                     *modlisp-socket*)))
41              (setq ,result (progn ,@body)))))
42        (cond
43         (,precomp
44          (write-header-line "Content-Length" 
45                             (write-to-string (length ,outstr)))
46          (write-header-line "Keep-Socket" "1")
47          (write-header-line "Keep-Alive" "timeout=15, max=99")
48          (write-header-line "Connection" "Keep-Alive")
49          (write-string "end" *modlisp-socket*)
50          (write-char #\NewLine *modlisp-socket*)
51          (write-string ,outstr *modlisp-socket*)
52          (finish-output *modlisp-socket*)
53          (setq *close-modlisp-socket* nil))
54         (t
55          (setq *close-modlisp-socket* t)
56          (finish-output *modlisp-socket*)))
57        ,result)))
58
59 (defun redirect-to-location (url)
60   (write-header-line "Status" "302 Redirect")
61   (write-header-line "Location" url)
62   (write-char #\NewLine *modlisp-socket*)
63   (setq *close-modlisp-socket* t))
64
65 (defun output-ml-page (format html)
66   (write-header-line "Status" "200 OK")
67   (write-header-line "Content-Type" (format-string format))
68   (write-header-line "Content-Length" (format nil "~d" (length html)))
69   (write-header-line "Keep-Socket" "1")
70   (write-header-line "Keep-Alive" "timeout=15, max=99")
71   (write-header-line "Connection" "Keep-Alive")
72   (write-string "end" *modlisp-socket*)
73   (write-char #\NewLine *modlisp-socket*)
74   (write-string html *modlisp-socket*)
75   (setq *close-modlisp-socket* nil))
76
77 (defun output-html-page (str)
78   (output-ml-page :html str))
79
80 (defun output-xml-page (str)
81   (output-ml-page :xml str))
82
83 ;; Utility functions for library users
84
85 (defun posted-to-alist (posted-string)
86   "Converts a posted string to an assoc list of keyword names and values,
87 \"a=1&bc=demo\" => ((:a . \"1\") (:bc . \"demo\"))"
88   (when posted-string
89     (let ((alist '()))
90       (dolist (name=val (kmrcl:delimited-string-to-list posted-string #\&)
91                (nreverse alist))
92         (let ((name-val-list (kmrcl:delimited-string-to-list name=val #\=)))
93           (if (= 2 (length name-val-list))
94             (destructuring-bind (name val) name-val-list
95               (push (cons (kmrcl:ensure-keyword name)
96                           (kmrcl:decode-uri-query-string val))
97                     alist))
98             (cmsg-c :debug "Invalid number of #\= in ~S" name-val-list)))))))