Packages
plug
1.12.1
1.20.3
1.20.2
1.20.1
retired
1.20.0
retired
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.15.6
1.15.5
1.15.4
1.15.3
1.15.2
1.15.1
1.15.0
1.14.2
1.14.1
1.14.0
1.13.6
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
retired
1.13.0
retired
1.12.1
1.12.0
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.2
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.0
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.14.0
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.4
0.4.3
0.4.2
0.4.1
Compose web applications with functions
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/plug/conn/cookies.ex
defmodule Plug.Conn.Cookies do
@moduledoc """
Conveniences for encoding and decoding cookies.
"""
@doc """
Decodes the given cookies as given in either a request or response header.
If a cookie is invalid, it is automatically discarded from the result.
## Examples
iex> decode("key1=value1;key2=value2")
%{"key1" => "value1", "key2" => "value2"}
"""
def decode(cookie) do
do_decode(:binary.split(cookie, ";", [:global]), %{})
end
defp do_decode([], acc), do: acc
defp do_decode([h | t], acc) do
case decode_kv(h) do
{k, v} -> do_decode(t, Map.put(acc, k, v))
false -> do_decode(t, acc)
end
end
defp decode_kv(""), do: false
defp decode_kv(<<h, t::binary>>) when h in [?\s, ?\t], do: decode_kv(t)
defp decode_kv(kv), do: decode_key(kv, "")
defp decode_key("", _key), do: false
defp decode_key(<<?=, _::binary>>, ""), do: false
defp decode_key(<<?=, t::binary>>, key), do: decode_value(t, "", key, "")
defp decode_key(<<h, _::binary>>, _key) when h in [?\s, ?\t, ?\r, ?\n, ?\v, ?\f], do: false
defp decode_key(<<h, t::binary>>, key), do: decode_key(t, <<key::binary, h>>)
defp decode_value("", _spaces, key, value), do: {key, value}
defp decode_value(<<?\s, t::binary>>, spaces, key, value),
do: decode_value(t, <<spaces::binary, ?\s>>, key, value)
defp decode_value(<<h, _::binary>>, _spaces, _key, _value) when h in [?\t, ?\r, ?\n, ?\v, ?\f],
do: false
defp decode_value(<<h, t::binary>>, spaces, key, value),
do: decode_value(t, "", key, <<value::binary, spaces::binary, h>>)
@doc """
Encodes the given cookies as expected in a response header.
"""
def encode(key, opts \\ %{}) when is_map(opts) do
value = Map.get(opts, :value)
path = Map.get(opts, :path, "/")
IO.iodata_to_binary([
"#{key}=#{value}; path=#{path}",
emit_if(opts[:domain], &["; domain=", &1]),
emit_if(opts[:max_age], &encode_max_age(&1, opts)),
emit_if(Map.get(opts, :secure, false), "; secure"),
emit_if(Map.get(opts, :http_only, true), "; HttpOnly"),
emit_if(Map.get(opts, :same_site, nil), &encode_same_site/1),
emit_if(opts[:extra], &["; ", &1])
])
end
defp encode_max_age(max_age, opts) do
time = Map.get(opts, :universal_time) || :calendar.universal_time()
time = add_seconds(time, max_age)
["; expires=", rfc2822(time), "; max-age=", Integer.to_string(max_age)]
end
defp encode_same_site(value) when is_binary(value), do: "; SameSite=#{value}"
defp emit_if(value, fun_or_string) do
cond do
!value ->
[]
is_function(fun_or_string) ->
fun_or_string.(value)
is_binary(fun_or_string) ->
fun_or_string
end
end
defp pad(number) when number in 0..9, do: <<?0, ?0 + number>>
defp pad(number), do: Integer.to_string(number)
defp rfc2822({{year, month, day} = date, {hour, minute, second}}) do
# Sat, 17 Apr 2010 14:00:00 GMT
[
weekday_name(:calendar.day_of_the_week(date)),
?,,
?\s,
pad(day),
?\s,
month_name(month),
?\s,
Integer.to_string(year),
?\s,
pad(hour),
?:,
pad(minute),
?:,
pad(second),
" GMT"
]
end
defp weekday_name(1), do: "Mon"
defp weekday_name(2), do: "Tue"
defp weekday_name(3), do: "Wed"
defp weekday_name(4), do: "Thu"
defp weekday_name(5), do: "Fri"
defp weekday_name(6), do: "Sat"
defp weekday_name(7), do: "Sun"
defp month_name(1), do: "Jan"
defp month_name(2), do: "Feb"
defp month_name(3), do: "Mar"
defp month_name(4), do: "Apr"
defp month_name(5), do: "May"
defp month_name(6), do: "Jun"
defp month_name(7), do: "Jul"
defp month_name(8), do: "Aug"
defp month_name(9), do: "Sep"
defp month_name(10), do: "Oct"
defp month_name(11), do: "Nov"
defp month_name(12), do: "Dec"
defp add_seconds(time, seconds_to_add) do
time_seconds = :calendar.datetime_to_gregorian_seconds(time)
:calendar.gregorian_seconds_to_datetime(time_seconds + seconds_to_add)
end
end