feat multipart: add helper to parse boundary

This commit is contained in:
Simon Cruanes 2024-12-02 14:45:26 -05:00
parent 3f37161649
commit a5a06f0159
No known key found for this signature in database
GPG key ID: EBFFF6F283F3A2B4
3 changed files with 31 additions and 55 deletions

View file

@ -204,6 +204,30 @@ and parse_headers_rec (self : st) acc : Headers.t =
) )
) )
let parse_content_type (hs : Tiny_httpd.Headers.t) : _ option =
match Tiny_httpd.Headers.get "content-type" hs with
| None -> None
| Some s ->
(match String.split_on_char ';' s with
| "multipart/form-data" :: tl ->
let boundary = ref None in
List.iter
(fun s ->
match Utils_.split1_on ~c:'=' @@ String.trim s with
| Some ("boundary", "") -> ()
| Some ("boundary", s) ->
let s =
if s.[0] = '"' && s.[String.length s - 1] = '"' then
String.sub s 1 (String.length s - 2)
else
s
in
boundary := Some (`boundary s)
| _ -> ())
tl;
!boundary
| _ -> None)
module Private_ = struct module Private_ = struct
type nonrec chunk = chunk = Delim | Eof | Read of int type nonrec chunk = chunk = Delim | Eof | Read of int

View file

@ -5,6 +5,9 @@ type st
val create : val create :
?buf_size:int -> ?out_buf_size:int -> boundary:string -> #Iostream.In.t -> st ?buf_size:int -> ?out_buf_size:int -> boundary:string -> #Iostream.In.t -> st
val parse_content_type : Tiny_httpd.Headers.t -> [ `boundary of string ] option
(** Parse headers for [content-type: multipart/form-data; boundary=…] *)
type slice = Iostream.Slice.t type slice = Iostream.Slice.t
type event = Part of Tiny_httpd.Headers.t | Read of slice | End_of_input type event = Part of Tiny_httpd.Headers.t | Read of slice | End_of_input

View file

@ -1,5 +1,3 @@
(* module StringMap = Map.Make (String) *)
let string_eq ~a ~a_start ~b ~len : bool = let string_eq ~a ~a_start ~b ~len : bool =
assert (len <= String.length b); assert (len <= String.length b);
if String.length a >= a_start + len then ( if String.length a >= a_start + len then (
@ -14,56 +12,7 @@ let string_eq ~a ~a_start ~b ~len : bool =
) else ) else
false false
let ends_with ~suffix ~suffix_length s = let split1_on ~c s =
let s_length = String.length s in match String.index s c with
s_length >= suffix_length | exception Not_found -> None
&& string_eq ~a:s ~a_start:(s_length - suffix_length) ~b:suffix | i -> Some (String.sub s 0 i, String.sub s (i + 1) (String.length s - i - 1))
~len:suffix_length
let rec first_matching p = function
| [] -> None
| x :: xs ->
(match p x with
| Some y -> Some y
| None -> first_matching p xs)
let[@inline] option_map f = function
| None -> None
| Some x -> Some (f x)
let find_common_idx a b =
let rec go i =
if i <= 0 then
None
else if ends_with ~suffix:b ~suffix_length:i a then
Some (String.length a - i)
else
go (i - 1)
in
go (String.length b)
(*
let[@inline] word = function
| "" -> []
| w -> [ Some w ]
let split_on_string ~pattern s =
let pattern_length = String.length pattern in
let rec go start acc =
match Stringext.find_from ~start s ~pattern with
| Some match_start ->
let before = String.sub s start (match_start - start) in
let new_acc = (None :: word before) @ acc in
let new_start = match_start + pattern_length in
go new_start new_acc
| None -> word (Stringext.string_after s start) @ acc
in
List.rev (go 0 [])
let split_and_process_string ~boundary s =
let f = function
| None -> `Delim
| Some w -> `Word w
in
List.map f @@ split_on_string ~pattern:boundary s
*)