Convert to keyword list

Hi all

I have a list with following values:

[{"host", "localhost:4000"}, {"connection", "keep-alive"},
 {"pragma", "no-cache"}, {"cache-control", "no-cache"},
 {"accept", "application/xml"}, {"sap-contextid-accept", "header"},
 {"accept-language", "en-US"}, {"maxdataserviceversion", "3.0"},
 {"user-agent",
  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"},
 {"referer", "http://localhost:4000/ui5"},
 {"accept-encoding", "gzip, deflate, sdch, br"}]

and I want to convert it to keyword list and tried as follow:

iex(4)> Enum.reduce(test, [], fn ({key, value},acc) -> [key: value] ++ acc end)
[key: "gzip, deflate, sdch, br", key: "http://localhost:4000/ui5",
 key: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36",
 key: "3.0", key: "en-US", key: "header", key: "application/xml",
 key: "no-cache", key: "no-cache", key: "keep-alive", key: "localhost:4000"]

Key should be a binary not Key.

How can I solve the problem?

Thanks

1 Like
list =[{"host", "localhost:4000"}, {"connection", "keep-alive"},
 {"pragma", "no-cache"}, {"cache-control", "no-cache"},
 {"accept", "application/xml"}, {"sap-contextid-accept", "header"},
 {"accept-language", "en-US"}, {"maxdataserviceversion", "3.0"},
 {"user-agent",
  "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"},
 {"referer", "http://localhost:4000/ui5"},
 {"accept-encoding", "gzip, deflate, sdch, br"}]

for {key, value} <- list, do: {String.to_atom(key), value}

Note that keys like "accept-encoding" will be represented as :"accept-encoding" as atoms and not :accept-encoding as you might expect.

Or if you want to use Enum.reduce:

Enum.reduce(list, [], fn {key, value}, acc ->  [{String.to_atom(key), value} | acc] end)

But the order of the keyword list will be reversed if you use Enum.reduce because you add the new values to the head of the list.

3 Likes

Or you can use this an preserve order
Enum.map(list, fn {key, value} -> {:"#{key}", value} end)

4 Likes

This looks like a list of headers. Keep in mind that if this is a list of headers from a client, converting the keys to atoms provides an attack vector on your system. A malicious user could send you arbitrary headers until your system ran out of RAM.

6 Likes

Also keep in mind the atoms are limited, an attacker can provide a random header list that will cause a crash.

iex(1)> Enum.each 1..2_000_000, fn(x) -> :"test_atom_#{x}" end
no more index entries in atom_tab (max=1048576)
Crash dump is being written to: erl_crash.dump...done

I don’t know why you want to transform header names to atoms :slight_smile:
You can access that information using List for example:

List.keyfind(list, "host", 0)
{"host", "localhost:4000"}
9 Likes