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.
This commit is contained in:
parent
a8ad41b06d
commit
5900823c3e
1 changed files with 83 additions and 23 deletions
|
@ -27,6 +27,8 @@
|
||||||
(define-module (tekuti mod-lisp)
|
(define-module (tekuti mod-lisp)
|
||||||
#:use-module (ice-9 rdelim)
|
#:use-module (ice-9 rdelim)
|
||||||
#:use-module (system repl error-handling)
|
#:use-module (system repl error-handling)
|
||||||
|
#:use-module (srfi srfi-9)
|
||||||
|
#:use-module (ice-9 poll)
|
||||||
#:use-module (rnrs bytevectors)
|
#:use-module (rnrs bytevectors)
|
||||||
#:use-module (web http)
|
#:use-module (web http)
|
||||||
#:use-module (web request)
|
#:use-module (web request)
|
||||||
|
@ -167,6 +169,17 @@
|
||||||
(bind sock family addr port)
|
(bind sock family addr port)
|
||||||
sock))
|
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
|
;; -> server
|
||||||
(define* (mod-lisp-open #:key
|
(define* (mod-lisp-open #:key
|
||||||
(host #f)
|
(host #f)
|
||||||
|
@ -176,21 +189,64 @@
|
||||||
INADDR_LOOPBACK))
|
INADDR_LOOPBACK))
|
||||||
(port 8080)
|
(port 8080)
|
||||||
(socket (make-default-socket family addr port)))
|
(socket (make-default-socket family addr port)))
|
||||||
(listen socket 5)
|
(listen socket 128)
|
||||||
socket)
|
(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)))
|
||||||
|
|
||||||
;; For mod-lisp, we don't do keep-alive.
|
;; -> (client request body | #f #f #f)
|
||||||
(define (keep-alive? response)
|
(define (mod-lisp-read server)
|
||||||
#f)
|
(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))))))))))))
|
||||||
|
|
||||||
;; -> (keep-alive client request body | keep-alive #f #f #f)
|
;; -> unspecified values
|
||||||
(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)
|
|
||||||
(define (mod-lisp-write server client response body)
|
(define (mod-lisp-write server client response body)
|
||||||
(let ((response (write-response/mod-lisp response client)))
|
(let ((response (write-response/mod-lisp response client)))
|
||||||
(cond
|
(cond
|
||||||
|
@ -201,12 +257,16 @@
|
||||||
(write-response-body/bytevector response body))
|
(write-response-body/bytevector response body))
|
||||||
(else
|
(else
|
||||||
(error "Expected a string or bytevector for body" body)))
|
(error "Expected a string or bytevector for body" body)))
|
||||||
(close-port (response-port response))
|
(close-port (response-port response))))
|
||||||
#f))
|
|
||||||
|
|
||||||
;; -> unspecified values
|
;; -> unspecified values
|
||||||
(define (mod-lisp-close server)
|
(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
|
(define-server-impl mod-lisp
|
||||||
mod-lisp-open
|
mod-lisp-open
|
||||||
|
|
Loading…
Reference in a new issue