AtlatestRepositorysigil-http

sigil-http / tree / testtest-multipart-bytes.sgl

1(import (sigil io)
2 (sigil test)
3 (sigil http request))
4
5(define (wrap bytes ending)
6 (bytevector-append (string->utf8 "--boundary\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\né雪\r\n--boundary\r\nContent-Disposition: form-data; name=\"logo\"; filename=\"test.png\"\r\nContent-Type: image/png\r\n\r\n") bytes (string->utf8 ending)))
7(define binary (make-bytevector 256))
8(let loop ((i 0))
9 (when (< i 256)
10 (bytevector-u8-set! binary i i)
11 (loop (+ i 1))))
12(test-group "byte multipart"
13 (test "UTF-8 fields decode independently of arbitrary file bytes"
14 (let* ((parts (parse-multipart-form-data-bytes (wrap binary "\r\n--boundary--\r\n") "boundary"))
15 (file (dict-ref (cdr (assoc 'logo parts)) content:)))
16 (assert-equal (cdr (assoc 'title parts)) "é雪")
17 (assert-equal (bytevector-length file) 256)
18 (let loop ((i 0))
19 (when (< i 256)
20 (assert-equal (bytevector-u8-ref file i) i)
21 (loop (+ i 1))))))
22 (test "file trailing CRLF and boundary lookalikes are retained"
23 (let* ((payload "x\r\n--boundaryX\r\n ")
24 (parts (parse-multipart-form-data-bytes (wrap (string->utf8 payload) "\r\n--boundary--") "boundary")))
25 (assert-equal (utf8->string (dict-ref (cdr (assoc 'logo parts)) content:)) payload)))
26 (test "empty file stays a zero-length bytevector"
27 (let ((parts (parse-multipart-form-data-bytes (wrap (make-bytevector 0) "\r\n--boundary--\r\n") "boundary")))
28 (assert-equal (bytevector-length (dict-ref (cdr (assoc 'logo parts)) content:)) 0)))
29 (test "truncated and malformed boundaries fail"
30 (assert-error (parse-multipart-form-data-bytes (wrap binary "") "boundary"))
31 (assert-error (parse-multipart-form-data-bytes (wrap binary "\r\n--boundary--oops") "boundary"))
32 (assert-error (parse-multipart-form-data-bytes binary "")))
33 (test "auto parser uses raw bytes even if body text was decoded"
34 (let* ((raw (wrap binary "\r\n--boundary--\r\n"))
35 (req (http-request method: 'POST path: "/" query: #f version: "HTTP/1.1"
36 headers: #{ content-type: "multipart/form-data; boundary=boundary" }
37 body: "damaged text" raw-body: raw))
38 (parts (parse-form-data req)))
39 (assert-equal (bytevector-length (dict-ref (cdr (assoc 'logo parts)) content:)) 256))))