http.scm 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. ;;; Web I/O: HTTP
  2. ;; Copyright (C) 2010, 2011 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 HTTP implementation of the (web server) interface.
  20. ;;;
  21. ;;; `read-request' sets the character encoding on the new port to
  22. ;;; latin-1. See the note in request.scm regarding character sets,
  23. ;;; strings, and bytevectors for more information.
  24. ;;;
  25. ;;; Code:
  26. (define-module (web server http)
  27. #:use-module ((srfi srfi-1) #:select (fold))
  28. #:use-module (srfi srfi-9)
  29. #:use-module (rnrs bytevectors)
  30. #:use-module (web request)
  31. #:use-module (web response)
  32. #:use-module (web server)
  33. #:use-module (ice-9 poll))
  34. (define (make-default-socket family addr port)
  35. (let ((sock (socket PF_INET SOCK_STREAM 0)))
  36. (setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
  37. (bind sock family addr port)
  38. sock))
  39. (define-record-type <http-server>
  40. (make-http-server socket poll-idx poll-set)
  41. http-server?
  42. (socket http-socket)
  43. (poll-idx http-poll-idx set-http-poll-idx!)
  44. (poll-set http-poll-set))
  45. (define *error-events* (logior POLLHUP POLLERR))
  46. (define *read-events* POLLIN)
  47. (define *events* (logior *error-events* *read-events*))
  48. ;; -> server
  49. (define* (http-open #:key
  50. (host #f)
  51. (family AF_INET)
  52. (addr (if host
  53. (inet-pton family host)
  54. INADDR_LOOPBACK))
  55. (port 8080)
  56. (socket (make-default-socket family addr port)))
  57. (listen socket 128)
  58. (sigaction SIGPIPE SIG_IGN)
  59. (let ((poll-set (make-empty-poll-set)))
  60. (poll-set-add! poll-set socket *events*)
  61. (make-http-server socket 0 poll-set)))
  62. ;; -> (client request body | #f #f #f)
  63. (define (http-read server)
  64. (let* ((poll-set (http-poll-set server)))
  65. (let lp ((idx (http-poll-idx server)))
  66. (let ((revents (poll-set-revents poll-set idx)))
  67. (cond
  68. ((zero? idx)
  69. ;; The server socket, and the end of our downward loop.
  70. (cond
  71. ((zero? revents)
  72. ;; No client ready, and no error; poll and loop.
  73. (poll poll-set)
  74. (lp (1- (poll-set-nfds poll-set))))
  75. ((not (zero? (logand revents *error-events*)))
  76. ;; An error.
  77. (set-http-poll-idx! server idx)
  78. (throw 'interrupt))
  79. (else
  80. ;; A new client. Add to set, poll, and loop.
  81. ;;
  82. ;; FIXME: preserve meta-info.
  83. (let ((client (accept (poll-set-port poll-set idx))))
  84. ;; Buffer input and output on this port.
  85. (setvbuf (car client) _IOFBF)
  86. ;; From "HOP, A Fast Server for the Diffuse Web", Serrano.
  87. (setsockopt (car client) SOL_SOCKET SO_SNDBUF (* 12 1024))
  88. (poll-set-add! poll-set (car client) *events*)
  89. (poll poll-set)
  90. (lp (1- (poll-set-nfds poll-set)))))))
  91. ((zero? revents)
  92. ;; Nothing on this port.
  93. (lp (1- idx)))
  94. ;; Otherwise, a client socket with some activity on
  95. ;; it. Remove it from the poll set.
  96. (else
  97. (let ((port (poll-set-remove! poll-set idx)))
  98. ;; Record the next index in all cases, in case the EOF check
  99. ;; throws an error.
  100. (set-http-poll-idx! server (1- idx))
  101. (cond
  102. ((eof-object? (peek-char port))
  103. ;; EOF.
  104. (close-port port)
  105. (lp (1- idx)))
  106. (else
  107. ;; Otherwise, try to read a request from this port.
  108. (with-throw-handler
  109. #t
  110. (lambda ()
  111. (let ((req (read-request port)))
  112. (values port
  113. req
  114. (read-request-body req))))
  115. (lambda (k . args)
  116. (false-if-exception (close-port port)))))))))))))
  117. (define (keep-alive? response)
  118. (let ((v (response-version response)))
  119. (and (or (< (response-code response) 400)
  120. (= (response-code response) 404))
  121. (case (car v)
  122. ((1)
  123. (case (cdr v)
  124. ((1) (not (memq 'close (response-connection response))))
  125. ((0) (memq 'keep-alive (response-connection response)))))
  126. (else #f)))))
  127. ;; -> 0 values
  128. (define (http-write server client response body)
  129. (let* ((response (write-response response client))
  130. (port (response-port response)))
  131. (cond
  132. ((not body)) ; pass
  133. ((bytevector? body)
  134. (write-response-body response body))
  135. (else
  136. (error "Expected a bytevector for body" body)))
  137. (cond
  138. ((keep-alive? response)
  139. (force-output port)
  140. (poll-set-add! (http-poll-set server) port *events*))
  141. (else
  142. (close-port port)))
  143. (values)))
  144. ;; -> unspecified values
  145. (define (http-close server)
  146. (let ((poll-set (http-poll-set server)))
  147. (let lp ((n (poll-set-nfds poll-set)))
  148. (if (positive? n)
  149. (begin
  150. (close-port (poll-set-remove! poll-set (1- n)))
  151. (lp (1- n)))))))
  152. (define-server-impl http
  153. http-open
  154. http-read
  155. http-write
  156. http-close)