fibers.scm 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. ;;; Web I/O: Non-blocking HTTP
  2. ;; Copyright (C) 2012 Free Software Foundation, Inc.
  3. ;; This library is free software; you can redistribute it and/or
  4. ;; modify it under the terms of the GNU Lesser General Public
  5. ;; License as published by the Free Software Foundation; either
  6. ;; version 3 of the License, or (at your option) any later version.
  7. ;;
  8. ;; This library is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;; Lesser General Public License for more details.
  12. ;;
  13. ;; You should have received a copy of the GNU Lesser General Public
  14. ;; License along with this library; if not, write to the Free Software
  15. ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. ;; 02110-1301 USA
  17. ;;; Commentary:
  18. ;;;
  19. ;;; This is the non-blocking HTTP implementation of the (web server)
  20. ;;; interface.
  21. ;;;
  22. ;;; Code:
  23. (define-module (web server fibers)
  24. #:use-module ((srfi srfi-1) #:select (fold))
  25. #:use-module (srfi srfi-9)
  26. #:use-module (web http)
  27. #:use-module (web request)
  28. #:use-module (web response)
  29. #:use-module (web server)
  30. #:use-module (ice-9 binary-ports)
  31. #:use-module (ice-9 suspendable-ports)
  32. #:use-module (ice-9 match)
  33. #:use-module (ice-9 threads)
  34. #:use-module (fibers)
  35. #:use-module (fibers channels))
  36. (define (set-nonblocking! port)
  37. (setvbuf port 'block 1024))
  38. (define (make-default-socket family addr port)
  39. (let ((sock (socket PF_INET SOCK_STREAM 0)))
  40. (setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
  41. (fcntl sock F_SETFD FD_CLOEXEC)
  42. (bind sock family addr port)
  43. (fcntl sock F_SETFL (logior O_NONBLOCK (fcntl sock F_GETFL)))
  44. sock))
  45. (define-record-type <server>
  46. (make-server request-channel thread)
  47. server?
  48. (request-channel server-request-channel)
  49. (thread server-thread))
  50. ;; -> server
  51. (define* (open-server #:key
  52. (host #f)
  53. (family AF_INET)
  54. (addr (if host
  55. (inet-pton family host)
  56. INADDR_LOOPBACK))
  57. (port 8080)
  58. (socket (make-default-socket family addr port)))
  59. (install-suspendable-ports!)
  60. ;; We use a large backlog by default. If the server is suddenly hit
  61. ;; with a number of connections on a small backlog, clients won't
  62. ;; receive confirmation for their SYN, leading them to retry --
  63. ;; probably successfully, but with a large latency.
  64. (listen socket 1024)
  65. (fcntl socket F_SETFL (logior O_NONBLOCK (fcntl socket F_GETFL)))
  66. (sigaction SIGPIPE SIG_IGN)
  67. (let* ((request-channel (make-channel))
  68. (thread (call-with-new-thread
  69. (lambda ()
  70. (run-fibers
  71. (lambda ()
  72. (socket-loop socket request-channel)))))))
  73. (make-server request-channel thread)))
  74. (define (bad-request msg . args)
  75. (throw 'bad-request msg args))
  76. (define (keep-alive? response)
  77. (let ((v (response-version response)))
  78. (and (or (< (response-code response) 400)
  79. (= (response-code response) 404))
  80. (case (car v)
  81. ((1)
  82. (case (cdr v)
  83. ((1) (not (memq 'close (response-connection response))))
  84. ((0) (memq 'keep-alive (response-connection response)))))
  85. (else #f)))))
  86. (define (client-loop client have-request)
  87. ;; Always disable Nagle's algorithm, as we handle buffering
  88. ;; ourselves.
  89. (setsockopt client IPPROTO_TCP TCP_NODELAY 1)
  90. (setvbuf client 'block 1024)
  91. (with-throw-handler #t
  92. (lambda ()
  93. (let ((response-channel (make-channel)))
  94. (let loop ()
  95. (cond
  96. ((eof-object? (lookahead-u8 client))
  97. (close-port client))
  98. (else
  99. (call-with-values
  100. (lambda ()
  101. (catch #t
  102. (lambda ()
  103. (let* ((request (read-request client))
  104. (body (read-request-body request)))
  105. (have-request response-channel request body)))
  106. (lambda (key . args)
  107. (display "While reading request:\n" (current-error-port))
  108. (print-exception (current-error-port) #f key args)
  109. (values (build-response #:version '(1 . 0) #:code 400
  110. #:headers '((content-length . 0)))
  111. #vu8()))))
  112. (lambda (response body)
  113. (write-response response client)
  114. (when body
  115. (put-bytevector client body))
  116. (force-output client)
  117. (if (and (keep-alive? response)
  118. (not (eof-object? (peek-char client))))
  119. (loop)
  120. (close-port client)))))))))
  121. (lambda (k . args)
  122. (catch #t
  123. (lambda () (close-port client))
  124. (lambda (k . args)
  125. (display "While closing port:\n" (current-error-port))
  126. (print-exception (current-error-port) #f k args))))))
  127. (define (socket-loop socket request-channel)
  128. (define (have-request response-channel request body)
  129. (put-message request-channel (vector response-channel request body))
  130. (match (get-message response-channel)
  131. (#(response body)
  132. (values response body))))
  133. (let loop ()
  134. (match (accept socket (logior SOCK_NONBLOCK SOCK_CLOEXEC))
  135. ((client . sockaddr)
  136. (spawn-fiber (lambda () (client-loop client have-request))
  137. #:parallel? #t)
  138. (loop)))))
  139. ;; -> (client request body | #f #f #f)
  140. (define (server-read server)
  141. (match (get-message (server-request-channel server))
  142. (#(response-channel request body)
  143. (let ((client response-channel))
  144. (values client request body)))))
  145. ;; -> 0 values
  146. (define (server-write server client response body)
  147. (let ((response-channel client))
  148. (put-message response-channel (vector response body)))
  149. (values))
  150. ;; -> unspecified values
  151. (define (close-server server)
  152. (cancel-thread (server-thread server))
  153. (join-thread (server-thread server)))
  154. (define-server-impl fibers
  155. open-server
  156. server-read
  157. server-write
  158. close-server)