Skip to content

Commit 746b312

Browse files
authored
Optimize cookie parsing (#1310)
Use length tracking and binary_part/3 instead of repeated binary concatenation to avoid allocating new binaries during decoding.
1 parent 041bb1b commit 746b312

1 file changed

Lines changed: 29 additions & 20 deletions

File tree

lib/plug/conn/cookies.ex

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -49,40 +49,49 @@ defmodule Plug.Conn.Cookies do
4949

5050
defp decode_kv("", acc), do: acc
5151
defp decode_kv(<<h, t::binary>>, acc) when h in [?\s, ?\t], do: decode_kv(t, acc)
52-
defp decode_kv(kv, acc) when is_binary(kv), do: decode_key(kv, "", acc)
52+
defp decode_kv(kv, acc) when is_binary(kv), do: decode_key(kv, kv, 0, acc)
5353

54-
defp decode_key(<<h, t::binary>>, _key, acc) when h in [?\s, ?\t, ?\r, ?\n, ?\v, ?\f],
55-
do: skip_until_cc(t, acc)
54+
defp decode_key(<<h, t::binary>>, _key_rest, _len, acc)
55+
when h in [?\s, ?\t, ?\r, ?\n, ?\v, ?\f],
56+
do: skip_until_cc(t, acc)
5657

57-
defp decode_key(<<?;, t::binary>>, _key, acc), do: decode_kv(t, acc)
58-
defp decode_key(<<?=, t::binary>>, "", acc), do: skip_until_cc(t, acc)
59-
defp decode_key(<<?=, t::binary>>, key, acc), do: decode_value(t, "", 0, key, acc)
60-
defp decode_key(<<h, t::binary>>, key, acc), do: decode_key(t, <<key::binary, h>>, acc)
61-
defp decode_key(<<>>, _key, acc), do: acc
58+
defp decode_key(<<?;, t::binary>>, _key_rest, _len, acc), do: decode_kv(t, acc)
59+
defp decode_key(<<?=, t::binary>>, _key_rest, 0, acc), do: skip_until_cc(t, acc)
6260

63-
defp decode_value(<<?;, t::binary>>, value, spaces, key, acc),
64-
do: decode_kv(t, [{key, trim_spaces(value, spaces)} | acc])
61+
defp decode_key(<<?=, t::binary>>, key_rest, len, acc) do
62+
key = binary_part(key_rest, 0, len)
63+
decode_value(t, t, 0, 0, key, acc)
64+
end
6565

66-
defp decode_value(<<?\s, t::binary>>, value, spaces, key, acc),
67-
do: decode_value(t, <<value::binary, ?\s>>, spaces + 1, key, acc)
66+
defp decode_key(<<_, t::binary>>, key_rest, len, acc), do: decode_key(t, key_rest, len + 1, acc)
67+
defp decode_key(<<>>, _key_rest, _len, acc), do: acc
6868

69-
defp decode_value(<<h, t::binary>>, _value, _spaces, _key, acc)
69+
defp decode_value(<<?;, t::binary>>, val_rest, len, spaces, key, acc) do
70+
value = binary_part(val_rest, 0, len - spaces)
71+
decode_kv(t, [{key, value} | acc])
72+
end
73+
74+
defp decode_value(<<?\s, t::binary>>, val_rest, len, spaces, key, acc) do
75+
decode_value(t, val_rest, len + 1, spaces + 1, key, acc)
76+
end
77+
78+
defp decode_value(<<h, t::binary>>, _val_rest, _len, _spaces, _key, acc)
7079
when h in [?\t, ?\r, ?\n, ?\v, ?\f],
7180
do: skip_until_cc(t, acc)
7281

73-
defp decode_value(<<h, t::binary>>, value, _spaces, key, acc),
74-
do: decode_value(t, <<value::binary, h>>, 0, key, acc)
82+
defp decode_value(<<_, t::binary>>, val_rest, len, _spaces, key, acc) do
83+
decode_value(t, val_rest, len + 1, 0, key, acc)
84+
end
7585

76-
defp decode_value(<<>>, value, spaces, key, acc),
77-
do: [{key, trim_spaces(value, spaces)} | acc]
86+
defp decode_value(<<>>, val_rest, len, spaces, key, acc) do
87+
value = binary_part(val_rest, 0, len - spaces)
88+
[{key, value} | acc]
89+
end
7890

7991
defp skip_until_cc(<<?;, t::binary>>, acc), do: decode_kv(t, acc)
8092
defp skip_until_cc(<<_, t::binary>>, acc), do: skip_until_cc(t, acc)
8193
defp skip_until_cc(<<>>, acc), do: acc
8294

83-
defp trim_spaces(value, 0), do: value
84-
defp trim_spaces(value, spaces), do: binary_part(value, 0, byte_size(value) - spaces)
85-
8695
@doc """
8796
Encodes the given cookies as expected in a response header.
8897

0 commit comments

Comments
 (0)