Commit a25bea411cd5d0430d502d11abb30a72f6926099

Thomas de Grivel 2017-06-27T18:08:19

Use a multi-buffered-output-stream as reply-stream

diff --git a/thot-simple.lisp b/thot-simple.lisp
index b7a1c15..fcc70e3 100644
--- a/thot-simple.lisp
+++ b/thot-simple.lisp
@@ -17,10 +17,15 @@
                       (return))
                     (when (find fd readable)
                       (socket:with-accept (clientfd) fd
-                        (with-stream (stream (babel-io-stream
-                                              (fd-io-stream clientfd)))
-                          (request-loop stream)))))))))
-    #'acceptor-loop-simple-fun))
+                        (with-stream (request-stream
+                                      (babel-input-stream
+                                       (fd-input-stream clientfd)))
+                          (with-stream (reply-stream
+                                        (babel-output-stream
+                                         (multi-buffered-output-stream
+                                          (fd-output-stream clientfd))))
+                            (request-loop request-stream reply-stream)))))))))
+      #'acceptor-loop-simple-fun)))
 
 (setq *acceptor-loop* 'acceptor-loop-simple)
 
diff --git a/thot.lisp b/thot.lisp
index 4512e28..80c1c67 100644
--- a/thot.lisp
+++ b/thot.lisp
@@ -192,11 +192,9 @@
    (headers-sent :initform nil
                  :accessor reply-headers-sent%
                  :type boolean)
-   (cont-queue :initform (make-instance 'queue
-                                        :element-type 'function
-                                        :size 40)
-         :accessor reply-cont-queue%
-         :type queue)))
+   (stream :initarg :stream
+           :accessor reply-stream%
+           :type buffered-output-stream)))
 
 (defvar *reply*)
 
@@ -226,64 +224,24 @@
 (defsetf reply-headers-sent (&optional (reply '*reply*)) (value)
   `(setf (reply-headers-sent% ,reply) ,value))
 
-(defun reply-cont-queue (&optional (reply *reply*))
+(defun reply-stream (&optional (reply *reply*))
   (declare (type reply reply))
-  (reply-cont-queue% reply))
-
-(defsetf reply-cont-queue (&optional (reply '*reply*)) (value)
-  `(setf (reply-cont-queue% ,reply) ,value))
+  (reply-stream% reply))
 
 (defun reply-content-length (&optional (reply *reply*))
   (declare (type reply reply))
   (parse-integer (reply-header 'content-length reply)))
 
-(defun reply-stream ()
-  (request-stream))
-
 (defun status (line)
   (let ((status (reply-status)))
     (when status
       (error 'status-already-sent status line)))
   (setf (reply-status) line)
   (let ((stream (reply-stream)))
-    (labels ((version (&optional (start 0))
-               (multiple-value-bind (count state)
-                   (write-sequence stream (request-http-version) :start start)
-                 (case state
-                   ((nil) (space))
-                   ((:eof) (error 'stream-end-error :stream stream))
-                   ((:non-blocking) (write (reply-cont-queue)
-                                           (lambda ()
-                                             (version (+ start count)))))
-                   (otherwise (error 'stream-output-error :stream stream)))))
-             (space ()
-               (case (write stream #\Space)
-                 ((nil) (line))
-                 ((:eof) (error 'stream-end-error :stream stream))
-                 ((:non-blocking) (write (reply-cont-queue) #'space))
-                 (otherwise (error 'stream-output-error :stream stream))))
-             (line (&optional (start 0))
-               (multiple-value-bind (count state)
-                   (write-sequence stream line :start start)
-                 (case state
-                   ((nil) (crlf))
-                   ((:eof) (error 'stream-end-error :stream stream))
-                   ((:non-blocking) (write (reply-cont-queue)
-                                           (lambda () (line (+ start count)))))
-                   (otherwise (error 'stream-output-error :stream stream)))))
-             (crlf (&optional (start 0))
-               (multiple-value-bind (count state)
-                   (write-sequence stream +crlf+)
-                 (case state
-                   ((nil) nil)
-                   ((:eof) (error 'stream-end-error :stream stream))
-                   ((:non-blocking) (write (reply-cont-queue)
-                                           (lambda () (crlf (+ start count)))))
-                   (otherwise (error 'stream-output-error
-                                     :stream stream))))))
-      (if (= 0 (queue-length (reply-cont-queue)))
-          (version)
-          (write (reply-cont-queue) #'version)))))
+    (write-sequence stream (request-http-version))
+    (write stream #\Space)
+    (write-sequence stream line)
+    (write-sequence stream +crlf+)))
 
 (defun header (line)
   (unless (reply-status)
@@ -296,30 +254,9 @@
              (setf (rest headers) (list line))
              (return))
            (pop headers))))
-  (let ((stream (request-stream)))
-    (labels ((line (&optional (start 0))
-               (multiple-value-bind (count state)
-                   (write-sequence stream line)
-                 (case state
-                   ((nil) (crlf))
-                   ((:eof) (error 'stream-end-error :stream stream))
-                   ((:non-blocking) (write (reply-cont-queue)
-                                           (lambda () (line (+ start count)))))
-                   (otherwise (error 'stream-output-error
-                                     :stream stream)))))
-             (crlf (&optional (start 0))
-               (multiple-value-bind (count state)
-                   (write-sequence stream +crlf+)
-                 (case state
-                   ((nil) nil)
-                   ((:eof) (error 'stream-end-error :stream stream))
-                   ((:non-blocking) (write (reply-cont-queue)
-                                           (lambda () (crlf (+ start count)))))
-                   (otherwise (error 'stream-output-error
-                                     :stream stream))))))
-      (if (= 0 (queue-length (reply-cont-queue)))
-          (line)
-          (write (reply-cont-queue) #'line)))))
+  (let ((stream (reply-stream)))
+    (write-sequence stream line)
+    (write-sequence stream +crlf+)))
 
 (defun end-headers ()
   (unless (reply-headers-sent)
@@ -328,21 +265,7 @@
 
 (defun content (string)
   (end-headers)
-  (let ((stream (reply-stream)))
-    (labels ((content-string (&optional (start 0))
-               (multiple-value-bind (count state)
-                   (write-sequence (request-stream) string)
-                 (case state
-                   ((nil) nil)
-                   (:eof) (error 'stream-end-error :stream stream)
-                   ((:non-blocking) (write (reply-cont-queue)
-                                           (lambda ()
-                                             (content-string (+ start count)))))
-                   (otherwise (error 'stream-output-error
-                                     :stream stream))))))
-      (if (= 0 (queue-length (reply-cont-queue)))
-          (content-string)
-          (write (reply-cont-queue) #'content-string)))))
+  (write-sequence (reply-stream) string))
 
 (defun 404-not-found ()
   (status "404 Not found")
@@ -371,7 +294,7 @@ The requested url ~S was not found on this server."
            (when (debug-p (or :thot :http))
              (format t "~&~S -> ~S~%" handler-func handler))
            (funcall handler)
-           (flush (request-stream% request))
+           (flush (reply-stream% reply))
            (return))))
     (if (string-equal "keep-alive" (request-header 'connection))
         :keep-alive
@@ -379,12 +302,12 @@ The requested url ~S was not found on this server."
 
 (defvar *stop* nil)
 
-(defun request-loop (stream)
+(defun request-loop (request-stream reply-stream)
   (loop
      (when *stop*
        (return))
-     (let* ((request (make-instance 'request :stream stream))
-            (reply (make-instance 'reply))
+     (let* ((request (make-instance 'request :stream request-stream))
+            (reply (make-instance 'reply :stream reply-stream))
             (result (funcall (request-reader request reply #'request-cont))))
        (unless (eq :keep-alive result)
          (return)))))