Source file req.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
open Base
open Lwt.Syntax
type t = Opium_kernel.Request.t
let key : t Core.Ctx.key = Core.Ctx.create_key ()
let add_to_ctx req ctx = Core.Ctx.add key req ctx
let create_and_add_to_ctx ?(body = "") ?(uri = "/") ctx =
let req =
Opium.Std.Request.create
~body:(Cohttp_lwt.Body.of_string body)
(Cohttp_lwt.Request.make (Uri.of_string uri))
in
add_to_ctx req ctx
let get_req ctx =
match Core.Ctx.find key ctx with
| None -> raise (Http_core.Exception "No HTTP request found in context")
| Some req -> req
module Query = struct
type t = (string * string list) list [@@deriving eq, show, yojson]
end
let is_get ctx =
let req = get_req ctx in
match Opium_kernel.Rock.Request.meth req with `GET -> true | _ -> false
let get_uri ctx =
let req = get_req ctx in
Opium_kernel.Request.uri req
let accepts_html ctx =
let req = get_req ctx in
Cohttp.Header.get (Opium.Std.Request.headers req) "Accept"
|> Option.value_map ~default:false ~f:(fun a ->
String.is_substring a ~substring:"text/html")
let ctx =
let req = get_req ctx in
match req |> Opium.Std.Request.headers |> Cohttp.Header.get_authorization with
| None -> Error "No authorization header found"
| Some token -> Ok token
let cookie_data ctx ~key =
let req = get_req ctx in
let cookies =
req |> Opium_kernel.Request.headers |> Cohttp.Cookie.Cookie_hdr.extract
in
cookies
|> List.find ~f:(fun (k, _) -> String.equal key k)
|> Option.map ~f:(fun (_, v) -> Uri.pct_decode v)
let ctx key =
let req = get_req ctx in
Cohttp.Header.get (Opium.Std.Request.headers req) key
let parse_token ctx =
get_header ctx "authorization"
|> Option.map ~f:(String.split ~on:' ')
|> Option.bind ~f:List.tl |> Option.bind ~f:List.hd
let find_in_query key query =
query
|> List.find ~f:(fun (k, _) -> String.equal k key)
|> Option.map ~f:(fun (_, r) -> r)
|> Option.bind ~f:List.hd
let get_query_string ctx =
let req = get_req ctx in
req |> Opium.Std.Request.uri |> Uri.query
let query_opt ctx key = ctx |> get_query_string |> find_in_query key
let query ctx key =
match query_opt ctx key with
| None -> Error (Printf.sprintf "Please provide a key '%s'" key)
| Some value -> Ok value
let query2_opt ctx key1 key2 = (query_opt ctx key1, query_opt ctx key2)
let query2 ctx key1 key2 = (query ctx key1, query ctx key2)
let query3_opt ctx key1 key2 key3 =
(query_opt ctx key1, query_opt ctx key2, query_opt ctx key3)
let query3 ctx key1 key2 key3 = (query ctx key1, query ctx key2, query ctx key3)
let urlencoded_list ?body ctx =
let req = get_req ctx in
let* body =
match body with
| Some body -> Lwt.return body
| None -> req |> Opium.Std.Request.body |> Opium.Std.Body.to_string
in
body |> Uri.pct_decode |> Uri.query_of_encoded |> Lwt.return
let urlencoded ?body ctx key =
let req = get_req ctx in
let* body =
match body with
| Some body -> Lwt.return body
| None -> req |> Opium.Std.Request.body |> Opium.Std.Body.to_string
in
match body |> Uri.pct_decode |> Uri.query_of_encoded |> find_in_query key with
| None -> Lwt.return None
| Some value -> Lwt.return @@ Some value
let urlencoded2 ctx key1 key2 =
let* body =
ctx |> get_req |> Opium.Std.Request.body |> Opium.Std.Body.to_string
in
let* value1 = urlencoded ~body ctx key1 in
let* value2 = urlencoded ~body ctx key2 in
Lwt.return @@ Option.both value1 value2
let urlencoded3 ctx key1 key2 key3 =
let* body =
ctx |> get_req |> Opium.Std.Request.body |> Opium.Std.Body.to_string
in
let* value1 = urlencoded ~body ctx key1 in
let* value2 = urlencoded ~body ctx key2 in
let* value3 = urlencoded ~body ctx key3 in
match (value1, value2, value3) with
| Some value1, Some value2, Some value3 ->
Lwt.return @@ Some (value1, value2, value3)
| _ -> Lwt.return None
let urlencoded4 ctx key1 key2 key3 key4 =
let* body =
ctx |> get_req |> Opium.Std.Request.body |> Opium.Std.Body.to_string
in
let* value1 = urlencoded ~body ctx key1 in
let* value2 = urlencoded ~body ctx key2 in
let* value3 = urlencoded ~body ctx key3 in
let* value4 = urlencoded ~body ctx key4 in
match (value1, value2, value3, value4) with
| Some value1, Some value2, Some value3, Some value4 ->
Lwt.return @@ Some (value1, value2, value3, value4)
| _ -> Lwt.return None
let urlencoded5 ctx key1 key2 key3 key4 key5 =
let* body =
ctx |> get_req |> Opium.Std.Request.body |> Opium.Std.Body.to_string
in
let* value1 = urlencoded ~body ctx key1 in
let* value2 = urlencoded ~body ctx key2 in
let* value3 = urlencoded ~body ctx key3 in
let* value4 = urlencoded ~body ctx key4 in
let* value5 = urlencoded ~body ctx key5 in
match (value1, value2, value3, value4, value5) with
| Some value1, Some value2, Some value3, Some value4, Some value5 ->
Lwt.return @@ Some (value1, value2, value3, value4, value5)
| _ -> Lwt.return None
let param ctx key =
let req = get_req ctx in
Option.try_with (fun () -> Opium.Std.param req key)
let param2 ctx key1 key2 = Option.both (param ctx key1) (param ctx key2)
let param3 ctx key1 key2 key3 =
match (param ctx key1, param ctx key2, param ctx key3) with
| Some p1, Some p2, Some p3 -> Some (p1, p2, p3)
| _ -> None
let param4 ctx key1 key2 key3 key4 =
match (param ctx key1, param ctx key2, param ctx key3, param ctx key4) with
| Some p1, Some p2, Some p3, Some p4 -> Some (p1, p2, p3, p4)
| _ -> None
let param5 ctx key1 key2 key3 key4 key5 =
match
( param ctx key1,
param ctx key2,
param ctx key3,
param ctx key4,
param ctx key5 )
with
| Some p1, Some p2, Some p3, Some p4, Some p5 -> Some (p1, p2, p3, p4, p5)
| _ -> None
let require_body ctx decode =
let* body =
ctx |> get_req |> Opium.Std.Request.body |> Cohttp_lwt.Body.to_string
in
body |> Utils.Json.parse |> Result.bind ~f:decode |> Lwt.return