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

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.

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

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.

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"}