Multipart

decodes multipart/form-data bodies (RFC 7578) into their parts. The boundary is a parameter of the Content-Type header; Request.multipart-data reads it off the request for you.

(match (Request.multipart-data &req)
  (Result.Success parts)
    (println* (FormPart.name (Array.unsafe-nth &parts 0)))
  (Result.Error e) (IO.errorln &e))

parse yields FormParts, whose bodies are Strings and so stop at their first NUL byte. Uploads that are not text need parse-bytes, which yields BinaryParts instead.

parse

defn

(Fn [(Ref String a), (Ref String b)] (Result (Array FormPart) String))

                        (parse body boundary)
                    

decodes a multipart/form-data body with the given boundary into its FormParts. Fails on the same bodies parse-bytes does.

A Carp String ends at its first NUL byte, so a binary body — any PNG, PDF or zip upload — is cut short before parsing even begins, and usually decodes to no parts at all. Reach for parse-bytes whenever the body might not be text.

parse-bytes

defn

(Fn [(Ref (Array Byte) a), (Ref String b)] (Result (Array BinaryPart) String))

                        (parse-bytes body boundary)
                    

decodes a multipart/form-data body with the given boundary into its BinaryParts, reading the body as bytes so that binary uploads survive intact.

Fails when the opening boundary delimiter is absent, when a part’s headers are not terminated by a CRLF CRLF — RFC 7578 requires every part to carry a Content-Disposition, so a part with no header block at all is malformed — and when a part’s header region holds a NUL byte: header field lines are US-ASCII, and reading one as a String would cut a filename short without saying so.

Any of these fails the whole body, not just the offending part.