package vif

  1. Overview
  2. Docs
A simple web framework for OCaml 5

Install

dune-project
 Dependency

Authors

Maintainers

Sources

vif-0.0.1.beta2.tbz
sha256=a16ff3dba7675d237d59188b032052b383ad9e367eb7c570c4e6e78b978b98e5
sha512=ad553f15f33f9f2427b691713f630476fd1f15b4cb61944a401cfb35c29dd3d1d3760b02dd211bddd39b6cf6ccc8ea5d9f88eefc3776611e2a7020242a16b9a9

doc/src/vif.core/vif_multipart_form.ml.html

Source file vif_multipart_form.ml

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
module Witness = struct
  type (_, _) eq = Refl : ('a, 'a) eq
  type _ equality = ..

  module type Inst = sig
    type t
    type _ equality += Eq : t equality
  end

  type 'a t = (module Inst with type t = 'a)

  let make : type a. unit -> a t =
   fun () ->
    let module Inst = struct
      type t = a
      type _ equality += Eq : t equality
    end in
    (module Inst)

  let _eq : type a b. a t -> b t -> (a, b) eq option =
   fun (module A) (module B) -> match A.Eq with B.Eq -> Some Refl | _ -> None
end

type 'a t = { rwit: 'a Witness.t; rfields: 'a fields_and_constr }

and 'a fields_and_constr =
  | Fields : ('a, 'b) fields * 'b -> 'a fields_and_constr

and ('a, 'b) fields =
  | F0 : ('a, 'a) fields
  | F1 : 'b field * ('a, 'c) fields -> ('a, 'b -> 'c) fields

and 'a field = { fname: string; ftype: 'a atom }
and 'a atom = Primary : 'a primary -> 'a atom | Record : 'a t -> 'a atom
and 'a primary = String : string primary | Int : int primary

type meta = {
    name: string option
  ; filename: string option
  ; size: int option
  ; mime: string option
}

let pp_meta ppf t =
  match (t.name, t.filename) with
  | Some name, _ -> Fmt.string ppf name
  | _, Some filename -> Fmt.string ppf filename
  | _ -> Fmt.pf ppf "<unknown-part>"

type raw = ((meta * Vif_headers.t) * string) list
type stream = (meta * string Flux.source) Flux.stream

module Fields_folder (Acc : sig
  type ('a, 'b) t
end) =
struct
  type 'a t = {
      nil: ('a, 'a) Acc.t
    ; cons: 'b 'c. 'b field -> ('a, 'c) Acc.t -> ('a, 'b -> 'c) Acc.t
  }

  let rec fold : type a c. a t -> (a, c) fields -> (a, c) Acc.t =
   fun folder -> function
    | F0 -> folder.nil
    | F1 (f, fs) -> folder.cons f (fold folder fs)
end

module Record_get = Fields_folder (struct
  type ('a, 'b) t = raw -> 'b -> 'a
end)

exception Field_not_found of string

let find_by_name name raw =
  let fn ((meta, _), _) =
    match meta.name with Some name' -> String.equal name name' | None -> false
  in
  let _, value =
    try List.find fn raw with Not_found -> raise (Field_not_found name)
  in
  value

let rec get_value : type a. a atom -> string -> raw -> a = function
  | Primary String -> find_by_name
  | Primary Int -> fun name raw -> int_of_string (find_by_name name raw)
  | Record r -> fun _ raw -> get_record r raw

and get_record : type a. a t -> raw -> a =
 fun { rfields= Fields (fs, constr); _ } ->
  let nil _raw fn = fn in
  let cons { fname; ftype } k =
    let get = get_value ftype fname in
    fun raw constr ->
      let x = get raw in
      let constr = constr x in
      k raw constr
  in
  let fn = Record_get.fold { nil; cons } fs in
  fun raw -> fn raw constr

type ('a, 'b, 'c) orecord = ('a, 'c) fields -> 'b * ('a, 'b) fields
type 'a a_field = Field : 'x field -> 'a a_field

let field fname ftype = { fname; ftype }
let record : 'b -> ('a, 'b, 'b) orecord = fun c fs -> (c, fs)

module SSet = Set.Make (String)

let check_unique fn =
  let rec go s = function
    | [] -> ()
    | x :: xs -> (
        match SSet.find_opt x s with
        | None -> go (SSet.add x s) xs
        | Some _ -> fn x)
  in
  go SSet.empty

let check_uniq_field_names rfields =
  let names = List.map (fun (Field { fname; _ }) -> fname) rfields in
  let failure fname =
    Fmt.invalid_arg "The name %s was used for two or more parts." fname
  in
  check_unique failure names

let fields r =
  let rec go : type a b. (a, b) fields -> a a_field list = function
    | F0 -> []
    | F1 (h, t) -> Field h :: go t
  in
  match r.rfields with Fields (f, _) -> go f

let app : type a b c d. (a, b, c -> d) orecord -> c field -> (a, b, d) orecord =
 fun r f fs -> r (F1 (f, fs))

let sealr : type a b. (a, b, a) orecord -> a t =
 fun r ->
  let c, fs = r F0 in
  let rwit = Witness.make () in
  let sealed = { rwit; rfields= Fields (fs, c) } in
  check_uniq_field_names (fields sealed);
  sealed

let ( |+ ) = app
let string = Primary String
let int = Primary Int