Select matching tuple in list, best method? (Plug.Conn.req_headers)

Hi,

I have a list of tuples, returned by Plug.Conn.req_headers and I want to find the tuple {"x-forwarded-for", ip}

An example tuple list:

req_headers: [{"host", "localhost:8443"}, 
{"content-type", "application/x-www-form-urlencoded; charset=UTF-8"}, 
{"origin", "http://example.com"}, 
{"accept-encoding", "gzip, deflate"}, {"accept", "*/*"}, 
{"user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/601.6.17 
    (KHTML, like Gecko) Version/9.1.1 Safari/601.6.17"}, 
{"referer", "http://example.com/"}, {"accept-language", "en-us"}, 
{"x-requested-with", "XMLHttpRequest"}, {"x-forwarded-for", "1.2.3.4"}, 
{"x-forwarded-host", "example.com"}, {"x-forwarded-server", "example.com"}, 
{"connection", "Keep-Alive"}, {"content-length", "4"}]

I managed to get it working with

{_, ip} = Enum.find(headers, fn({k, v}) -> k == "host" end)

However, that seems a bit cumbersome. Is there a more elixir-y way to perform the same task?

Thanks!

2 Likes

What about List.keyfind/3 ?

{_, ip} = List.keyfind(req_headers, "x-forwarded-for", 0)
3 Likes

Ah, that’s definitely it. Thanks!

Edit: It fails when the key can’t be found, since {_, ip} doesn’t match to 0. However it seems that I can’t use {0, 0} as a default for List.keyfind/3. Any ideas?

1 Like

How about Plug.Conn.get_req_header/2?

Here’s the underlying implementation:

    for {k, v} <- headers, k == key, do: v
  end```
6 Likes

Plug.Conn.get_req_header/2 is the right answer. Keep in mind that headers can be set with multiple values, so this will return a list.

4 Likes