2023-02-27

multipart-form-data parsing

sph-lib includes a multipart-form-data parser that can do partial reading and supports unlimited nesting of parts

usage example

below is an example that reads all data and saves it in a list. this is what the simpler to use "html-read-multipart-form-data" does internally

(import (sph) (sph web html))

(define-as example-data open-input-string
  "-----------------------------19737173311706079401624261242\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\naeu\r\n-----------------------------19737173311706079401624261242\r\nContent-Disposition: form-data; name=\"names\"\r\n\r\n[\"a\",\"b\"]\r\n-----------------------------19737173311706079401624261242\r\nContent-Disposition: form-data; name=\"type\"\r\n\r\ndocl\r\n-----------------------------19737173311706079401624261242--\r\n")

(html-fold-multipart-form-data
  (l (header fold-lines result)
    (fold-lines
      (l (line result next) (next (pair line result)))
      (list)
      (l (result-fold-lines result next-part)
        (next-part
          (pair
            (pair header
              (if (null? result-fold-lines) result-fold-lines
                (string-join
                  (reverse
                    (pair (string-drop-right (first result-fold-lines) 2)
                      (tail result-fold-lines)))
                  "")))
            result)))))
  (l (header port result) (pair (pair header (html-read-multipart-form-data port)) result)) (list)
  example-data)

the result

(((("Content-Disposition"
  ("form-data" . #t)
    ("name" . "type")))
  .
  "docl")
  ((("Content-Disposition"
    ("form-data" . #t)
    ("name" . "names")))
  .
  "[\"a\",\"b\"]")
  ((("Content-Disposition"
    ("form-data" . #t)
    ("name" . "content")))
  .
  "aeu"))
(html-multipart-form-data-ref result "submit-name")
((("Content-Disposition"
  ("form-data" . #t)
  ("name" . "submit-name")))
  .
  "Larry")