summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorGravatar Andy Wingo2010-12-03 17:00:10 +0100
committerGravatar Andy Wingo2010-12-03 17:00:10 +0100
commit5900823c3e168cea97b3b51d61c3fdc2130a921e (patch)
treec41f2b9ff7ba28bca24984010d36a05ce238fc89
parenta8ad41b06d2fa053b0bb7f507d184131672e587a (diff)
downloadtekuti-5900823c3e168cea97b3b51d61c3fdc2130a921e.tar.gz
tekuti-5900823c3e168cea97b3b51d61c3fdc2130a921e.zip
update mod-lisp web server impl
* tekuti/mod-lisp.scm: Update to use the poll set, do the right thing for SIGPIPE, etc, following http.scm. Maybe now it will actually be reliable.
-rw-r--r--tekuti/mod-lisp.scm110
1 files changed, 85 insertions, 25 deletions
diff --git a/tekuti/mod-lisp.scm b/tekuti/mod-lisp.scm
index 41b8630..458e187 100644
--- a/tekuti/mod-lisp.scm
+++ b/tekuti/mod-lisp.scm
@@ -27,6 +27,8 @@
(define-module (tekuti mod-lisp)
#:use-module (ice-9 rdelim)
#:use-module (system repl error-handling)
+ #:use-module (srfi srfi-9)
+ #:use-module (ice-9 poll)
#:use-module (rnrs bytevectors)
#:use-module (web http)
#:use-module (web request)
@@ -167,30 +169,84 @@
(bind sock family addr port)
sock))
+(define-record-type <mod-lisp-server>
+ (make-mod-lisp-server socket poll-idx poll-set)
+ mod-lisp-server?
+ (socket mod-lisp-socket)
+ (poll-idx mod-lisp-poll-idx set-mod-lisp-poll-idx!)
+ (poll-set mod-lisp-poll-set))
+
+(define *error-events* (logior POLLHUP POLLERR))
+(define *read-events* POLLIN)
+(define *events* (logior *error-events* *read-events*))
+
;; -> server
(define* (mod-lisp-open #:key
- (host #f)
- (family AF_INET)
- (addr (if host
- (inet-pton family host)
- INADDR_LOOPBACK))
- (port 8080)
- (socket (make-default-socket family addr port)))
- (listen socket 5)
- socket)
-
-;; For mod-lisp, we don't do keep-alive.
-(define (keep-alive? response)
- #f)
-
-;; -> (keep-alive client request body | keep-alive #f #f #f)
-(define (mod-lisp-read server keep-alive)
- (let* ((client (accept server))
- (req (read-request/mod-lisp (car client)))
- (body-str (read-request-body/latin-1 req)))
- (values keep-alive (car client) req body-str)))
-
-;; -> (#f | client)
+ (host #f)
+ (family AF_INET)
+ (addr (if host
+ (inet-pton family host)
+ INADDR_LOOPBACK))
+ (port 8080)
+ (socket (make-default-socket family addr port)))
+ (listen socket 128)
+ (sigaction SIGPIPE SIG_IGN)
+ (let ((poll-set (make-empty-poll-set)))
+ (poll-set-add! poll-set socket *events*)
+ (make-mod-lisp-server socket 0 poll-set)))
+
+;; -> (client request body | #f #f #f)
+(define (mod-lisp-read server)
+ (let* ((poll-set (mod-lisp-poll-set server)))
+ (let lp ((idx (mod-lisp-poll-idx server)))
+ (let ((revents (poll-set-revents poll-set idx)))
+ (cond
+ ((zero? idx)
+ ;; The server socket, and the end of our downward loop.
+ (cond
+ ((zero? revents)
+ ;; No client ready, and no error; poll and loop.
+ (poll poll-set)
+ (lp (1- (poll-set-nfds poll-set))))
+ ((not (zero? (logand revents *error-events*)))
+ ;; An error.
+ (throw 'interrupt))
+ (else
+ ;; A new client. Add to set, poll, and loop.
+ ;;
+ ;; FIXME: preserve meta-info.
+ (let ((client (accept (poll-set-port poll-set idx))))
+ ;; Set line buffering while reading the request.
+ (setvbuf (car client) _IOLBF)
+ ;; From "HOP, A Fast Server for the Diffuse Web", Serrano.
+ (setsockopt (car client) SOL_SOCKET SO_SNDBUF (* 12 1024))
+ (poll-set-add! poll-set (car client) *events*)
+ (poll poll-set)
+ (lp (1- (poll-set-nfds poll-set)))))))
+ ((zero? revents)
+ ;; Nothing on this port.
+ (lp (1- idx)))
+ ;; Otherwise, a client socket with some activity on
+ ;; it. Remove it from the poll set.
+ (else
+ (let ((port (poll-set-remove! poll-set idx)))
+ (cond
+ ((eof-object? (peek-char port))
+ ;; EOF.
+ (close-port port)
+ (lp (1- idx)))
+ (else
+ ;; Otherwise, try to read a request from this port.
+ ;; Record the next index.
+ (set-mod-lisp-poll-idx! server (1- idx))
+ (let ((req (read-request/mod-lisp port)))
+ ;; Block buffering for reading body and writing response.
+ (setvbuf port _IOFBF)
+ (values port
+ req
+ (read-request-body/latin-1 req))))))))))))
+
+;; -> unspecified values
(define (mod-lisp-write server client response body)
(let ((response (write-response/mod-lisp response client)))
(cond
@@ -201,12 +257,16 @@
(write-response-body/bytevector response body))
(else
(error "Expected a string or bytevector for body" body)))
- (close-port (response-port response))
- #f))
+ (close-port (response-port response))))
;; -> unspecified values
(define (mod-lisp-close server)
- (close-port server))
+ (let ((poll-set (mod-lisp-poll-set server)))
+ (let lp ((n (poll-set-nfds poll-set)))
+ (if (positive? n)
+ (begin
+ (close-port (poll-set-remove! poll-set (1- n)))
+ (lp (1- n)))))))
(define-server-impl mod-lisp
mod-lisp-open