fileserver.scm 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. #!/usr/bin/env bash
  2. # -*- mode: scheme -*-
  3. exec guile -s $0 $@
  4. !#
  5. (import (rnrs)
  6. (only (srfi :13 strings)
  7. string-index
  8. string-prefix? string-suffix?
  9. string-concatenate string-trim-both)
  10. (rnrs io ports)
  11. (fibers web server)
  12. (fibers)
  13. (web request)
  14. (web response)
  15. (web uri))
  16. (define (read-file path)
  17. (with-input-from-file path
  18. (lambda () (get-bytevector-all (current-input-port)))))
  19. (define (read-file-to-port path port)
  20. (with-input-from-file path
  21. (lambda () (let ((bv (get-bytevector-n (current-input-port) (expt 2 20)))) ;; 1MiB
  22. (let lp ((count (bytevector-length bv)))
  23. (cond ((not (eof-object? count))
  24. (put-bytevector port bv 0 count)
  25. (lp (get-bytevector-n! (current-input-port) bv 0 count)))
  26. (else (close-port port))))))))
  27. (define (handler request body)
  28. (let* ((path* (uri-path (request-uri request)))
  29. (path (string-drop path* (min 1 (string-length path*))))
  30. (port (request-port request))
  31. ;; test file http://127.0.0.1/htdig/search.html
  32. (filepath "fileserver.scm")
  33. (err #f)
  34. (errparams '())
  35. (res "")
  36. (128kiB (expt 2 17))
  37. (maxsize 128kiB)) ;; 15k threads would be 2GiB
  38. (if (not (access? filepath R_OK))
  39. (values (build-response #:code 404)
  40. (string-append "Resource not found: "
  41. filepath))
  42. (cond ((< (stat:size (stat filepath)) maxsize) ;; can simply read the whole file
  43. (values '((content-type . (text/html)))
  44. (read-file filepath)))
  45. (else ;; chunk the file to preserve memory
  46. (spawn-fiber (lambda () (read-file-to-port filepath port))
  47. #:parallel? #f)
  48. (values '((content-type . (text/html)))
  49. #f)))))) ;; already putting the body into the port
  50. (run-server handler #:host "192.168.178.101" #:port 4223)