package opium

  1. Overview
  2. Docs
OCaml web framework

Install

dune-project
 Dependency

Authors

Maintainers

Sources

opium-0.20.0.tbz
sha256=326b91866de90baf535f8b7d4b2ff23e39d952e573c04b3c13f1054b59ff2fb6
sha512=59b83e7c8fe5f7ae328fb7f2343fe5b8fb735e8f6ee263cfd6c75bb179688ef7cf2b4586b35a2231ed3f3c1ada543021b7a4759326ae095eb77a5f38b9fa3a8a

doc/src/opium/request.ml.html

Source file request.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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
open Import
include Rock.Request

let of_string'
    ?(content_type = "text/plain")
    ?version
    ?env
    ?(headers = Headers.empty)
    target
    meth
    body
  =
  let headers = Headers.add_unless_exists headers "Content-Type" content_type in
  make ?version ~headers ~body:(Body.of_string body) ?env target meth
;;

let of_plain_text ?version ?headers ?env ~body target meth =
  of_string' ?version ?env ?headers target meth body
;;

let of_json ?version ?headers ?env ~body target meth =
  of_string'
    ~content_type:"application/json"
    ?version
    ?headers
    ?env
    target
    meth
    (body |> Yojson.Safe.to_string)
;;

let of_urlencoded ?version ?headers ?env ~body target meth =
  of_string'
    ~content_type:"application/x-www-form-urlencoded"
    ?version
    ?headers
    ?env
    target
    meth
    (body |> Uri.encoded_of_query)
;;

let to_json_exn t =
  let open Lwt.Syntax in
  let* body = t.body |> Body.copy |> Body.to_string in
  Lwt.return @@ Yojson.Safe.from_string body
;;

let to_json t =
  let open Lwt.Syntax in
  Lwt.catch
    (fun () ->
      let+ json = to_json_exn t in
      Some json)
    (function
      | _ -> Lwt.return None)
;;

let to_plain_text t = Body.copy t.body |> Body.to_string

let to_urlencoded t =
  let open Lwt.Syntax in
  let* body = t.body |> Body.copy |> Body.to_string in
  body |> Uri.query_of_encoded |> Lwt.return
;;

let header header t = Headers.get t.headers header
let headers header t = Headers.get_multi t.headers header
let add_header (k, v) t = { t with headers = Headers.add t.headers k v }

let add_header_or_replace (k, v) t =
  { t with
    headers =
      (if Headers.mem t.headers k
      then Headers.replace t.headers k v
      else Headers.add t.headers k v)
  }
;;

let add_header_unless_exists (k, v) t =
  { t with headers = Headers.add_unless_exists t.headers k v }
;;

let add_headers hs t = { t with headers = Headers.add_list t.headers hs }

let add_headers_or_replace hs t =
  List.fold_left hs ~init:t ~f:(fun acc el -> add_header_or_replace el acc)
;;

let add_headers_unless_exists hs t =
  { t with headers = Headers.add_list_unless_exists t.headers hs }
;;

let remove_header key t = { t with headers = Headers.remove t.headers key }

let cookie ?signed_with cookie t =
  Cookie.cookie_of_headers ?signed_with cookie (t.headers |> Headers.to_list)
  |> Option.map snd
;;

let cookies ?signed_with t =
  Cookie.cookies_of_headers ?signed_with (t.headers |> Headers.to_list)
;;

let add_cookie ?sign_with (k, v) t =
  let cookies = cookies t in
  let cookies =
    List.replace_or_add
      ~f:(fun (k2, _v2) _ -> String.equal k k2)
      ( k
      , match sign_with with
        | Some signer -> Cookie.Signer.sign signer v
        | None -> v )
      cookies
  in
  let cookie_header = cookies |> List.map ~f:Cookie.make |> Cookie.to_cookie_header in
  add_header_or_replace cookie_header t
;;

let add_cookie_unless_exists ?sign_with (k, v) t =
  let cookies = cookies t in
  if List.exists cookies ~f:(fun (k2, _v2) -> String.equal k2 k)
  then t
  else add_cookie ?sign_with (k, v) t
;;

let remove_cookie key t =
  let cookie_header =
    cookies t
    |> List.filter_map ~f:(fun (k, v) ->
           if not (String.equal k key) then Some (Cookie.make (k, v)) else None)
    |> Cookie.to_cookie_header
  in
  add_header_or_replace cookie_header t
;;

let content_type t = header "Content-Type" t
let set_content_type s t = add_header ("Content-Type", s) t

let authorization t =
  let s = header "Authorization" t in
  Option.map Auth.credential_of_string s
;;

let set_authorization cred t =
  let s = Auth.string_of_credential cred in
  add_header ("Authorization", s) t
;;

let to_multipart_form_data
    ?(callback = fun ~name:_ ~filename:_ _line -> Lwt.return_unit)
    t
  =
  match t.meth, content_type t with
  | `POST, Some content_type
    when String.is_prefix content_type ~prefix:"multipart/form-data; boundary=" ->
    let open Lwt.Syntax in
    let body = t.body |> Body.copy |> Body.to_stream in
    let* result = Multipart_form_data.parse ~stream:body ~content_type ~callback in
    Lwt.return @@ Some result
  | _ -> Lwt.return None
;;

let to_multipart_form_data_exn ?callback t =
  let open Lwt.Syntax in
  let* result = to_multipart_form_data ?callback t in
  match result with
  | Some r -> Lwt.return r
  | None ->
    raise (Invalid_argument "The request is not a valid multipart/form-data request.")
;;

let find_in_query key query =
  query
  |> List.assoc_opt key
  |> fun opt ->
  Option.bind opt (function
      | [] -> None
      | x :: _ -> Some x)
;;

let find_list_in_query key query =
  query |> List.concat_map ~f:(fun (k, v) -> if k = key then v else [])
;;

let urlencoded key t =
  let open Lwt.Syntax in
  let* query = to_urlencoded t in
  Lwt.return @@ find_in_query key query
;;

let urlencoded_list key t =
  let open Lwt.Syntax in
  let* query = to_urlencoded t in
  Lwt.return @@ find_list_in_query key query
;;

let urlencoded_exn key t =
  let open Lwt.Syntax in
  let+ o = urlencoded key t in
  Option.get o
;;

let query_list t = t.target |> Uri.of_string |> Uri.query
let query key t = query_list t |> find_in_query key
let query_exn key t = query key t |> Option.get

let sexp_of_t { version; target; headers; meth; body; env } =
  let open Sexp_conv in
  let open Sexp in
  List
    [ List [ Atom "version"; Version.sexp_of_t version ]
    ; List [ Atom "target"; sexp_of_string target ]
    ; List [ Atom "method"; Method.sexp_of_t meth ]
    ; List [ Atom "headers"; Headers.sexp_of_t headers ]
    ; List [ Atom "body"; Body.sexp_of_t body ]
    ; List [ Atom "env"; Context.sexp_of_t env ]
    ]
;;

let pp fmt t = Sexplib0.Sexp.pp_hum fmt (sexp_of_t t)

let pp_hum fmt t =
  Format.fprintf
    fmt
    "%s %s %s\n%s\n\n%a\n%!"
    (Method.to_string t.meth)
    t.target
    (Version.to_string t.version)
    (Headers.to_string t.headers)
    Body.pp_hum
    t.body
;;
OCaml

Innovation. Community. Security.