-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmodlisp-clisp.lisp
189 lines (160 loc) · 6.23 KB
/
modlisp-clisp.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
;;; -*- Mode:Lisp; Syntax:Common-lisp; Package:MODLISP; Base:10 -*-
;; modlisp-clisp.lisp
;; adapted from modlisp-acl.lisp
;; Original CLISP adaption by Rachel Richard <rr@u.washington.edu>
;; Changes by Nils Kassube <nika@kassube.de> on 2001-11-24:
;;
;; - replaced :lisp by :ext for CLISP's new naming convention,
;; works now with recent CLISP distributions
;; - added modlisp-server to the :export line
(in-package :user)
(provide :modlisp)
(eval-when (compile load eval)
(defpackage :modlisp
(:nicknames :lph)
(:use :cl)
(:export modlisp-server)
))
(in-package :modlisp)
;;;;;
;;;
;;; First part adapted from server.cl
;;;
;;;;;
(defvar *server-count* 0) ; used to name servers
(defun make-socket-server (&key (name (format nil "socket server ~d "
(incf *server-count*)))
port
function
wait
(format :text))
;;
;; create a server process with the given name, listening on the
;; given port, running the given function on each connection that
;; comes in, and possibly waiting for that function's completion before
;; accepting a new connection.
;;
;; name - a string naming the server process -- if nil, then this
;; function will create a name.
;; port - if nil then an internet domain port number will be chosen
;; by the operating system. If a number is given then that
;; port will be used (or an error will be signalled if it
;; is already in use). If port is a string then a unix
;; domain port will be used. (this will not work on Windows).
;; function - the function to run when a connection is made. This
;; function must take one argument which is the stream used
;; used for reading from and writing to the process that connected
;; to this socket.
;; wait - if true, then the function will be run in the server process
;; and thus the server won't accept a new connection until
;; the function finishes.
;; format - :text (the default) or :binary. This determes what kind
;; of data can sent to and read from the socket stream.
;;
;;
;;
;; The return value is the port number on which the server is
;; listening.
;;
(let ((passive-socket (ext:socket-server port) ;
))
(start-socket-server passive-socket
:function function
:wait wait)
(ext:socket-server-port passive-socket)))
(defun start-socket-server (passive-socket &key function wait)
;; internal function run in the server lightweight process
;; that continually processes the connection.
;; This code is careful to ensure that the sockets are
;; properly closed something abnormal happens.
(unwind-protect
(loop (let ((connection (ext:socket-accept passive-socket)))
(if wait
(progn
(unwind-protect
(funcall function connection)
(handler-case (values-list (cons t
(multiple-value-list
(close connection))))
(error (condition) (declare (ignore-if-unused condition))
nil))))
(unwind-protect
(funcall function connection)
(handler-case (values-list (cons t
(multiple-value-list
(close connection))))
(error (condition) (declare (ignore-if-unused condition))
nil)))
)))
(handler-case (values-list (cons t
(multiple-value-list
(close passive-socket))))
(error (condition) (declare (ignore-if-unused condition))
nil))))
;;;;;
;;;
;;; Second part adapted from mod-lisp.lisp
;;;
;;;;;
(defconstant +apache-port+ 3000)
(defvar *apache-socket* nil) ;the socket to apache
(defvar *close-apache-socket* nil) ;set to t if you want to close the socket to apache
(defvar *apache-nb-use-socket* 0) ;the number of requests sent in this socket
(defun modlisp-server (&optional (port +apache-port+))
(make-socket-server :name "test"
:port port
:function 'apache-listen))
(defun apache-listen (*apache-socket*)
(let ((*close-apache-socket* t))
(unwind-protect
(loop for *apache-nb-use-socket* from 0
for command = (get-apache-command)
while command
do (process-apache-command command)
(force-output *apache-socket*)
until *close-apache-socket*)
(close *apache-socket*))))
(defun get-apache-command ()
(ignore-errors
(let* ((header (loop for key = (read-line *apache-socket* nil nil)
while (and key (string-not-equal key "end"))
collect (cons key (read-line *apache-socket* nil nil)) )))
(let* ((content-length (cdr (assoc "content-length" header :test #'equal)))
(content (when content-length (make-string (parse-integer content-length :junk-allowed t)))))
(when content
(read-sequence content *apache-socket*)
(push (cons "posted-content" content) header))
header))))
(defun process-apache-command (command)
(let ((html (if (equal (cdr (assoc "url" command :test #'string=))
"/modlisp/fixed")
(debug-table command)
(fixed-html))))
(write-header-line "Status" "200 OK")
(write-header-line "Content-Type" "text/html")
(write-header-line "Content-Length" (format nil "~d" (length html)))
(write-header-line "Keep-Socket" "1")
(write-string "end" *apache-socket*)
(write-char #\NewLine *apache-socket*)
(write-string html *apache-socket*)
(setf *close-apache-socket* nil)))
(defun debug-table (command)
(with-output-to-string (s)
(write-string "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">
<HTML><HEAD></HEAD><BODY><TABLE bgcolor=\"#c0c0c0\">
<TR bgcolor=\"yellow\"><TH COLSPAN=2>CLISP + mod_lisp 2.0 + apache + Linux</TH></TR>
<TR bgcolor=\"yellow\"><TH>Key</TH><TH>Value</TH></TR>" s)
(format s "<TR bgcolor=\"#F0F0c0\"><TD>apache-nb-use-socket</TD><TD>~a</TD></TR>" *apache-nb-use-socket*)
(loop for (key . value) in command do
(format s "<TR bgcolor=\"#F0F0c0\"><TD>~a</TD><TD>~a</TD></TR>" key value))
(write-string "</TABLE></BODY></HTML>" s)))
(defun fixed-html ()
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">
<HTML><HEAD></HEAD><BODY><H1>mod_lisp 2.0</H1><P>This is a constant
html string sent by mod_lisp 2.0 + CLISP + apache + Linux</P>
</BODY></HTML>")
(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*))