server.scm 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #!/usr/bin/env bash
  2. exec guile -s $0 $@
  3. !#
  4. (import (rnrs)
  5. (only (srfi :13 strings)
  6. string-index
  7. string-prefix? string-suffix?
  8. string-concatenate string-trim-both)
  9. (fibers web server)
  10. (web request)
  11. (web uri))
  12. (define base64-alphabet
  13. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
  14. (define base64url-alphabet
  15. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_")
  16. ;; Create a lookup table for the alphabet and remember the latest table.
  17. (define get-decode-table
  18. (let ((ascii-table #f)
  19. (extra-table '()) ;in the unlikely case of unicode chars
  20. (table-alphabet #f))
  21. (lambda (alphabet)
  22. (unless (eq? alphabet table-alphabet)
  23. ;; Rebuild the table.
  24. (do ((ascii (make-vector 128 #f))
  25. (extra '())
  26. (i 0 (+ i 1)))
  27. ((= i (string-length alphabet))
  28. (set! ascii-table ascii)
  29. (set! extra-table extra))
  30. (let ((c (char->integer (string-ref alphabet i))))
  31. (if (fx<=? c 127)
  32. (vector-set! ascii c i)
  33. (set! extra (cons (cons c i) extra)))))
  34. (set! table-alphabet alphabet))
  35. (values ascii-table extra-table))))
  36. ;; Decodes a correctly padded base64 string, optionally ignoring
  37. ;; non-alphabet characters.
  38. (define base64-decode
  39. (case-lambda
  40. ((str)
  41. (base64-decode str base64-alphabet #f))
  42. ((str alphabet)
  43. (base64-decode str alphabet #f))
  44. ((str alphabet port)
  45. (base64-decode str alphabet port #t))
  46. ((str alphabet port strict?)
  47. (define (pad? c) (eqv? c (char->integer #\=)))
  48. (let-values (((p extract) (if port
  49. (values port (lambda () (values)))
  50. (open-bytevector-output-port)))
  51. ((ascii extra) (get-decode-table alphabet)))
  52. (define-syntax lookup
  53. (syntax-rules ()
  54. ((_ c) (or (and (fx<=? c 127) (vector-ref ascii c))
  55. (cond ((assv c extra) => cdr)
  56. (else #f))))))
  57. (let* ((len (if strict?
  58. (string-length str)
  59. (let lp ((i (fx- (string-length str) 1)))
  60. ;; Skip trailing invalid chars.
  61. (cond ((fxzero? i) 0)
  62. ((let ((c (char->integer (string-ref str i))))
  63. (or (lookup c) (pad? c)))
  64. (fx+ i 1))
  65. (else (lp (fx- i 1))))))))
  66. (let lp ((i 0))
  67. (cond
  68. ((fx=? i len)
  69. (extract))
  70. ((fx<=? i (fx- len 4))
  71. (let lp* ((c1 (char->integer (string-ref str i)))
  72. (c2 (char->integer (string-ref str (fx+ i 1))))
  73. (c3 (char->integer (string-ref str (fx+ i 2))))
  74. (c4 (char->integer (string-ref str (fx+ i 3))))
  75. (i i))
  76. (let ((i1 (lookup c1)) (i2 (lookup c2))
  77. (i3 (lookup c3)) (i4 (lookup c4)))
  78. (cond
  79. ((and i1 i2 i3 i4)
  80. ;; All characters present and accounted for.
  81. ;; The most common case.
  82. (let ((x (fxior (fxarithmetic-shift-left i1 18)
  83. (fxarithmetic-shift-left i2 12)
  84. (fxarithmetic-shift-left i3 6)
  85. i4)))
  86. (put-u8 p (fxbit-field x 16 24))
  87. (put-u8 p (fxbit-field x 8 16))
  88. (put-u8 p (fxbit-field x 0 8))
  89. (lp (fx+ i 4))))
  90. ((and i1 i2 i3 (pad? c4) (= i (- len 4)))
  91. ;; One padding character at the end of the input.
  92. (let ((x (fxior (fxarithmetic-shift-left i1 18)
  93. (fxarithmetic-shift-left i2 12)
  94. (fxarithmetic-shift-left i3 6))))
  95. (put-u8 p (fxbit-field x 16 24))
  96. (put-u8 p (fxbit-field x 8 16))
  97. (lp (fx+ i 4))))
  98. ((and i1 i2 (pad? c3) (pad? c4) (= i (- len 4)))
  99. ;; Two padding characters.
  100. (let ((x (fxior (fxarithmetic-shift-left i1 18)
  101. (fxarithmetic-shift-left i2 12))))
  102. (put-u8 p (fxbit-field x 16 24))
  103. (lp (fx+ i 4))))
  104. ((not strict?)
  105. ;; Non-alphabet characters.
  106. (let lp ((i i) (c* '()) (n 4))
  107. (cond ((fxzero? n)
  108. ;; Found four valid characters.
  109. (lp* (cadddr c*) (caddr c*) (cadr c*) (car c*)
  110. (fx- i 4)))
  111. ((fx=? i len)
  112. (error 'base64-decode
  113. "Invalid input in non-strict mode."
  114. i c*))
  115. (else
  116. ;; Gather alphabetic (or valid
  117. ;; padding) characters.
  118. (let ((c (char->integer (string-ref str i))))
  119. (cond ((or (lookup c)
  120. (and (pad? c)
  121. (fx<=? n 2)
  122. (fx=? i (fx- len n))))
  123. (lp (fx+ i 1) (cons c c*) (fx- n 1)))
  124. (else
  125. (lp (fx+ i 1) c* n))))))))
  126. (else
  127. (error 'base64-decode
  128. "Invalid input in strict mode."
  129. c1 c2 c3 c4))))))
  130. (else
  131. (error 'base64-decode
  132. "The input is too short, it may be missing padding." i)))))))))
  133. (define (handler request body)
  134. (let* ((path* (uri-path (request-uri request)))
  135. (path (string-drop path* (min 1 (string-length path*))))
  136. (err #f)
  137. (errparams '())
  138. (res ""))
  139. (catch #t
  140. (lambda ()
  141. (set! res (utf8->string (base64-decode path))))
  142. (lambda (key . parameters) (set! err key) (set! errparams parameters)))
  143. (if err
  144. (values '((content-type . (text/plain)))
  145. (format #f "Hello, Error! \n\n~a\n\nCould not decode base64: ~a" err path))
  146. (values '((content-type . (text/plain)))
  147. (format #f "I am just a simple, overloaded homeserver. But come, try me! \n\nDecoded base64: ~a" res)))))
  148. (run-server handler #:host "192.168.178.101" #:port 2342)