blob: 7f581a54ec49aa5869312547ed68ec6c4a9310b6 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
;;;; lazybones.decoders package.
(in-package #:lazybones.decoders)
;;; HELPERS
(defun read-body-to-string (stream content-length)
"Reads CONTENT-LENGTH characters from STREAM and returns a string."
(let ((string (make-string content-length)))
(read-sequence string stream)
string))
(defun binary-content-p (content-type)
(or (alexandria:starts-with-subseq "image" content-type)
(alexandria:starts-with-subseq "audio" content-type)
(and (alexandria:starts-with-subseq "application" content-type)
(not (equal content-type "application/json")))
(alexandria:starts-with-subseq "video" content-type)))
(defun butlast-to-string (res)
(map 'string 'identity (butlast res)))
(defun make-keyword (str)
(read-from-string (format nil ":~a" str)))
(defun write-binary-to-tmp-file (body)
(cl-fad:with-output-to-temporary-file (out-file :element-type '(unsigned-byte 8))
(loop :for char :across body :do (write-byte (char-int char) out-file))))
;;; PLAIN TEXT DECODER
(defun decode-text/plain (stream content-type content-length)
(declare (ignore content-type))
(read-body-to-string stream content-length))
(add-decoder "text/plain" #'decode-text/plain)
;;; JSON DECODER
(defun decode-application/json (stream content-type content-length)
"Reads LEN characters from stream and decodes them as JSON, returning a PLIST"
(declare (ignore content-type))
(jonathan:parse (read-body-to-string stream content-length)))
(add-decoder "application/json" #'decode-application/json)
;;; MULTIPART/FORM-DATA DECODER
;; Temporarily justing the hunchentoot post-parameter feature
(add-decoder "multipart/form-data"
(lambda (&rest ignore)
(declare (ignore ignore))
(loop :for (k . v) :in (hunchentoot:post-parameters*)
:when (and (listp v) (= 3 (length v)))
:collect (list :name k
:body (first v)
:filename (second v)
:content-type (third v))
:collect (list :name k :body v))))
;;; APPLICATION/X-WWW-FORM-URLENCODED
(defun decode-application/x-www-form-urlencoded (stream content-type content-length)
(declare (ignore content-type))
(->> (read-body-to-string stream content-length)
(split-sequence #\&)
(mapcar (lambda (s) (split-sequence #\= s)))
(as->* pairs
(loop
:for (key undecoded) :in pairs
:appending (list (make-keyword key)
(urldecode undecoded :queryp t))))))
(add-decoder "application/x-www-form-urlencoded"
#'decode-application/x-www-form-urlencoded)
|