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
open Misc
open Sexplib.Std
module Co = Cohttp
let encode x = Uri.pct_encode ~component:`Query_key x
let decode = Uri.pct_decode
module Env = struct
type cookie = (string * string) list
let key : cookie Hmap0.key =
Hmap0.Key.create ("cookie", [%sexp_of: (string * string) list])
end
module Env_resp = struct
type cookie = Co.Cookie.Set_cookie_hdr.t list
let key : cookie Hmap0.key =
Hmap0.Key.create ("cookie_res", [%sexp_of: Co.Cookie.Set_cookie_hdr.t list])
end
let current_cookies env record =
Option.value ~default:[] (Hmap0.find Env.key (env record))
let current_cookies_resp env record =
Option.value ~default:[] (Hmap0.find Env_resp.key (env record))
let cookies_raw req =
req |> Rock.Request.request |> Co.Request.headers
|> Co.Cookie.Cookie_hdr.extract
let cookies req =
req |> cookies_raw
|> List.filter_map ~f:(fun (k, v) ->
Option.try_with (fun () -> (k, decode v)))
let get req ~key =
let cookie1 =
let env = current_cookies (fun r -> r.Rock.Request.env) req in
List.find_map env ~f:(fun (k, v) -> if k = key then Some v else None)
in
match cookie1 with
| Some cookie -> Some cookie
| None ->
let cookies = cookies_raw req in
cookies
|> List.find_map ~f:(fun (k, v) ->
if k = key then Some (decode v) else None)
let set_cookies ?expiration ?(path = "/") ?domain ?secure ?http_only resp
cookies =
let env = Rock.Response.env resp in
let current_cookies =
current_cookies_resp (fun r -> r.Rock.Response.env) resp
in
let cookies' =
List.map cookies ~f:(fun (key, data) ->
Co.Cookie.Set_cookie_hdr.make ~path ?domain ?expiration ?secure
?http_only
(key, encode data))
in
let all_cookies = current_cookies @ cookies' in
{resp with Rock.Response.env= Hmap0.add Env_resp.key all_cookies env}
let set ?expiration ?path ?domain ?secure ?http_only resp ~key ~data =
set_cookies ?expiration ?path ?domain ?secure ?http_only resp [(key, data)]
let m =
let filter handler req =
handler req
>>| fun response ->
let =
let module Cookie = Co.Cookie.Set_cookie_hdr in
response
|> current_cookies_resp (fun r -> r.Rock.Response.env)
|> List.map ~f:Cookie.serialize
in
let = Rock.Response.headers response in
{ response with
Rock.Response.headers=
List.fold_left cookie_headers ~init:old_headers
~f:(fun (k, v) -> Co.Header.add headers k v) }
in
Rock.Middleware.create ~filter ~name:"Cookie"