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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
open Lwt.Syntax
include Opium_kernel.Rock.Request
let to_plain_text t = t |> Opium.Std.Request.body |> Opium.Std.Body.to_string
let to_json t =
let* body = t |> Opium.Std.Request.body |> Opium.Std.Body.to_string in
try Lwt.return (Some (Yojson.Safe.from_string body)) with
| _ -> Lwt.return None
;;
let to_json_exn t =
let* json = to_json t in
Lwt.return
(match json with
| Some json -> json
| None -> failwith "Failed to create request from json")
;;
let to_urlencoded t =
let* body = t |> Opium.Std.Request.body |> Opium.Std.Body.to_string in
Lwt.return (Uri.query_of_encoded body)
;;
let to_multipart_form_data_exn
?(callback = fun ~name:_ ~filename:_ _line -> Lwt.return_unit)
t
=
let stream = t |> Opium.Std.Request.body |> Opium.Std.Body.to_stream in
Multipart_form_data.parse ~stream ~content_type:"multipart/form-data" ~callback
;;
let to_multipart_form_data
?(callback = fun ~name:_ ~filename:_ _line -> Lwt.return_unit)
t
=
Lwt.catch
(fun () ->
let* parsed = to_multipart_form_data_exn ~callback t in
Lwt.return (Some parsed))
(fun _ -> Lwt.return None)
;;
let s t = Cohttp.Header.get (Cohttp.Request.headers t.request) s
let s t = Cohttp.Header.get_multi (Cohttp.Request.headers t.request) s
let (k, v) t =
let request =
{ t.request with headers = Cohttp.Header.add (Cohttp.Request.headers t.request) k v }
in
{ t with request }
;;
let (k, v) t =
let request =
{ t.request with headers = Cohttp.Header.add (Cohttp.Request.headers t.request) k v }
in
{ t with request }
;;
let (k, v) t =
let request =
{ t.request with
headers = Cohttp.Header.add_unless_exists (Cohttp.Request.headers t.request) k v
}
in
{ t with request }
;;
let t =
let request =
{ t.request with
headers = Cohttp.Header.add_list (Cohttp.Request.headers t.request) headers
}
in
{ t with request }
;;
let t =
let request =
{ t.request with
headers = Cohttp.Header.add_list (Cohttp.Request.headers t.request) headers
}
in
{ t with request }
;;
let t =
List.fold_left (fun t (k, v) -> add_header_unless_exists (k, v) t) t headers
;;
let s t =
let request =
{ t.request with headers = Cohttp.Header.remove (Cohttp.Request.headers t.request) s }
in
{ t with request }
;;
let cookie ?signed_with cookie t =
Cookie.cookie_of_headers ?signed_with cookie (t.request.headers |> Cohttp.Header.to_list)
|> Option.map snd
;;
let cookies ?signed_with t =
Cookie.cookies_of_headers ?signed_with (t.request.headers |> Cohttp.Header.to_list)
;;
let replace_or_add_to_list ~f to_add l =
let found = ref false in
let rec aux acc l =
match l with
| [] -> if not !found then to_add :: acc |> List.rev else List.rev acc
| el :: rest ->
if f el to_add
then (
found := true;
aux (to_add :: acc) rest)
else aux (el :: acc) rest
in
aux [] l
;;
let add_cookie ?sign_with (k, v) t =
let cookies = cookies t in
let cookies =
replace_or_add_to_list
~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 = cookies |> List.map 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 (fun (k2, _v2) -> String.equal k2 k) cookies
then t
else add_cookie ?sign_with (k, v) t
;;
let remove_cookie key t =
let =
cookies t
|> List.filter (fun (k, _) -> not (String.equal k key))
|> List.map Cookie.make
|> 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_or_replace ("content-type", s) t
let find_in_query key query =
query
|> List.find_opt (fun (k, _) -> k = key)
|> Option.map (fun (_, r) -> r)
|> fun opt ->
Option.bind opt (fun x ->
try Some (List.hd x) with
| Not_found -> None)
;;
let urlencoded key t =
let open Lwt.Syntax in
let* query = to_urlencoded t in
Lwt.return @@ find_in_query key query
;;
let urlencoded_exn key t =
let open Lwt.Syntax in
let+ o = urlencoded key t in
match o with
| Some o -> o
| None -> failwith ("Could not get urlencoded with key: " ^ key)
;;
let query_list t = t.request |> Cohttp.Request.uri |> Uri.query
let query key t = query_list t |> find_in_query key
let query_exn key t =
match query key t with
| Some o -> o
| None -> failwith ("Can not get query string with key: " ^ key)
;;
let is_get req =
match Opium_kernel.Rock.Request.meth req with
| `GET -> true
| _ -> false
;;
let contains substring string =
let re = Str.regexp_string string in
try
ignore (Str.search_forward re substring 0);
true
with
| Not_found -> false
;;
let accepts_html req =
Cohttp.Header.get (Opium.Std.Request.headers req) "Accept"
|> Option.map (contains "text/html")
|> Option.value ~default:false
;;
let authorization_token t =
let ( let* ) = Option.bind in
let* = header "authorization" t in
match String.split_on_char ' ' header with
| [ _; token ] -> Some token
| _ -> None
;;
let param key t =
try Some (Opium.Std.param t key) with
| _ -> None
;;
let params key1 key2 t =
match param key1 t, param key2 t with
| Some a, Some b -> Some (a, b)
| _ -> None
;;
let params3 key1 key2 key3 t =
match param key1 t, param key2 t, param key3 t with
| Some p1, Some p2, Some p3 -> Some (p1, p2, p3)
| _ -> None
;;
let params4 key1 key2 key3 key4 t =
match param key1 t, param key2 t, param key3 t, param key4 t with
| Some p1, Some p2, Some p3, Some p4 -> Some (p1, p2, p3, p4)
| _ -> None
;;
let params5 key1 key2 key3 key4 key5 t =
match param key1 t, param key2 t, param key3 t, param key4 t, param key5 t with
| Some p1, Some p2, Some p3, Some p4, Some p5 -> Some (p1, p2, p3, p4, p5)
| _ -> None
;;
let make
?(body = Opium.Std.Body.empty)
?(env = Opium_kernel.Hmap.empty)
?( = Cohttp.Header.init ())
uri
meth
=
let uri = Uri.of_string uri in
let request = Cohttp_lwt_unix.Request.make ~meth ~headers uri in
{ body; env; request }
;;
let get
?(body = Opium.Std.Body.empty)
?(env = Opium_kernel.Hmap.empty)
?( = Cohttp.Header.init ())
uri
=
let uri = Uri.of_string uri in
let request = Cohttp_lwt_unix.Request.make ~meth:`GET ~headers uri in
{ body; env; request }
;;
let post
?(body = Opium.Std.Body.empty)
?(env = Opium_kernel.Hmap.empty)
?( = Cohttp.Header.init ())
uri
=
let uri = Uri.of_string uri in
let request = Cohttp_lwt_unix.Request.make ~meth:`POST ~headers uri in
{ body; env; request }
;;
let put
?(body = Opium.Std.Body.empty)
?(env = Opium_kernel.Hmap.empty)
?( = Cohttp.Header.init ())
uri
=
let uri = Uri.of_string uri in
let request = Cohttp_lwt_unix.Request.make ~meth:`PUT ~headers uri in
{ body; env; request }
;;
let delete
?(body = Opium.Std.Body.empty)
?(env = Opium_kernel.Hmap.empty)
?( = Cohttp.Header.init ())
uri
=
let uri = Uri.of_string uri in
let request = Cohttp_lwt_unix.Request.make ~meth:`DELETE ~headers uri in
{ body; env; request }
;;
let of_plain_text
?body
?(env = Opium_kernel.Hmap.empty)
?( = Cohttp.Header.init ())
uri
meth
=
let uri = Uri.of_string uri in
let body =
body
|> Option.map Cohttp_lwt.Body.of_string
|> Option.value ~default:Opium.Std.Body.empty
in
let request = Cohttp_lwt_unix.Request.make ~meth ~headers uri in
let request = { body; env; request } in
add_header ("content-type", "text/plain") request
;;
let of_json
?body
?(env = Opium_kernel.Hmap.empty)
?( = Cohttp.Header.init ())
uri
meth
=
let uri = Uri.of_string uri in
let body =
body
|> Option.map Yojson.Safe.to_string
|> Option.map Cohttp_lwt.Body.of_string
|> Option.value ~default:Opium.Std.Body.empty
in
let request = Cohttp_lwt_unix.Request.make ~meth ~headers uri in
let request = { body; env; request } in
add_header ("content-type", "application/json") request
;;
let of_urlencoded
?(body = [])
?(env = Opium_kernel.Hmap.empty)
?( = Cohttp.Header.init ())
uri
meth
=
let uri = Uri.of_string uri in
let body = body |> Uri.encoded_of_query |> Cohttp_lwt.Body.of_string in
let request = Cohttp_lwt_unix.Request.make ~meth ~headers uri in
{ body; env; request }
;;