http.scm 6.4 KB

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