-
Notifications
You must be signed in to change notification settings - Fork 190
/
Cookies.jl
executable file
·179 lines (138 loc) · 5.88 KB
/
Cookies.jl
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
"""
Functionality for dealing with HTTP cookies.
"""
module Cookies
import HTTP
import Genie, Genie.Encryption, Genie.HTTPUtils
"""
get(payload::Union{HTTP.Response,HTTP.Request}, key::Union{String,Symbol}, default::T; encrypted::Bool = true)::T where T
Attempts to get the Cookie value stored at `key` within `payload`.
If the `key` is not set, the `default` value is returned.
# Arguments
- `payload::Union{HTTP.Response,HTTP.Request}`: the request or response object containing the Cookie headers
- `key::Union{String,Symbol}`: the name of the cookie value
- `default::T`: default value to be returned if no cookie value is set at `key`
- `encrypted::Bool`: if `true` the value stored on the cookie is automatically decrypted
"""
function get(payload::Union{HTTP.Response,HTTP.Request}, key::Union{String,Symbol}, default::T; encrypted::Bool = true)::T where T
val = get(payload, key, encrypted = encrypted)
val === nothing ? default : parse(T, val)
end
"""
get(res::HTTP.Response, key::Union{String,Symbol}) :: Union{Nothing,String}
Retrieves a value stored on the cookie as `key` from the `Respose` object.
# Arguments
- `payload::Union{HTTP.Response,HTTP.Request}`: the request or response object containing the Cookie headers
- `key::Union{String,Symbol}`: the name of the cookie value
- `encrypted::Bool`: if `true` the value stored on the cookie is automatically decrypted
"""
function get(res::HTTP.Response, key::Union{String,Symbol}; encrypted::Bool = true) :: Union{Nothing,String}
(haskey(HTTPUtils.Dict(res), "Set-Cookie") || haskey(HTTPUtils.Dict(res), "set-cookie")) ?
nullablevalue(res, key, encrypted = encrypted) :
nothing
end
"""
get(req::Request, key::Union{String,Symbol}) :: Union{Nothing,String}
Retrieves a value stored on the cookie as `key` from the `Request` object.
# Arguments
- `req::HTTP.Request`: the request or response object containing the Cookie headers
- `key::Union{String,Symbol}`: the name of the cookie value
- `encrypted::Bool`: if `true` the value stored on the cookie is automatically decrypted
"""
function get(req::HTTP.Request, key::Union{String,Symbol}; encrypted::Bool = true) :: Union{Nothing,String}
(haskey(HTTPUtils.Dict(req), "cookie") || haskey(HTTPUtils.Dict(req), "Cookie")) ?
nullablevalue(req, key, encrypted = encrypted) :
nothing
end
"""
set!(res::HTTP.Response, key::Union{String,Symbol}, value::Any, attributes::Dict; encrypted::Bool = true) :: HTTP.Response
Sets `value` under the `key` label on the `Cookie`.
# Arguments
- `res::HTTP.Response`: the HTTP.Response object
- `key::Union{String,Symbol}`: the key for storing the cookie value
- `value::Any`: the cookie value
- `attributes::Dict`: additional cookie attributes, such as `Path` or `HttpOnly`
- `encrypted::Bool`: if `true` the value is stored encoded
"""
function set!(res::HTTP.Response, key::Union{String,Symbol}, value::Any, attributes::Dict{String,<:Any} = Dict(); encrypted::Bool = true) :: HTTP.Response
normalized_attrs = Dict{Symbol,Any}()
for (k,v) in attributes
normalized_attrs[Symbol(lowercase(string(k)))] = v
end
value = string(value)
encrypted && (value = Genie.Encryption.encrypt(value))
cookie = HTTP.Cookies.Cookie(string(key), value; normalized_attrs...)
headers = Dict(res.headers)
if haskey(headers, "Set-Cookie")
headers["Set-Cookie"] *= "\nSet-Cookie: " * HTTP.Cookies.String(cookie, false) * "; "
elseif haskey(headers, "set-cookie")
headers["set-cookie"] *= "\nset-cookie: " * HTTP.Cookies.String(cookie, false) * "; "
else
headers["Set-Cookie"] = HTTP.Cookies.String(cookie, false) * "; "
end
res.headers = [(k => v) for (k,v) in headers]
res
end
"""
Dict(req::Request) :: Dict{String,String}
Extracts the `Cookie` and `Set-Cookie` data from the `Request` and `Response` objects and converts it into a Dict.
"""
function Base.Dict(r::Union{HTTP.Request,HTTP.Response}) :: Dict{String,String}
d = Dict{String,String}()
headers = Dict(r.headers)
h = if haskey(headers, "Cookie")
split(headers["Cookie"], ";")
elseif haskey(headers, "cookie")
split(headers["cookie"], ";")
elseif haskey(headers, "Set-Cookie")
split(headers["Set-Cookie"], ";")
elseif haskey(headers, "set-cookie")
split(headers["set-cookie"], ";")
else
[]
end
for cookie in h
cookie_parts = split(cookie, "=")
if length(cookie_parts) == 2
d[strip(cookie_parts[1])] = cookie_parts[2]
else
d[strip(cookie_parts[1])] = ""
end
end
d
end
### PRIVATE ###
"""
nullablevalue(payload::Union{HTTP.Response,HTTP.Request}, key::Union{String,Symbol}; encrypted::Bool = true)
Attempts to retrieve a cookie value stored at `key` in the `payload object` and returns a `Union{Nothing,String}`
# Arguments
- `payload::Union{HTTP.Response,HTTP.Request}`: the request or response object containing the Cookie headers
- `key::Union{String,Symbol}`: the name of the cookie value
- `encrypted::Bool`: if `true` the value stored on the cookie is automatically decrypted
"""
function nullablevalue(payload::Union{HTTP.Response,HTTP.Request}, key::Union{String,Symbol}; encrypted::Bool = true) :: Union{Nothing,String}
for cookie in split(Dict(payload)["cookie"], ';')
cookie = strip(cookie)
if startswith(lowercase(cookie), lowercase(string(key)))
value = split(cookie, '=')[2] |> String
encrypted && (value = Genie.Encryption.decrypt(value))
return string(value)
end
end
nothing
end
"""
getcookies(req::HTTP.Request) :: Vector{HTTP.Cookies.Cookie}
Extracts cookies from within `req`
"""
function getcookies(req::HTTP.Request) :: Vector{HTTP.Cookies.Cookie}
HTTP.Cookies.cookies(req)
end
"""
getcookies(req::HTTP.Request) :: Vector{HTTP.Cookies.Cookie}
Extracts cookies from within `req`, filtering them by `matching` name.
"""
function getcookies(req::HTTP.Request, matching::String) :: Vector{HTTP.Cookies.Cookie}
HTTP.Cookies.readcookies(req.headers, matching)
end
end