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
module C = Cohttp.Cookie.Set_cookie_hdr
let domain_from_uri uri =
Uri.host uri
|> Option.value ~default:""
module Cookie = struct
type expiration = [
| `Session
| `Max_age of int64
]
type t = { name : string;
value : string;
expiration : expiration;
domain : string;
path : string;
secure : bool }
let name c = c.name
let value c = c.value
let expiration c = c.expiration
let domain c = c.domain
let path c = c.path
let secure c = c.secure
let domain_match host dom =
let host_length,dom_length = String.length host, String.length dom in
let delta = host_length - dom_length in
host=dom
|| (delta > 0
&& String.sub host delta (host_length-delta) = dom
&& host.[delta-1] = '.')
let path_match uri_path cookie_path =
let u_length, c_length = String.length uri_path,
String.length cookie_path in
u_length >= c_length && String.sub uri_path 0 c_length = cookie_path
let match_uri uri cookie =
match Uri.host uri, domain cookie with
| Some host, dom ->
domain_match host dom
&& path_match (Uri.path uri) (path cookie)
| _ -> false
let make ?(expiration = `Session) ?(path = "") ?(secure = false) ~domain name value =
{ name = name;
value = value;
expiration = expiration;
domain = domain;
path = path;
secure = secure}
let from_hdr uri c =
{ name = C.cookie c |> fst;
value = C.cookie c |> snd;
expiration = C.expiration c;
domain = Option.value (C.domain c) ~default:(domain_from_uri uri);
path = Option.value (C.path c) ~default:"";
secure = C.secure c }
end
module Key = struct
type t = {name: string; domain : string; path : string}
let key c =
{name = Cookie.name c;
domain = Cookie.domain c;
path = Cookie.path c}
let to_string k = k.name ^ k.domain ^ k.path
let compare k k' = String.compare (to_string k) (to_string k')
end
module JarMap = Map.Make(Key)
type t = Cookie.t JarMap.t
let map = JarMap.map
let iter f = JarMap.iter (fun _ -> f)
let fold f = JarMap.fold (fun _ -> f)
let is_empty = JarMap.is_empty
let empty = JarMap.empty
let add c jar =
match Cookie.expiration c with
| `Max_age 0L -> JarMap.remove (Key.key c) jar
| _ -> JarMap.add (Key.key c) c jar
let remove c jar = JarMap.remove (Key.key c) jar
let uri jar =
let add_to_jar jar c = add (Cookie.from_hdr uri c) jar in
C.extract headers
|> List.map snd
|> List.fold_left add_to_jar jar
let uri jar =
let buffer = Buffer.create 64 in
let c first =
match Cookie.match_uri uri c with
| true ->
let sep = (match first with
| true -> ""
| false -> "; ")
in
Printf.bprintf buffer "%s%s=%s" sep (Cookie.name c) (Cookie.value c);
false
| false -> first
in
fold to_header jar true |> ignore;
Cohttp.Header.add headers "Cookie" (Buffer.contents buffer)