Page MenuHomePhorge

No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/remote_ip/headers/forwarded.ex b/lib/remote_ip/headers/forwarded.ex
index 263362a..1fc3fbb 100644
--- a/lib/remote_ip/headers/forwarded.ex
+++ b/lib/remote_ip/headers/forwarded.ex
@@ -1,166 +1,166 @@
defmodule RemoteIp.Headers.Forwarded do
@moduledoc """
[RFC 7239](https://tools.ietf.org/html/rfc7239) compliant parser for
`Forwarded` headers.
"""
use Combine
@doc """
Given a `Forwarded` header's string value, parses out IP addresses from the
`for=` parameter.
## Examples
iex> RemoteIp.Headers.Forwarded.parse("for=1.2.3.4;by=2.3.4.5")
[{1, 2, 3, 4}]
iex> RemoteIp.Headers.Forwarded.parse("for=\\"[::1]\\", for=\\"[::2]\\"")
[{0, 0, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 2}]
iex> RemoteIp.Headers.Forwarded.parse("invalid")
[]
"""
@type header :: String.t
@type ip :: :inet.ip_address
@spec parse(header) :: [ip]
def parse(header) when is_binary(header) do
case Combine.parse(header, forwarded()) do
[elements] -> Enum.flat_map(elements, &parse_forwarded_for/1)
_ -> []
end
end
defp parse_forwarded_for(pairs) do
case pairs |> fors do
[string] -> parse_ip(string)
_ -> [] # no `for=`s or multiple `for=`s
end
end
defp fors(pairs) do
for {key, val} <- pairs, String.downcase(key) == "for", do: val
end
defp parse_ip(string) do
case Combine.parse(string, ip_address()) do
[ip] -> [ip]
_ -> []
end
end
# https://tools.ietf.org/html/rfc7239#section-4
defp forwarded do
sep_by(forwarded_element(), comma()) |> eof
end
defp forwarded_element do
sep_by1(forwarded_pair(), char(";"))
end
defp forwarded_pair do
pair = [token(), ignore(char("=")), value()]
pipe(pair, &List.to_tuple/1)
end
defp value do
either(token(), quoted_string())
end
# https://tools.ietf.org/html/rfc7230#section-3.2.6
defp token do
word_of(~r/[!#$%&'*+\-.^_`|~0-9a-zA-Z]/)
end
defp quoted_string do
quoted(string_of(either(qdtext(), quoted_pair())))
end
defp quoted(parser) do
between(char("\""), parser, char("\""))
end
defp string_of(parser) do
map(many(parser), &Enum.join/1)
end
defp qdtext do
word_of(~r/[\t \x21\x23-\x5B\x5D-\x7E\x80-\xFF]/)
end
@quotable [?\t]
++ Enum.to_list(0x21..0x7E)
++ Enum.to_list(0x80..0xFF)
|> Enum.map(&<<&1::utf8>>)
defp quoted_pair do
ignore(char("\\")) |> one_of(char(), @quotable)
end
# https://tools.ietf.org/html/rfc7230#section-7
defp comma do
skip(many(either(space(), tab())))
|> char(",")
|> skip(many(either(space(), tab())))
end
# https://tools.ietf.org/html/rfc7239#section-6
defp ip_address do
node_name()
|> ignore(option(ignore(char(":")) |> node_port))
|> eof
end
defp node_name do
choice [
ipv4_address(),
between(char("["), ipv6_address(), char("]")),
ignore(string("unknown")),
ignore(obfuscated()),
]
end
defp node_port(previous) do
previous |> either(port(), obfuscated())
end
defp port do
# Have to try to parse the wider integers first due to greediness. For
# example, the port "12345" would be matched by fixed_integer(1) and the
# remaining "2345" would cause a parse error for the eof in ip_address/0.
choice(Enum.map(5..1, &fixed_integer/1))
end
defp obfuscated do
word_of(~r/^_[a-zA-Z0-9._\-]+/)
end
# Could follow the ABNF described in
# https://tools.ietf.org/html/rfc3986#section-3.2.2, but prefer to lean on
# the existing :inet parser - we want its output anyway.
defp ipv4_address do
map(word_of(~r/[0-9.]/), fn string ->
- case :inet.parse_ipv4strict_address(string |> to_char_list) do
+ case :inet.parse_ipv4strict_address(string |> to_charlist) do
{:ok, ip} -> ip
{:error, :einval} -> {:error, "Invalid IPv4 address"}
end
end)
end
defp ipv6_address do
map(word_of(~r/[0-9a-f:.]/i), fn string ->
- case :inet.parse_ipv6strict_address(string |> to_char_list) do
+ case :inet.parse_ipv6strict_address(string |> to_charlist) do
{:ok, ip} -> ip
{:error, :einval} -> {:error, "Invalid IPv6 address"}
end
end)
end
end
diff --git a/lib/remote_ip/headers/generic.ex b/lib/remote_ip/headers/generic.ex
index 1431aeb..641b80b 100644
--- a/lib/remote_ip/headers/generic.ex
+++ b/lib/remote_ip/headers/generic.ex
@@ -1,55 +1,55 @@
defmodule RemoteIp.Headers.Generic do
@moduledoc """
Generic parser for forwarding headers.
When there is no other special `RemoteIp.Headers.*` parser submodule,
`RemoteIp.Headers.parse/2` will use this module to parse the header value.
So, `RemoteIp.Headers.Generic` is used to parse `X-Forwarded-For`,
`X-Real-IP`, `X-Client-IP`, and generally unrecognized headers.
"""
@doc """
Parses a comma-separated list of IPs.
Any amount of whitespace is allowed before and after the commas, as well as
at the beginning/end of the input.
## Examples
iex> RemoteIp.Headers.Generic.parse("1.2.3.4, 5.6.7.8")
[{1, 2, 3, 4}, {5, 6, 7, 8}]
iex> RemoteIp.Headers.Generic.parse(" ::1 ")
[{0, 0, 0, 0, 0, 0, 0, 1}]
iex> RemoteIp.Headers.Generic.parse("invalid")
[]
"""
@type header :: String.t
@type ip :: :inet.ip_address
@spec parse(header) :: [ip]
def parse(header) when is_binary(header) do
header
|> split_commas
|> parse_ips
end
defp split_commas(header) do
header |> String.trim |> String.split(~r/\s*,\s*/)
end
defp parse_ips(strings) do
Enum.reduce(strings, [], fn string, ips ->
case parse_ip(string) do
{:ok, ip} -> [ip | ips]
{:error, :einval} -> ips
end
end) |> Enum.reverse
end
defp parse_ip(string) do
- string |> to_char_list |> :inet.parse_strict_address
+ string |> to_charlist |> :inet.parse_strict_address
end
end
diff --git a/mix.lock b/mix.lock
index 0b25b1e..b392e9a 100644
--- a/mix.lock
+++ b/mix.lock
@@ -1,6 +1,6 @@
-%{"combine": {:hex, :combine, "0.9.2", "cd3c8721f378ebe032487d8a4fa2ced3181a456a3c21b16464da8c46904bb552", [:mix], []},
+%{"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.0.2", "a0b0904d74ecc14da8bd2e6e0248e1a409a2bc91aade75fcf428125603de3853", [:mix], []},
"ex_doc": {:hex, :ex_doc, "0.14.3", "e61cec6cf9731d7d23d254266ab06ac1decbb7651c3d1568402ec535d387b6f7", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
"inet_cidr": {:hex, :inet_cidr, "1.0.1", "9038d0598eb2f7f4b4347c566b773c79e10edfb038633de9f55d538ba2703ac3", [:mix], []},
"mime": {:hex, :mime, "1.0.1", "05c393850524767d13a53627df71beeebb016205eb43bfbd92d14d24ec7a1b51", [:mix], []},
"plug": {:hex, :plug, "1.2.2", "cfbda521b54c92ab8ddffb173fbaabed8d8fc94bec07cd9bb58a84c1c501b0bd", [:mix], [{:cowboy, "~> 1.0", [hex: :cowboy, optional: true]}, {:mime, "~> 1.0", [hex: :mime, optional: false]}]}}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 1:54 PM (1 d, 13 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39812
Default Alt Text
(7 KB)

Event Timeline