r5489: *** 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.9 2003/08/10 17:56:44 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) headers)
23                         &body body)
24   (let ((fmt (gensym "FMT-"))
25         (precomp (gensym "PRE-"))
26         (result (gensym "RES-"))
27         (outstr (gensym "STR-"))
28         (stream (gensym "STRM-"))
29         (hdr (gensym "HDR-")))
30     `(let ((,fmt ,format)
31            (,precomp ,precompute)
32            ,result ,outstr ,stream)
33        (declare (ignorable ,stream))
34        (write-header-line "Status" "200 OK")
35        (write-header-line "Content-Type" (format-string ,fmt))
36        (dolist (,hdr ,headers)
37          (write-header-line (car ,hdr) (cdr ,hdr)))
38        (unless ,precomp
39          (write-string "end" *modlisp-socket*)
40          (write-char #\NewLine *modlisp-socket*))
41        (setq ,outstr
42          (with-output-to-string (,stream)
43            (let ((*modlisp-socket* (if ,precomp
44                                       ,stream
45                                     *modlisp-socket*)))
46              (setq ,result (progn ,@body)))))
47        (cond
48         (,precomp
49          (write-header-line "Content-Length" 
50                             (write-to-string (length ,outstr)))
51          (write-header-line "Keep-Socket" "1")
52          (write-header-line "Connection" "Keep-Alive")
53          (write-string "end" *modlisp-socket*)
54          (write-char #\NewLine *modlisp-socket*)
55          (write-string ,outstr *modlisp-socket*)
56          (finish-output *modlisp-socket*)
57          (setq *close-modlisp-socket* nil))
58         (t
59          (finish-output *modlisp-socket*)
60          (setq *close-modlisp-socket* t)))
61        ,result)))
62
63 (defun redirect-to-location (url)
64   (write-header-line "Status" "307 Temporary Redirect")
65   (write-header-line "Location" url)
66   ;;(write-header-line "Keep-Socket" "1")
67   ;;(write-header-line "Connection" "Keep-Alive")
68   (write-string "end" *modlisp-socket*)
69   (write-char #\NewLine *modlisp-socket*)
70   (force-output *modlisp-socket*)
71   (setq *close-modlisp-socket* t))
72
73 (defun output-ml-page (format html)
74   (write-header-line "Status" "200 OK")
75   (write-header-line "Content-Type" (format-string format))
76   (write-header-line "Content-Length" (format nil "~d" (length html)))
77   (write-header-line "Keep-Socket" "1")
78   (write-header-line "Connection" "Keep-Alive")
79   (write-string "end" *modlisp-socket*)
80   (write-char #\NewLine *modlisp-socket*)
81   (write-string html *modlisp-socket*)
82   (force-output *modlisp-socket*)
83   (setq *close-modlisp-socket* nil))
84
85 (defun output-html-page (str)
86   (output-ml-page :html str))
87
88 (defun output-xml-page (str)
89   (output-ml-page :xml str))
90
91 ;; Utility functions for library users
92
93 (defun query-to-alist (posted-string)
94   "Converts a posted string to an assoc list of keyword names and values,
95 \"a=1&bc=demo\" => ((:a . \"1\") (:bc . \"demo\"))"
96   (when posted-string
97     (let ((alist '()))
98       (dolist (name=val (kmrcl:delimited-string-to-list posted-string #\&)
99                (nreverse alist))
100         (let ((name-val-list (kmrcl:delimited-string-to-list name=val #\=)))
101           (if (= 2 (length name-val-list))
102             (destructuring-bind (name val) name-val-list
103               (push (cons (kmrcl:ensure-keyword name)
104                           (kmrcl:decode-uri-query-string val))
105                     alist))
106             (cmsg-c :debug "Invalid number of #\= in ~S" name-val-list)))))))