Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F116040
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
98 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/remote_ip.ex b/lib/remote_ip.ex
index acfb68b..c03482c 100644
--- a/lib/remote_ip.ex
+++ b/lib/remote_ip.ex
@@ -1,75 +1,64 @@
defmodule RemoteIp do
@behaviour Plug
@headers ~w[
forwarded
x-forwarded-for
]
# x-client-ip
# x-real-ip
# etc
@proxies []
# https://en.wikipedia.org/wiki/Loopback
# https://en.wikipedia.org/wiki/Private_network
@reserved ~w[
127.0.0.0/8
::1/128
fc00::/7
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
]
def init(opts \\ []) do
headers = Keyword.get(opts, :headers, @headers)
+ headers = MapSet.new(headers)
proxies = Keyword.get(opts, :proxies, @proxies) ++ @reserved
proxies = proxies |> Enum.map(&InetCidr.parse/1)
{headers, proxies}
end
- def call(conn, {[], _proxies}) do
- conn
- end
-
- def call(conn, {[header | next_headers], proxies}) when is_binary(header) do
- case last_forwarded_ip(conn, header, proxies) do
- nil -> call(conn, {next_headers, proxies})
+ def call(conn, {headers, proxies}) do
+ case last_forwarded_ip(conn, headers, proxies) do
+ nil -> conn
ip -> %{conn | remote_ip: ip}
end
end
- defp last_forwarded_ip(conn, header, proxies) do
+ defp last_forwarded_ip(conn, headers, proxies) do
conn
- |> ips_from(header)
+ |> ips_from(headers)
|> last_ip_forwarded_through(proxies)
end
+ defp ips_from(%Plug.Conn{req_headers: headers}, allowed) do
+ RemoteIp.Headers.parse(headers, allowed)
+ end
+
defp last_ip_forwarded_through(ips, proxies) do
ips
|> Enum.reverse
|> Enum.find(&forwarded?(&1, proxies))
end
defp forwarded?(ip, proxies) do
!proxy?(ip, proxies)
end
defp proxy?(ip, proxies) do
Enum.any?(proxies, fn proxy -> InetCidr.contains?(proxy, ip) end)
end
-
- defp ips_from(conn, "forwarded" = header) do
- conn
- |> Plug.Conn.get_req_header(header)
- |> RemoteIp.Headers.Forwarded.parse
- end
-
- defp ips_from(conn, header) when is_binary(header) do
- conn
- |> Plug.Conn.get_req_header(header)
- |> RemoteIp.Headers.Generic.parse
- end
end
diff --git a/lib/remote_ip/headers.ex b/lib/remote_ip/headers.ex
new file mode 100644
index 0000000..169fc41
--- /dev/null
+++ b/lib/remote_ip/headers.ex
@@ -0,0 +1,23 @@
+defmodule RemoteIp.Headers do
+ def parse(headers, %MapSet{} = allowed) when is_list(headers) do
+ headers
+ |> allow(allowed)
+ |> parse_each
+ end
+
+ defp allow(headers, allowed) do
+ Enum.filter(headers, fn {header, _} -> MapSet.member?(allowed, header) end)
+ end
+
+ defp parse_each(headers) do
+ Enum.flat_map(headers, &parse_ips/1)
+ end
+
+ defp parse_ips({"forwarded", value}) when is_binary(value) do
+ RemoteIp.Headers.Forwarded.parse(value)
+ end
+
+ defp parse_ips({header, value}) when is_binary(header) and is_binary(value) do
+ RemoteIp.Headers.Generic.parse(value)
+ end
+end
diff --git a/lib/remote_ip/headers/forwarded.ex b/lib/remote_ip/headers/forwarded.ex
index 6d9e8e3..106521f 100644
--- a/lib/remote_ip/headers/forwarded.ex
+++ b/lib/remote_ip/headers/forwarded.ex
@@ -1,143 +1,141 @@
defmodule RemoteIp.Headers.Forwarded do
use Combine
- def parse(headers) when is_list(headers) do
- Enum.flat_map(headers, fn header ->
- case Combine.parse(header, forwarded) do
- [elements] -> Enum.flat_map(elements, &parse_forwarded_for/1)
- _ -> []
- end
- end)
+ 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
{: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
{: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 925fbe6..9b5879c 100644
--- a/lib/remote_ip/headers/generic.ex
+++ b/lib/remote_ip/headers/generic.ex
@@ -1,26 +1,24 @@
defmodule RemoteIp.Headers.Generic do
- def parse(headers) when is_list(headers) do
- headers
+ def parse(header) when is_binary(header) do
+ header
|> split_commas
|> parse_ips
end
- defp split_commas(headers) do
- Enum.flat_map(headers, fn header ->
- header |> String.trim |> String.split(~r/\s*,\s*/)
- 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
end
end
diff --git a/test/remote_ip/headers/forwarded_test.exs b/test/remote_ip/headers/forwarded_test.exs
index 7c896b2..6191e60 100644
--- a/test/remote_ip/headers/forwarded_test.exs
+++ b/test/remote_ip/headers/forwarded_test.exs
@@ -1,395 +1,360 @@
defmodule RemoteIp.Headers.ForwardedTest do
use ExUnit.Case, async: true
alias RemoteIp.Headers.Forwarded
describe "parsing" do
test "RFC 7239 examples" do
- parsed = Forwarded.parse([~S'for="_gazonk"'])
+ parsed = Forwarded.parse(~S'for="_gazonk"')
assert parsed == []
- parsed = Forwarded.parse([~S'For="[2001:db8:cafe::17]:4711"'])
+ parsed = Forwarded.parse(~S'For="[2001:db8:cafe::17]:4711"')
assert parsed == [{8193, 3512, 51966, 0, 0, 0, 0, 23}]
- parsed = Forwarded.parse([~S'for=192.0.2.60;proto=http;by=203.0.113.43'])
+ parsed = Forwarded.parse(~S'for=192.0.2.60;proto=http;by=203.0.113.43')
assert parsed == [{192, 0, 2, 60}]
- parsed = Forwarded.parse([~S'for=192.0.2.43, for=198.51.100.17'])
+ parsed = Forwarded.parse(~S'for=192.0.2.43, for=198.51.100.17')
assert parsed == [{192, 0, 2, 43}, {198, 51, 100, 17}]
end
- test "an empty list of headers" do
- assert [] == Forwarded.parse([])
- end
-
test "case insensitivity" do
- assert [{0, 0, 0, 0}] == Forwarded.parse([~S'for=0.0.0.0'])
- assert [{0, 0, 0, 0}] == Forwarded.parse([~S'foR=0.0.0.0'])
- assert [{0, 0, 0, 0}] == Forwarded.parse([~S'fOr=0.0.0.0'])
- assert [{0, 0, 0, 0}] == Forwarded.parse([~S'fOR=0.0.0.0'])
- assert [{0, 0, 0, 0}] == Forwarded.parse([~S'For=0.0.0.0'])
- assert [{0, 0, 0, 0}] == Forwarded.parse([~S'FoR=0.0.0.0'])
- assert [{0, 0, 0, 0}] == Forwarded.parse([~S'FOr=0.0.0.0'])
- assert [{0, 0, 0, 0}] == Forwarded.parse([~S'FOR=0.0.0.0'])
-
- assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse([~S'for="[::]"'])
- assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse([~S'foR="[::]"'])
- assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse([~S'fOr="[::]"'])
- assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse([~S'fOR="[::]"'])
- assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse([~S'For="[::]"'])
- assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse([~S'FoR="[::]"'])
- assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse([~S'FOr="[::]"'])
- assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse([~S'FOR="[::]"'])
+ assert [{0, 0, 0, 0}] == Forwarded.parse(~S'for=0.0.0.0')
+ assert [{0, 0, 0, 0}] == Forwarded.parse(~S'foR=0.0.0.0')
+ assert [{0, 0, 0, 0}] == Forwarded.parse(~S'fOr=0.0.0.0')
+ assert [{0, 0, 0, 0}] == Forwarded.parse(~S'fOR=0.0.0.0')
+ assert [{0, 0, 0, 0}] == Forwarded.parse(~S'For=0.0.0.0')
+ assert [{0, 0, 0, 0}] == Forwarded.parse(~S'FoR=0.0.0.0')
+ assert [{0, 0, 0, 0}] == Forwarded.parse(~S'FOr=0.0.0.0')
+ assert [{0, 0, 0, 0}] == Forwarded.parse(~S'FOR=0.0.0.0')
+
+ assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse(~S'for="[::]"')
+ assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse(~S'foR="[::]"')
+ assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse(~S'fOr="[::]"')
+ assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse(~S'fOR="[::]"')
+ assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse(~S'For="[::]"')
+ assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse(~S'FoR="[::]"')
+ assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse(~S'FOr="[::]"')
+ assert [{0, 0, 0, 0, 0, 0, 0, 0}] == Forwarded.parse(~S'FOR="[::]"')
end
test "IPv4" do
- assert [] == Forwarded.parse([~S'for='])
- assert [] == Forwarded.parse([~S'for=1'])
- assert [] == Forwarded.parse([~S'for=1.2'])
- assert [] == Forwarded.parse([~S'for=1.2.3'])
- assert [] == Forwarded.parse([~S'for=1000.2.3.4'])
- assert [] == Forwarded.parse([~S'for=1.2000.3.4'])
- assert [] == Forwarded.parse([~S'for=1.2.3000.4'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4000'])
- assert [] == Forwarded.parse([~S'for=1abc.2.3.4'])
- assert [] == Forwarded.parse([~S'for=1.2abc.3.4'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4abc'])
- assert [] == Forwarded.parse([~S'for=1.2.3abc.4'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4abc'])
- assert [] == Forwarded.parse([~S'for="1.2.3.4'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4"'])
-
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for=1.2.3.4'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="1.2.3.4"'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="\1.2\.3.\4"'])
+ assert [] == Forwarded.parse(~S'for=')
+ assert [] == Forwarded.parse(~S'for=1')
+ assert [] == Forwarded.parse(~S'for=1.2')
+ assert [] == Forwarded.parse(~S'for=1.2.3')
+ assert [] == Forwarded.parse(~S'for=1000.2.3.4')
+ assert [] == Forwarded.parse(~S'for=1.2000.3.4')
+ assert [] == Forwarded.parse(~S'for=1.2.3000.4')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4000')
+ assert [] == Forwarded.parse(~S'for=1abc.2.3.4')
+ assert [] == Forwarded.parse(~S'for=1.2abc.3.4')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4abc')
+ assert [] == Forwarded.parse(~S'for=1.2.3abc.4')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4abc')
+ assert [] == Forwarded.parse(~S'for="1.2.3.4')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4"')
+
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for=1.2.3.4')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="1.2.3.4"')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="\1.2\.3.\4"')
end
test "IPv4 with port" do
- assert [] == Forwarded.parse([~S'for=1.2.3.4:'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4:1'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4:12'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4:123'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4:1234'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4:12345'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4:123456'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4:_underscore'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4:no_underscore'])
-
- assert [] == Forwarded.parse([~S'for="1.2.3.4:"'])
- assert [] == Forwarded.parse([~S'for="1.2.3.4:123456"'])
- assert [] == Forwarded.parse([~S'for="1.2.3.4:no_underscore"'])
- assert [] == Forwarded.parse([~S'for="1.2\.3.4\:no_un\der\score"'])
-
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="1.2.3.4:1"'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="1.2.3.4:12"'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="1.2.3.4:123"'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="1.2.3.4:1234"'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="1.2.3.4:12345"'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="1.2.3.4:_underscore"'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for="\1.2\.3.4\:_po\r\t"'])
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:1')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:12')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:123')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:1234')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:12345')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:123456')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:_underscore')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4:no_underscore')
+
+ assert [] == Forwarded.parse(~S'for="1.2.3.4:"')
+ assert [] == Forwarded.parse(~S'for="1.2.3.4:123456"')
+ assert [] == Forwarded.parse(~S'for="1.2.3.4:no_underscore"')
+ assert [] == Forwarded.parse(~S'for="1.2\.3.4\:no_un\der\score"')
+
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="1.2.3.4:1"')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="1.2.3.4:12"')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="1.2.3.4:123"')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="1.2.3.4:1234"')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="1.2.3.4:12345"')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="1.2.3.4:_underscore"')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for="\1.2\.3.4\:_po\r\t"')
end
test "improperly formatted IPv6" do
- assert [] == Forwarded.parse([~S'for=[127.0.0.1]'])
- assert [] == Forwarded.parse([~S'for="[127.0.0.1]"'])
-
- assert [] == Forwarded.parse([~S'for=::127.0.0.1'])
- assert [] == Forwarded.parse([~S'for=[::127.0.0.1]'])
- assert [] == Forwarded.parse([~S'for="::127.0.0.1"'])
- assert [] == Forwarded.parse([~S'for="[::127.0.0.1"'])
- assert [] == Forwarded.parse([~S'for="::127.0.0.1]"'])
-
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8"'])
- assert [] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8"'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8]"'])
+ assert [] == Forwarded.parse(~S'for=[127.0.0.1]')
+ assert [] == Forwarded.parse(~S'for="[127.0.0.1]"')
+
+ assert [] == Forwarded.parse(~S'for=::127.0.0.1')
+ assert [] == Forwarded.parse(~S'for=[::127.0.0.1]')
+ assert [] == Forwarded.parse(~S'for="::127.0.0.1"')
+ assert [] == Forwarded.parse(~S'for="[::127.0.0.1"')
+ assert [] == Forwarded.parse(~S'for="::127.0.0.1]"')
+
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8"')
+ assert [] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8"')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8]"')
end
test "IPv6 with port" do
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:'])
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:1'])
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:12'])
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:123'])
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:1234'])
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:12345'])
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:123456'])
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:_underscore'])
- assert [] == Forwarded.parse([~S'for=::1.2.3.4:no_underscore'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:1'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:12'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:123'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:1234'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:12345'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:123456'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:_underscore'])
- assert [] == Forwarded.parse([~S'for=[::1.2.3.4]:no_underscore'])
-
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:"'])
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:123456"'])
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:no_underscore"'])
- assert [] == Forwarded.parse([~S'for="::1.2\.3.4\:no_un\der\score"'])
- assert [] == Forwarded.parse([~S'for="[::1.2.3.4]:"'])
- assert [] == Forwarded.parse([~S'for="[::1.2.3.4]:123456"'])
- assert [] == Forwarded.parse([~S'for="[::1.2.3.4]:no_underscore"'])
- assert [] == Forwarded.parse([~S'for="\[::1.2\.3.4]\:no_un\der\score"'])
-
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:1"'])
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:12"'])
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:123"'])
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:1234"'])
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:12345"'])
- assert [] == Forwarded.parse([~S'for="::1.2.3.4:_underscore"'])
- assert [] == Forwarded.parse([~S'for="::\1.2\.3.4\:_po\r\t"'])
-
- assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse([~S'for="[::1.2.3.4]:1"'])
- assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse([~S'for="[::1.2.3.4]:12"'])
- assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse([~S'for="[::1.2.3.4]:123"'])
- assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse([~S'for="[::1.2.3.4]:1234"'])
- assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse([~S'for="[::1.2.3.4]:12345"'])
- assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse([~S'for="[::1.2.3.4]:_underscore"'])
- assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse([~S'for="[::\1.2\.3.4\]\:_po\r\t"'])
-
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:'])
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:1'])
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:12'])
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:123'])
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:1234'])
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:12345'])
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:123456'])
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:_underscore'])
- assert [] == Forwarded.parse([~S'for=1:2:3:4:5:6:7:8:no_underscore'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:1'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:12'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:123'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:1234'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:12345'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:123456'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:_underscore'])
- assert [] == Forwarded.parse([~S'for=[1:2:3:4:5:6:7:8]:no_underscore'])
-
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:"'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:123456"'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:no_underscore"'])
- assert [] == Forwarded.parse([~S'for="::1.2\.3.4\:no_un\der\score"'])
- assert [] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:"'])
- assert [] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:123456"'])
- assert [] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:no_underscore"'])
- assert [] == Forwarded.parse([~S'for="\[1:2\:3:4:5:6:7:8]\:no_un\der\score"'])
-
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:1"'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:12"'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:123"'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:1234"'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:12345"'])
- assert [] == Forwarded.parse([~S'for="1:2:3:4:5:6:7:8:_underscore"'])
- assert [] == Forwarded.parse([~S'for="\1:2\:3:4:5:6:7:8\:_po\r\t"'])
-
- assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:1"'])
- assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:12"'])
- assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:123"'])
- assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:1234"'])
- assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:12345"'])
- assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse([~S'for="[1:2:3:4:5:6:7:8]:_underscore"'])
- assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse([~S'for="[1:2:3:4:\5:6\:7:8\]\:_po\r\t"'])
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:')
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:1')
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:12')
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:123')
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:1234')
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:12345')
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:123456')
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:_underscore')
+ assert [] == Forwarded.parse(~S'for=::1.2.3.4:no_underscore')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:1')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:12')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:123')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:1234')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:12345')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:123456')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:_underscore')
+ assert [] == Forwarded.parse(~S'for=[::1.2.3.4]:no_underscore')
+
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:"')
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:123456"')
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:no_underscore"')
+ assert [] == Forwarded.parse(~S'for="::1.2\.3.4\:no_un\der\score"')
+ assert [] == Forwarded.parse(~S'for="[::1.2.3.4]:"')
+ assert [] == Forwarded.parse(~S'for="[::1.2.3.4]:123456"')
+ assert [] == Forwarded.parse(~S'for="[::1.2.3.4]:no_underscore"')
+ assert [] == Forwarded.parse(~S'for="\[::1.2\.3.4]\:no_un\der\score"')
+
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:1"')
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:12"')
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:123"')
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:1234"')
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:12345"')
+ assert [] == Forwarded.parse(~S'for="::1.2.3.4:_underscore"')
+ assert [] == Forwarded.parse(~S'for="::\1.2\.3.4\:_po\r\t"')
+
+ assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse(~S'for="[::1.2.3.4]:1"')
+ assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse(~S'for="[::1.2.3.4]:12"')
+ assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse(~S'for="[::1.2.3.4]:123"')
+ assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse(~S'for="[::1.2.3.4]:1234"')
+ assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse(~S'for="[::1.2.3.4]:12345"')
+ assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse(~S'for="[::1.2.3.4]:_underscore"')
+ assert [{0, 0, 0, 0, 0, 0, 258, 772}] == Forwarded.parse(~S'for="[::\1.2\.3.4\]\:_po\r\t"')
+
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:')
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:1')
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:12')
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:123')
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:1234')
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:12345')
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:123456')
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:_underscore')
+ assert [] == Forwarded.parse(~S'for=1:2:3:4:5:6:7:8:no_underscore')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:1')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:12')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:123')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:1234')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:12345')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:123456')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:_underscore')
+ assert [] == Forwarded.parse(~S'for=[1:2:3:4:5:6:7:8]:no_underscore')
+
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:"')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:123456"')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:no_underscore"')
+ assert [] == Forwarded.parse(~S'for="::1.2\.3.4\:no_un\der\score"')
+ assert [] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:"')
+ assert [] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:123456"')
+ assert [] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:no_underscore"')
+ assert [] == Forwarded.parse(~S'for="\[1:2\:3:4:5:6:7:8]\:no_un\der\score"')
+
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:1"')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:12"')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:123"')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:1234"')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:12345"')
+ assert [] == Forwarded.parse(~S'for="1:2:3:4:5:6:7:8:_underscore"')
+ assert [] == Forwarded.parse(~S'for="\1:2\:3:4:5:6:7:8\:_po\r\t"')
+
+ assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:1"')
+ assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:12"')
+ assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:123"')
+ assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:1234"')
+ assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:12345"')
+ assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse(~S'for="[1:2:3:4:5:6:7:8]:_underscore"')
+ assert [{1, 2, 3, 4, 5, 6, 7, 8}] == Forwarded.parse(~S'for="[1:2:3:4:\5:6\:7:8\]\:_po\r\t"')
end
test "IPv6 without ::" do
- assert [{0x0001, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456:7890:a:bc:def:d34d]"'])
- assert [{0x0001, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23:456:7890:a:bc:1.2.3.4]"'])
+ assert [{0x0001, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456:7890:a:bc:def:d34d]"')
+ assert [{0x0001, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23:456:7890:a:bc:1.2.3.4]"')
end
test "IPv6 with :: at position 0" do
- assert [{0x0000, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[::23:456:7890:a:bc:def:d34d]"'])
- assert [{0x0000, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[::23:456:7890:a:bc:1.2.3.4]"'])
- assert [{0x0000, 0x0000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[::456:7890:a:bc:def:d34d]"'])
- assert [{0x0000, 0x0000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[::456:7890:a:bc:1.2.3.4]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[::7890:a:bc:def:d34d]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[::7890:a:bc:1.2.3.4]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[::a:bc:def:d34d]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[::a:bc:1.2.3.4]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[::bc:def:d34d]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[::bc:1.2.3.4]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[::def:d34d]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[::1.2.3.4]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse([~S'for="[::d34d]"'])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[::]"'])
+ assert [{0x0000, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[::23:456:7890:a:bc:def:d34d]"')
+ assert [{0x0000, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[::23:456:7890:a:bc:1.2.3.4]"')
+ assert [{0x0000, 0x0000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[::456:7890:a:bc:def:d34d]"')
+ assert [{0x0000, 0x0000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[::456:7890:a:bc:1.2.3.4]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[::7890:a:bc:def:d34d]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[::7890:a:bc:1.2.3.4]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[::a:bc:def:d34d]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[::a:bc:1.2.3.4]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[::bc:def:d34d]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[::bc:1.2.3.4]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[::def:d34d]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[::1.2.3.4]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse(~S'for="[::d34d]"')
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[::]"')
end
test "IPv6 with :: at position 1" do
- assert [{0x0001, 0x000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1::456:7890:a:bc:def:d34d]"'])
- assert [{0x0001, 0x000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1::456:7890:a:bc:1.2.3.4]"'])
- assert [{0x0001, 0x000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1::7890:a:bc:def:d34d]"'])
- assert [{0x0001, 0x000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1::7890:a:bc:1.2.3.4]"'])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1::a:bc:def:d34d]"'])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1::a:bc:1.2.3.4]"'])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1::bc:def:d34d]"'])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1::bc:1.2.3.4]"'])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1::def:d34d]"'])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1::1.2.3.4]"'])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse([~S'for="[1::d34d]"'])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[1::]"'])
+ assert [{0x0001, 0x000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1::456:7890:a:bc:def:d34d]"')
+ assert [{0x0001, 0x000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1::456:7890:a:bc:1.2.3.4]"')
+ assert [{0x0001, 0x000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1::7890:a:bc:def:d34d]"')
+ assert [{0x0001, 0x000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1::7890:a:bc:1.2.3.4]"')
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1::a:bc:def:d34d]"')
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1::a:bc:1.2.3.4]"')
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1::bc:def:d34d]"')
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1::bc:1.2.3.4]"')
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1::def:d34d]"')
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1::1.2.3.4]"')
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse(~S'for="[1::d34d]"')
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[1::]"')
end
test "IPv6 with :: at position 2" do
- assert [{0x0001, 0x023, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23::7890:a:bc:def:d34d]"'])
- assert [{0x0001, 0x023, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23::7890:a:bc:1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23::a:bc:def:d34d]"'])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23::a:bc:1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23::bc:def:d34d]"'])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23::bc:1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23::def:d34d]"'])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23::1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse([~S'for="[1:23::d34d]"'])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[1:23::]"'])
+ assert [{0x0001, 0x023, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23::7890:a:bc:def:d34d]"')
+ assert [{0x0001, 0x023, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23::7890:a:bc:1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23::a:bc:def:d34d]"')
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23::a:bc:1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23::bc:def:d34d]"')
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23::bc:1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23::def:d34d]"')
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23::1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse(~S'for="[1:23::d34d]"')
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[1:23::]"')
end
test "IPv6 with :: at position 3" do
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456::a:bc:def:d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23:456::a:bc:1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456::bc:def:d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23:456::bc:1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456::def:d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23:456::1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456::d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[1:23:456::]"'])
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456::a:bc:def:d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23:456::a:bc:1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456::bc:def:d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23:456::bc:1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456::def:d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23:456::1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456::d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[1:23:456::]"')
end
test "IPv6 with :: at position 4" do
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456:7890::bc:def:d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23:456:7890::bc:1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456:7890::def:d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23:456:7890::1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456:7890::d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[1:23:456:7890::]"'])
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456:7890::bc:def:d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x00bc, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23:456:7890::bc:1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456:7890::def:d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23:456:7890::1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456:7890::d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[1:23:456:7890::]"')
end
test "IPv6 with :: at position 5" do
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456:7890:a::def:d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0102, 0x0304}] == Forwarded.parse([~S'for="[1:23:456:7890:a::1.2.3.4]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456:7890:a::d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[1:23:456:7890:a::]"'])
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0def, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456:7890:a::def:d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0102, 0x0304}] == Forwarded.parse(~S'for="[1:23:456:7890:a::1.2.3.4]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0000, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456:7890:a::d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[1:23:456:7890:a::]"')
end
test "IPv6 with :: at position 6" do
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0000, 0xd34d}] == Forwarded.parse([~S'for="[1:23:456:7890:a:bc::d34d]"'])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[1:23:456:7890:a:bc::]"'])
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0000, 0xd34d}] == Forwarded.parse(~S'for="[1:23:456:7890:a:bc::d34d]"')
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[1:23:456:7890:a:bc::]"')
end
test "IPv6 with leading zeroes" do
- assert [{0x0000, 0x0001, 0x0002, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[0:01:002:0003:0000::]"'])
- assert [{0x000a, 0x001a, 0x002a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[0a:01a:002a::]"'])
- assert [{0x00ab, 0x01ab, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[0ab:01ab::]"'])
- assert [{0x0abc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse([~S'for="[0abc::]"'])
+ assert [{0x0000, 0x0001, 0x0002, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[0:01:002:0003:0000::]"')
+ assert [{0x000a, 0x001a, 0x002a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[0a:01a:002a::]"')
+ assert [{0x00ab, 0x01ab, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[0ab:01ab::]"')
+ assert [{0x0abc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Forwarded.parse(~S'for="[0abc::]"')
end
test "IPv6 with mixed case" do
- assert [{0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd}] == Forwarded.parse([~S'for="[abcd:abcD:abCd:abCD:aBcd:aBcD:aBCd:aBCD]"'])
- assert [{0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd}] == Forwarded.parse([~S'for="[Abcd:AbcD:AbCd:AbCD:ABcd:ABcD:ABCd:ABCD]"'])
+ assert [{0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd}] == Forwarded.parse(~S'for="[abcd:abcD:abCd:abCD:aBcd:aBcD:aBCd:aBCD]"')
+ assert [{0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd}] == Forwarded.parse(~S'for="[Abcd:AbcD:AbCd:AbCD:ABcd:ABcD:ABCd:ABCD]"')
end
test "semicolons" do
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'for=1.2.3.4;proto=http;by=2.3.4.5'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'proto=http;for=1.2.3.4;by=2.3.4.5'])
- assert [{1, 2, 3, 4}] == Forwarded.parse([~S'proto=http;by=2.3.4.5;for=1.2.3.4'])
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'for=1.2.3.4;proto=http;by=2.3.4.5')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'proto=http;for=1.2.3.4;by=2.3.4.5')
+ assert [{1, 2, 3, 4}] == Forwarded.parse(~S'proto=http;by=2.3.4.5;for=1.2.3.4')
- assert [] == Forwarded.parse([~S'for=1.2.3.4proto=http;by=2.3.4.5'])
- assert [] == Forwarded.parse([~S'proto=httpfor=1.2.3.4;by=2.3.4.5'])
- assert [] == Forwarded.parse([~S'proto=http;by=2.3.4.5for=1.2.3.4'])
+ assert [] == Forwarded.parse(~S'for=1.2.3.4proto=http;by=2.3.4.5')
+ assert [] == Forwarded.parse(~S'proto=httpfor=1.2.3.4;by=2.3.4.5')
+ assert [] == Forwarded.parse(~S'proto=http;by=2.3.4.5for=1.2.3.4')
- assert [] == Forwarded.parse([~S'for=1.2.3.4;proto=http;by=2.3.4.5;'])
- assert [] == Forwarded.parse([~S'proto=http;for=1.2.3.4;by=2.3.4.5;'])
- assert [] == Forwarded.parse([~S'proto=http;by=2.3.4.5;for=1.2.3.4;'])
+ assert [] == Forwarded.parse(~S'for=1.2.3.4;proto=http;by=2.3.4.5;')
+ assert [] == Forwarded.parse(~S'proto=http;for=1.2.3.4;by=2.3.4.5;')
+ assert [] == Forwarded.parse(~S'proto=http;by=2.3.4.5;for=1.2.3.4;')
- assert [] == Forwarded.parse([~S'for=1.2.3.4;proto=http;for=2.3.4.5'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4;for=2.3.4.5;proto=http'])
- assert [] == Forwarded.parse([~S'proto=http;for=1.2.3.4;for=2.3.4.5'])
+ assert [] == Forwarded.parse(~S'for=1.2.3.4;proto=http;for=2.3.4.5')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4;for=2.3.4.5;proto=http')
+ assert [] == Forwarded.parse(~S'proto=http;for=1.2.3.4;for=2.3.4.5')
end
test "parameters other than `for`" do
- assert [] == Forwarded.parse([~S'by=1.2.3.4'])
- assert [] == Forwarded.parse([~S'host=example.com'])
- assert [] == Forwarded.parse([~S'proto=http'])
- assert [] == Forwarded.parse([~S'by=1.2.3.4;proto=http;host=example.com'])
+ assert [] == Forwarded.parse(~S'by=1.2.3.4')
+ assert [] == Forwarded.parse(~S'host=example.com')
+ assert [] == Forwarded.parse(~S'proto=http')
+ assert [] == Forwarded.parse(~S'by=1.2.3.4;proto=http;host=example.com')
end
test "bad whitespace" do
- assert [] == Forwarded.parse([~S'for= 1.2.3.4'])
- assert [] == Forwarded.parse([~S'for = 1.2.3.4'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4; proto=http'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4 ;proto=http'])
- assert [] == Forwarded.parse([~S'for=1.2.3.4 ; proto=http'])
- assert [] == Forwarded.parse([~S'proto=http; for=1.2.3.4'])
- assert [] == Forwarded.parse([~S'proto=http ;for=1.2.3.4'])
- assert [] == Forwarded.parse([~S'proto=http ; for=1.2.3.4'])
+ assert [] == Forwarded.parse(~S'for= 1.2.3.4')
+ assert [] == Forwarded.parse(~S'for = 1.2.3.4')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4; proto=http')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4 ;proto=http')
+ assert [] == Forwarded.parse(~S'for=1.2.3.4 ; proto=http')
+ assert [] == Forwarded.parse(~S'proto=http; for=1.2.3.4')
+ assert [] == Forwarded.parse(~S'proto=http ;for=1.2.3.4')
+ assert [] == Forwarded.parse(~S'proto=http ; for=1.2.3.4')
end
test "commas" do
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse([~S'for=1.2.3.4, for=2.3.4.5'])
- assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}] == Forwarded.parse([~S'for=1.2.3.4, for="[::2:3:4:5]"'])
- assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}] == Forwarded.parse([~S'for=1.2.3.4, for="[::2:3:4:5]"'])
- assert [{0, 0, 0, 0, 1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse([~S'for="[::1:2:3:4]", for=2.3.4.5'])
- assert [{0, 0, 0, 0, 1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}] == Forwarded.parse([~S'for="[::1:2:3:4]", for="[::2:3:4:5]"'])
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(~S'for=1.2.3.4, for=2.3.4.5')
+ assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}] == Forwarded.parse(~S'for=1.2.3.4, for="[::2:3:4:5]"')
+ assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}] == Forwarded.parse(~S'for=1.2.3.4, for="[::2:3:4:5]"')
+ assert [{0, 0, 0, 0, 1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(~S'for="[::1:2:3:4]", for=2.3.4.5')
+ assert [{0, 0, 0, 0, 1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}] == Forwarded.parse(~S'for="[::1:2:3:4]", for="[::2:3:4:5]"')
end
test "optional whitespace" do
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}, {4, 5, 6, 7}, {5, 6, 7, 8}] == Forwarded.parse(["for=1.2.3.4,for=2.3.4.5,\sfor=3.4.5.6\s,for=4.5.6.7\s,\sfor=5.6.7.8"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}, {4, 5, 6, 7}, {5, 6, 7, 8}] == Forwarded.parse(["for=1.2.3.4,for=2.3.4.5,\tfor=3.4.5.6\t,for=4.5.6.7\t,\tfor=5.6.7.8"])
-
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\s\s,\s\sfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\s\s,\s\tfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\s\s,\t\sfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\s\s,\t\tfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\s\t,\s\sfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\s\t,\s\tfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\s\t,\t\sfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\s\t,\t\tfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\s,\s\sfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\s,\s\tfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\s,\t\sfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\s,\t\tfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\t,\s\sfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\t,\s\tfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\t,\t\sfor=2.3.4.5"])
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\t,\t\tfor=2.3.4.5"])
-
- assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse(["for=1.2.3.4\t\s\s\s\s\t\s\t\s\t,\t\s\s\t\tfor=2.3.4.5"])
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}, {4, 5, 6, 7}, {5, 6, 7, 8}] == Forwarded.parse("for=1.2.3.4,for=2.3.4.5,\sfor=3.4.5.6\s,for=4.5.6.7\s,\sfor=5.6.7.8")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}, {4, 5, 6, 7}, {5, 6, 7, 8}] == Forwarded.parse("for=1.2.3.4,for=2.3.4.5,\tfor=3.4.5.6\t,for=4.5.6.7\t,\tfor=5.6.7.8")
+
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\s\s,\s\sfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\s\s,\s\tfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\s\s,\t\sfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\s\s,\t\tfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\s\t,\s\sfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\s\t,\s\tfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\s\t,\t\sfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\s\t,\t\tfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\s,\s\sfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\s,\s\tfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\s,\t\sfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\s,\t\tfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\t,\s\sfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\t,\s\tfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\t,\t\sfor=2.3.4.5")
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\t,\t\tfor=2.3.4.5")
+
+ assert [{1, 2, 3, 4}, {2, 3, 4, 5}] == Forwarded.parse("for=1.2.3.4\t\s\s\s\s\t\s\t\s\t,\t\s\s\t\tfor=2.3.4.5")
end
test "commas and semicolons" do
- assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}, {3, 4, 5, 6}, {0, 0, 0, 0, 4, 5, 6, 7}] == Forwarded.parse([~S'for=1.2.3.4, for="[::2:3:4:5]";proto=http;host=example.com, proto=http;for=3.4.5.6;by=127.0.0.1, proto=http;host=example.com;for="[::4:5:6:7]"'])
- end
-
- test "multiple headers" do
- assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}, {3, 4, 5, 6}, {0, 0, 0, 0, 4, 5, 6, 7}] == Forwarded.parse([
- ~S'for=1.2.3.4',
- ~S'for="[::2:3:4:5]";proto=http;host=example.com',
- ~S'proto=http;for=3.4.5.6;by=127.0.0.1',
- ~S'proto=http;host=example.com;for="[::4:5:6:7]"',
- ])
-
- assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}, {3, 4, 5, 6}, {0, 0, 0, 0, 4, 5, 6, 7}] == Forwarded.parse([
- ~S'for=1.2.3.4, for="[::2:3:4:5]";proto=http;host=example.com',
- ~S'proto=http;for=3.4.5.6;by=127.0.0.1',
- ~S'proto=http;host=example.com;for="[::4:5:6:7]"',
- ])
-
- assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}, {3, 4, 5, 6}, {0, 0, 0, 0, 4, 5, 6, 7}] == Forwarded.parse([
- ~S'for=1.2.3.4, for="[::2:3:4:5]";proto=http;host=example.com, proto=http;for=3.4.5.6;by=127.0.0.1',
- ~S'proto=http;host=example.com;for="[::4:5:6:7]"',
- ])
-
- assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}, {3, 4, 5, 6}, {0, 0, 0, 0, 4, 5, 6, 7}] == Forwarded.parse([
- ~S'for=1.2.3.4',
- ~S'for="[::2:3:4:5]";proto=http;host=example.com',
- ~S'proto=http;for=3.4.5.6;by=127.0.0.1, proto=http;host=example.com;for="[::4:5:6:7]"',
- ])
-
- assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}, {3, 4, 5, 6}, {0, 0, 0, 0, 4, 5, 6, 7}] == Forwarded.parse([
- ~S'for=1.2.3.4',
- ~S'for="[::2:3:4:5]";proto=http;host=example.com, proto=http;for=3.4.5.6;by=127.0.0.1, proto=http;host=example.com;for="[::4:5:6:7]"',
- ])
+ assert [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}, {3, 4, 5, 6}, {0, 0, 0, 0, 4, 5, 6, 7}] == Forwarded.parse(~S'for=1.2.3.4, for="[::2:3:4:5]";proto=http;host=example.com, proto=http;for=3.4.5.6;by=127.0.0.1, proto=http;host=example.com;for="[::4:5:6:7]"')
end
end
end
diff --git a/test/remote_ip/headers/generic_test.exs b/test/remote_ip/headers/generic_test.exs
index 391fb0c..d979a99 100644
--- a/test/remote_ip/headers/generic_test.exs
+++ b/test/remote_ip/headers/generic_test.exs
@@ -1,175 +1,150 @@
defmodule RemoteIp.Headers.GenericTest do
use ExUnit.Case, async: true
alias RemoteIp.Headers.Generic
describe "parsing" do
- test "an empty list of headers" do
- assert [] == Generic.parse([])
- end
-
test "bad IPs" do
- assert [] == Generic.parse([""])
- assert [] == Generic.parse([" "])
- assert [] == Generic.parse(["not_an_ip"])
- assert [] == Generic.parse(["unknown"])
+ assert [] == Generic.parse("")
+ assert [] == Generic.parse(" ")
+ assert [] == Generic.parse("not_an_ip")
+ assert [] == Generic.parse("unknown")
end
test "bad IPv4" do
- assert [] == Generic.parse(["1"])
- assert [] == Generic.parse(["1.2"])
- assert [] == Generic.parse(["1.2.3"])
- assert [] == Generic.parse(["1000.2.3.4"])
- assert [] == Generic.parse(["1.2000.3.4"])
- assert [] == Generic.parse(["1.2.3000.4"])
- assert [] == Generic.parse(["1.2.3.4000"])
- assert [] == Generic.parse(["1abc.2.3.4"])
- assert [] == Generic.parse(["1.2abc.3.4"])
- assert [] == Generic.parse(["1.2.3.4abc"])
- assert [] == Generic.parse(["1.2.3abc.4"])
- assert [] == Generic.parse(["1.2.3.4abc"])
- assert [] == Generic.parse(["1.2.3.4.5"])
+ assert [] == Generic.parse("1")
+ assert [] == Generic.parse("1.2")
+ assert [] == Generic.parse("1.2.3")
+ assert [] == Generic.parse("1000.2.3.4")
+ assert [] == Generic.parse("1.2000.3.4")
+ assert [] == Generic.parse("1.2.3000.4")
+ assert [] == Generic.parse("1.2.3.4000")
+ assert [] == Generic.parse("1abc.2.3.4")
+ assert [] == Generic.parse("1.2abc.3.4")
+ assert [] == Generic.parse("1.2.3.4abc")
+ assert [] == Generic.parse("1.2.3abc.4")
+ assert [] == Generic.parse("1.2.3.4abc")
+ assert [] == Generic.parse("1.2.3.4.5")
end
test "bad IPv6" do
- assert [] == Generic.parse(["1:"])
- assert [] == Generic.parse(["1:2"])
- assert [] == Generic.parse(["1:2:3"])
- assert [] == Generic.parse(["1:2:3:4"])
- assert [] == Generic.parse(["1:2:3:4:5"])
- assert [] == Generic.parse(["1:2:3:4:5:6"])
- assert [] == Generic.parse(["1:2:3:4:5:6:7"])
- assert [] == Generic.parse(["1:2:3:4:5:6:7:8:"])
- assert [] == Generic.parse(["1:2:3:4:5:6:7:8:9"])
- assert [] == Generic.parse(["1:::2:3:4:5:6:7:8"])
- assert [] == Generic.parse(["a:b:c:d:e:f::g"])
+ assert [] == Generic.parse("1:")
+ assert [] == Generic.parse("1:2")
+ assert [] == Generic.parse("1:2:3")
+ assert [] == Generic.parse("1:2:3:4")
+ assert [] == Generic.parse("1:2:3:4:5")
+ assert [] == Generic.parse("1:2:3:4:5:6")
+ assert [] == Generic.parse("1:2:3:4:5:6:7")
+ assert [] == Generic.parse("1:2:3:4:5:6:7:8:")
+ assert [] == Generic.parse("1:2:3:4:5:6:7:8:9")
+ assert [] == Generic.parse("1:::2:3:4:5:6:7:8")
+ assert [] == Generic.parse("a:b:c:d:e:f::g")
end
test "IPv4" do
- assert [{1, 2, 3, 4}] == Generic.parse(["1.2.3.4"])
- assert [{1, 2, 3, 4}] == Generic.parse([" 1.2.3.4 "])
+ assert [{1, 2, 3, 4}] == Generic.parse("1.2.3.4")
+ assert [{1, 2, 3, 4}] == Generic.parse(" 1.2.3.4 ")
end
test "IPv6 without ::" do
- assert [{0x0001, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1:23:456:7890:a:bc:def:d34d"])
- assert [{0x0001, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1:23:456:7890:a:bc:1.2.3.4"])
+ assert [{0x0001, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1:23:456:7890:a:bc:def:d34d")
+ assert [{0x0001, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1:23:456:7890:a:bc:1.2.3.4")
end
test "IPv6 with :: at position 0" do
- assert [{0x0000, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["::23:456:7890:a:bc:def:d34d"])
- assert [{0x0000, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["::23:456:7890:a:bc:1.2.3.4"])
- assert [{0x0000, 0x0000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["::456:7890:a:bc:def:d34d"])
- assert [{0x0000, 0x0000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["::456:7890:a:bc:1.2.3.4"])
- assert [{0x0000, 0x0000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["::7890:a:bc:def:d34d"])
- assert [{0x0000, 0x0000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["::7890:a:bc:1.2.3.4"])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["::a:bc:def:d34d"])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["::a:bc:1.2.3.4"])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["::bc:def:d34d"])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["::bc:1.2.3.4"])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse(["::def:d34d"])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse(["::1.2.3.4"])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse(["::d34d"])
- assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["::"])
+ assert [{0x0000, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("::23:456:7890:a:bc:def:d34d")
+ assert [{0x0000, 0x0023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("::23:456:7890:a:bc:1.2.3.4")
+ assert [{0x0000, 0x0000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("::456:7890:a:bc:def:d34d")
+ assert [{0x0000, 0x0000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("::456:7890:a:bc:1.2.3.4")
+ assert [{0x0000, 0x0000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("::7890:a:bc:def:d34d")
+ assert [{0x0000, 0x0000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("::7890:a:bc:1.2.3.4")
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("::a:bc:def:d34d")
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("::a:bc:1.2.3.4")
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("::bc:def:d34d")
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse("::bc:1.2.3.4")
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse("::def:d34d")
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse("::1.2.3.4")
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse("::d34d")
+ assert [{0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("::")
end
test "IPv6 with :: at position 1" do
- assert [{0x0001, 0x000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1::456:7890:a:bc:def:d34d"])
- assert [{0x0001, 0x000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1::456:7890:a:bc:1.2.3.4"])
- assert [{0x0001, 0x000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1::7890:a:bc:def:d34d"])
- assert [{0x0001, 0x000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1::7890:a:bc:1.2.3.4"])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1::a:bc:def:d34d"])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1::a:bc:1.2.3.4"])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1::bc:def:d34d"])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1::bc:1.2.3.4"])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse(["1::def:d34d"])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse(["1::1.2.3.4"])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse(["1::d34d"])
- assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["1::"])
+ assert [{0x0001, 0x000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1::456:7890:a:bc:def:d34d")
+ assert [{0x0001, 0x000, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1::456:7890:a:bc:1.2.3.4")
+ assert [{0x0001, 0x000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1::7890:a:bc:def:d34d")
+ assert [{0x0001, 0x000, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1::7890:a:bc:1.2.3.4")
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1::a:bc:def:d34d")
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1::a:bc:1.2.3.4")
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1::bc:def:d34d")
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1::bc:1.2.3.4")
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse("1::def:d34d")
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse("1::1.2.3.4")
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse("1::d34d")
+ assert [{0x0001, 0x000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("1::")
end
test "IPv6 with :: at position 2" do
- assert [{0x0001, 0x023, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1:23::7890:a:bc:def:d34d"])
- assert [{0x0001, 0x023, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1:23::7890:a:bc:1.2.3.4"])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1:23::a:bc:def:d34d"])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1:23::a:bc:1.2.3.4"])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1:23::bc:def:d34d"])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1:23::bc:1.2.3.4"])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse(["1:23::def:d34d"])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse(["1:23::1.2.3.4"])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse(["1:23::d34d"])
- assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["1:23::"])
+ assert [{0x0001, 0x023, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1:23::7890:a:bc:def:d34d")
+ assert [{0x0001, 0x023, 0x0000, 0x7890, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1:23::7890:a:bc:1.2.3.4")
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1:23::a:bc:def:d34d")
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1:23::a:bc:1.2.3.4")
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1:23::bc:def:d34d")
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1:23::bc:1.2.3.4")
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse("1:23::def:d34d")
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse("1:23::1.2.3.4")
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse("1:23::d34d")
+ assert [{0x0001, 0x023, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("1:23::")
end
test "IPv6 with :: at position 3" do
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1:23:456::a:bc:def:d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1:23:456::a:bc:1.2.3.4"])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1:23:456::bc:def:d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1:23:456::bc:1.2.3.4"])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse(["1:23:456::def:d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse(["1:23:456::1.2.3.4"])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse(["1:23:456::d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["1:23:456::"])
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x000a, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1:23:456::a:bc:def:d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x000a, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1:23:456::a:bc:1.2.3.4")
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1:23:456::bc:def:d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1:23:456::bc:1.2.3.4")
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse("1:23:456::def:d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse("1:23:456::1.2.3.4")
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse("1:23:456::d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("1:23:456::")
end
test "IPv6 with :: at position 4" do
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse(["1:23:456:7890::bc:def:d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse(["1:23:456:7890::bc:1.2.3.4"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse(["1:23:456:7890::def:d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse(["1:23:456:7890::1.2.3.4"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse(["1:23:456:7890::d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["1:23:456:7890::"])
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x00bc, 0x0def, 0xd34d}] == Generic.parse("1:23:456:7890::bc:def:d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x00bc, 0x0102, 0x0304}] == Generic.parse("1:23:456:7890::bc:1.2.3.4")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0def, 0xd34d}] == Generic.parse("1:23:456:7890::def:d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0102, 0x0304}] == Generic.parse("1:23:456:7890::1.2.3.4")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0000, 0xd34d}] == Generic.parse("1:23:456:7890::d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("1:23:456:7890::")
end
test "IPv6 with :: at position 5" do
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0def, 0xd34d}] == Generic.parse(["1:23:456:7890:a::def:d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0102, 0x0304}] == Generic.parse(["1:23:456:7890:a::1.2.3.4"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0000, 0xd34d}] == Generic.parse(["1:23:456:7890:a::d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0000, 0x0000}] == Generic.parse(["1:23:456:7890:a::"])
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0def, 0xd34d}] == Generic.parse("1:23:456:7890:a::def:d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0102, 0x0304}] == Generic.parse("1:23:456:7890:a::1.2.3.4")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0000, 0xd34d}] == Generic.parse("1:23:456:7890:a::d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x0000, 0x0000, 0x0000}] == Generic.parse("1:23:456:7890:a::")
end
test "IPv6 with :: at position 6" do
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0000, 0xd34d}] == Generic.parse(["1:23:456:7890:a:bc::d34d"])
- assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0000, 0x0000}] == Generic.parse(["1:23:456:7890:a:bc::"])
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0000, 0xd34d}] == Generic.parse("1:23:456:7890:a:bc::d34d")
+ assert [{0x0001, 0x023, 0x0456, 0x7890, 0x000a, 0x00bc, 0x0000, 0x0000}] == Generic.parse("1:23:456:7890:a:bc::")
end
test "IPv6 with leading zeroes" do
- assert [{0x0000, 0x0001, 0x0002, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["0:01:002:0003:0000::"])
- assert [{0x000a, 0x001a, 0x002a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["0a:01a:002a::"])
- assert [{0x00ab, 0x01ab, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["0ab:01ab::"])
- assert [{0x0abc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse(["0abc::"])
+ assert [{0x0000, 0x0001, 0x0002, 0x0003, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("0:01:002:0003:0000::")
+ assert [{0x000a, 0x001a, 0x002a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("0a:01a:002a::")
+ assert [{0x00ab, 0x01ab, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("0ab:01ab::")
+ assert [{0x0abc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}] == Generic.parse("0abc::")
end
test "IPv6 with mixed case" do
- assert [{0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd}] == Generic.parse(["abcd:abcD:abCd:abCD:aBcd:aBcD:aBCd:aBCD"])
- assert [{0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd}] == Generic.parse(["Abcd:AbcD:AbCd:AbCD:ABcd:ABcD:ABCd:ABCD"])
+ assert [{0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd}] == Generic.parse("abcd:abcD:abCd:abCD:aBcd:aBcD:aBCd:aBCD")
+ assert [{0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd, 0xabcd}] == Generic.parse("Abcd:AbcD:AbCd:AbCD:ABcd:ABcD:ABCd:ABCD")
end
test "commas with optional whitespace" do
- assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse(["127.0.0.1,::1"])
- assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse(["127.0.0.1,\s::1"])
- assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse(["127.0.0.1\s,::1"])
- assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse(["127.0.0.1\s,\s::1"])
- assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse(["\s\t\s\t127.0.0.1\t\t\s\s,\s\t\t\s::1\t"])
- end
-
- test "multiple headers" do
- headers = [
- "1.1.1.1, unknown, 2.2.2.2",
- " 3.3.3.3 , 4.4.4.4,not_an_ip",
- "5.5.5.5,::6:6:6:6",
- "unknown,5,7.7.7.7",
- ]
-
- ips = [
- {1, 1, 1, 1},
- {2, 2, 2, 2},
- {3, 3, 3, 3},
- {4, 4, 4, 4},
- {5, 5, 5, 5},
- {0, 0, 0, 0, 6, 6, 6, 6},
- {7, 7, 7, 7},
- ]
-
- assert ips == Generic.parse(headers)
+ assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse("127.0.0.1,::1")
+ assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse("127.0.0.1,\s::1")
+ assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse("127.0.0.1\s,::1")
+ assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse("127.0.0.1\s,\s::1")
+ assert [{127, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1}] == Generic.parse("\s\t\s\t127.0.0.1\t\t\s\s,\s\t\t\s::1\t")
end
end
end
diff --git a/test/remote_ip/headers_test.exs b/test/remote_ip/headers_test.exs
new file mode 100644
index 0000000..560d7b6
--- /dev/null
+++ b/test/remote_ip/headers_test.exs
@@ -0,0 +1,126 @@
+defmodule RemoteIp.HeadersTest do
+ use ExUnit.Case, async: true
+ alias RemoteIp.Headers
+
+ @abc_headers [
+ {"a", "1.1.1.1"},
+ {"x", "0.0.0.0"},
+ {"b", "2.2.2.2"},
+ {"y", "0.0.0.0"},
+ {"c", "3.3.3.3"},
+ {"z", "0.0.0.0"},
+ ]
+
+ @abc_allowed MapSet.new(~w[a b c])
+
+ test "parsing an empty list of headers" do
+ assert Headers.parse([], @abc_allowed) == []
+ end
+
+ test "parsing with no allowed headers" do
+ assert Headers.parse(@abc_headers, MapSet.new) == []
+ end
+
+ test "only allowed headers get parsed" do
+ assert Headers.parse(@abc_headers, @abc_allowed) == [{1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}]
+ end
+
+ test "parsing Forwarded headers" do
+ ips = [{1, 2, 3, 4}, {0, 0, 0, 0, 2, 3, 4, 5}, {3, 4, 5, 6}, {0, 0, 0, 0, 4, 5, 6, 7}]
+
+ assert ips == Headers.parse([
+ {"forwarded", ~S'for=1.2.3.4'},
+ {"forwarded", ~S'for="[::2:3:4:5]";proto=http;host=example.com'},
+ {"forwarded", ~S'proto=http;for=3.4.5.6;by=127.0.0.1'},
+ {"forwarded", ~S'proto=http;host=example.com;for="[::4:5:6:7]"'},
+ ], MapSet.new(~w[forwarded]))
+
+ assert ips == Headers.parse([
+ {"forwarded", ~S'for=1.2.3.4, for="[::2:3:4:5]";proto=http;host=example.com'},
+ {"forwarded", ~S'proto=http;for=3.4.5.6;by=127.0.0.1'},
+ {"forwarded", ~S'proto=http;host=example.com;for="[::4:5:6:7]"'},
+ ], MapSet.new(~w[forwarded]))
+
+ assert ips == Headers.parse([
+ {"forwarded", ~S'for=1.2.3.4, for="[::2:3:4:5]";proto=http;host=example.com, proto=http;for=3.4.5.6;by=127.0.0.1'},
+ {"forwarded", ~S'proto=http;host=example.com;for="[::4:5:6:7]"'},
+ ], MapSet.new(~w[forwarded]))
+
+ assert ips == Headers.parse([
+ {"forwarded", ~S'for=1.2.3.4'},
+ {"forwarded", ~S'for="[::2:3:4:5]";proto=http;host=example.com'},
+ {"forwarded", ~S'proto=http;for=3.4.5.6;by=127.0.0.1, proto=http;host=example.com;for="[::4:5:6:7]"'},
+ ], MapSet.new(~w[forwarded]))
+
+ assert ips == Headers.parse([
+ {"forwarded", ~S'for=1.2.3.4'},
+ {"forwarded", ~S'for="[::2:3:4:5]";proto=http;host=example.com, proto=http;for=3.4.5.6;by=127.0.0.1, proto=http;host=example.com;for="[::4:5:6:7]"'},
+ ], MapSet.new(~w[forwarded]))
+ end
+
+ test "parsing generic headers" do
+ headers = [
+ {"generic", "1.1.1.1, unknown, 2.2.2.2"},
+ {"generic", " 3.3.3.3 , 4.4.4.4,not_an_ip"},
+ {"generic", "5.5.5.5,::6:6:6:6"},
+ {"generic", "unknown,5,7.7.7.7"},
+ ]
+
+ ips = [
+ {1, 1, 1, 1},
+ {2, 2, 2, 2},
+ {3, 3, 3, 3},
+ {4, 4, 4, 4},
+ {5, 5, 5, 5},
+ {0, 0, 0, 0, 6, 6, 6, 6},
+ {7, 7, 7, 7},
+ ]
+
+ assert Headers.parse(headers, MapSet.new(~w[generic])) == ips
+ end
+
+ test "parsing an unrecognized header falls back to generic parsing" do
+ headers = [
+ {"x-forwarded-for", "1.1.1.1,2.2.2.2"},
+ {"x-real-ip", "3.3.3.3, 4.4.4.4"},
+ {"x-client-ip", "5.5.5.5"},
+ ]
+ allowed = MapSet.new(~w[x-forwarded-for x-real-ip x-client-ip])
+ ips = [
+ {1, 1, 1, 1},
+ {2, 2, 2, 2},
+ {3, 3, 3, 3},
+ {4, 4, 4, 4},
+ {5, 5, 5, 5},
+ ]
+
+ assert Headers.parse(headers, allowed) == ips
+ end
+
+ test "parsing multiple kinds of headers" do
+ headers = [
+ {"forwarded", "for=1.1.1.1"},
+ {"x-forwarded-for", "2.2.2.2"},
+ {"forwarded", "for=3.3.3.3, for=4.4.4.4"},
+ {"not-allowed", "0.0.0.0"},
+ {"forwarded", "for=5.5.5.5"},
+ {"x-forwarded-for", "6.6.6.6"},
+ {"x-forwarded-for", "7.7.7.7"},
+ {"not-allowed", "10.10.10.10"},
+ ]
+
+ allowed = MapSet.new(~w[forwarded x-forwarded-for])
+
+ ips = [
+ {1, 1, 1, 1},
+ {2, 2, 2, 2},
+ {3, 3, 3, 3},
+ {4, 4, 4, 4},
+ {5, 5, 5, 5},
+ {6, 6, 6, 6},
+ {7, 7, 7, 7},
+ ]
+
+ assert Headers.parse(headers, allowed) == ips
+ end
+end
diff --git a/test/remote_ip_test.exs b/test/remote_ip_test.exs
index 92d444f..856eae4 100644
--- a/test/remote_ip_test.exs
+++ b/test/remote_ip_test.exs
@@ -1,301 +1,301 @@
defmodule RemoteIpTest do
use ExUnit.Case, async: true
use Plug.Test
# put_req_header/3 will obliterate existing values, whereas we want to
# append multiple values for the same header.
#
def add_req_header(%Plug.Conn{req_headers: headers} = conn, header, value) do
%{conn | req_headers: headers ++ [{header, value}]}
end
def forwarded(conn, value), do: add_req_header(conn, "forwarded", value)
def x_forwarded_for(conn, ip), do: add_req_header(conn, "x-forwarded-for", ip)
def custom(conn, ip), do: add_req_header(conn, "custom", ip)
def remote_ip(conn, opts \\ []) do
RemoteIp.call(conn, RemoteIp.init(opts)).remote_ip
end
# Not a real IP address, but RemoteIp shouldn't ever be actually manipulating
# this value. So, in this Conn, we use :peer as a canary in the coalmine.
#
@conn %Plug.Conn{remote_ip: :peer}
test "zero hops (i.e., no forwarding headers)" do
assert :peer == @conn |> remote_ip
assert :peer == @conn |> remote_ip(headers: ~w[])
assert :peer == @conn |> remote_ip(headers: ~w[custom])
assert :peer == @conn |> remote_ip(proxies: ~w[])
assert :peer == @conn |> remote_ip(proxies: ~w[0.0.0.0/0 ::/0])
assert :peer == @conn |> remote_ip(headers: ~w[], proxies: ~w[])
assert :peer == @conn |> remote_ip(headers: ~w[], proxies: ~w[0.0.0.0/0 ::/0])
assert :peer == @conn |> remote_ip(headers: ~w[custom], proxies: ~w[])
assert :peer == @conn |> remote_ip(headers: ~w[custom], proxies: ~w[0.0.0.0/0 ::/0])
end
describe "one hop" do
test "from an unknown IP" do
assert :peer == @conn |> forwarded("for=unknown") |> remote_ip
assert :peer == @conn |> x_forwarded_for("not_an_ip") |> remote_ip
assert :peer == @conn |> custom("_obf") |> remote_ip(headers: ~w[custom])
end
test "from a loopback IP" do
assert :peer == @conn |> forwarded("for=127.0.0.1") |> remote_ip
assert :peer == @conn |> x_forwarded_for("::1") |> remote_ip
assert :peer == @conn |> custom("127.0.0.2") |> remote_ip(headers: ~w[custom])
end
test "from a private IP" do
assert :peer == @conn |> forwarded("for=10.0.0.1") |> remote_ip
assert :peer == @conn |> x_forwarded_for("172.16.0.1") |> remote_ip
assert :peer == @conn |> x_forwarded_for("fd00::") |> remote_ip
assert :peer == @conn |> custom("192.168.0.1") |> remote_ip(headers: ~w[custom])
end
test "from a public IP configured as a known proxy" do
assert :peer == @conn |> forwarded("for=1.2.3.4") |> remote_ip(proxies: ~w[1.2.3.4/32])
assert :peer == @conn |> x_forwarded_for("::a") |> remote_ip(proxies: ~w[::a/128])
assert :peer == @conn |> custom("1.2.3.4") |> remote_ip(headers: ~w[custom], proxies: ~w[1.2.0.0/16])
end
test "from a public IP not configured as a known proxy" do
assert {1, 2, 3, 4} == @conn |> forwarded("for=1.2.3.4") |> remote_ip(proxies: ~w[::/0])
assert {1, 2, 3, 4, 5, 6, 7, 8} == @conn |> x_forwarded_for("1:2:3:4:5:6:7:8") |> remote_ip(proxies: ~w[1:1::/64])
assert {1, 2, 3, 4} == @conn |> custom("1.2.3.4") |> remote_ip(headers: ~w[custom])
end
end
describe "two hops" do
test "from unknown to unknown" do
assert :peer == @conn |> forwarded("for=unknown,for=_obf") |> remote_ip
assert :peer == @conn |> x_forwarded_for("_obf,not_an_ip") |> remote_ip
assert :peer == @conn |> custom("unknown,unknown") |> remote_ip(headers: ~w[custom])
end
test "from unknown to loopback" do
assert :peer == @conn |> forwarded("for=_obf,for=127.0.0.1") |> remote_ip
assert :peer == @conn |> x_forwarded_for("unknown,::1") |> remote_ip
assert :peer == @conn |> custom("not_an_ip, 127.0.0.2") |> remote_ip(headers: ~w[custom])
end
test "from unknown to private" do
assert :peer == @conn |> forwarded("for=unknown,for=10.10.10.10") |> remote_ip
assert :peer == @conn |> x_forwarded_for("_obf, fc00::ABCD") |> remote_ip
assert :peer == @conn |> x_forwarded_for("not_an_ip,192.168.0.4") |> remote_ip
assert :peer == @conn |> custom("unknown,172.16.72.1") |> remote_ip(headers: ~w[custom])
end
test "from unknown to proxy" do
assert :peer == @conn |> forwarded("for=_obf,for=1.2.3.4") |> remote_ip(proxies: ~w[1.2.3.4/32])
assert :peer == @conn |> x_forwarded_for("unknown,a:b:c:d:e:f::") |> remote_ip(proxies: ~w[::/0])
assert :peer == @conn |> custom("not_an_ip,1.2.3.4") |> remote_ip(headers: ~w[custom], proxies: ~w[1.0.0.0/8])
end
test "from unknown to non-proxy" do
assert {1, 2, 3, 4} == @conn |> forwarded("for=unknown,for=1.2.3.4") |> remote_ip(proxies: ~w[1.2.3.5/32])
assert {0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0} == @conn |> x_forwarded_for("_obf,a:b:c:d:e:f::") |> remote_ip
assert {1, 2, 3, 4} == @conn |> custom("not_an_ip,1.2.3.4") |> remote_ip(headers: ~w[custom], proxies: ~w[8.6.7.5/32 3:0:9::/64])
end
test "from loopback to unknown" do
assert :peer == @conn |> forwarded("for=\"[::1]\",for=unknown") |> remote_ip
assert :peer == @conn |> x_forwarded_for("127.0.0.1,not_an_ip") |> remote_ip
assert :peer == @conn |> custom("127.0.0.2,_obfuscated_ipaddr") |> remote_ip(headers: ~w[custom])
end
test "from loopback to loopback" do
assert :peer == @conn |> forwarded("for=127.0.0.1, for=127.0.0.1") |> remote_ip
assert :peer == @conn |> x_forwarded_for("::1, ::1") |> remote_ip
assert :peer == @conn |> custom("::1, 127.0.0.1") |> remote_ip(headers: ~w[custom])
end
test "from loopback to private" do
assert :peer == @conn |> forwarded("for=127.0.0.10, for=\"[fc00::1]\"") |> remote_ip
assert :peer == @conn |> x_forwarded_for("::1, 192.168.1.2") |> remote_ip
assert :peer == @conn |> custom("127.0.0.1, 172.16.0.1") |> remote_ip(headers: ~w[custom])
assert :peer == @conn |> custom("127.1.2.3, 10.10.10.1") |> remote_ip(headers: ~w[custom])
end
test "from loopback to proxy" do
assert :peer == @conn |> forwarded("for=127.0.0.1 , for=1.2.3.4") |> remote_ip(proxies: ~w[1.2.3.4/32])
assert :peer == @conn |> x_forwarded_for("::1, 1.2.3.4") |> remote_ip(proxies: ~w[1.2.3.0/24])
assert :peer == @conn |> custom("127.0.0.2, 2001:0db8:85a3:0000:0000:8A2E:0370:7334") |> remote_ip(headers: ~w[custom], proxies: ~w[2001:0db8:85a3::8A2E:0370:7334/128])
end
test "from loopback to non-proxy" do
assert {1, 2, 3, 4} == @conn |> forwarded("for=127.0.0.1, for=1.2.3.4") |> remote_ip
assert {1, 2, 3, 4} == @conn |> x_forwarded_for("::1, 1.2.3.4") |> remote_ip(proxies: ~w[2.0.0.0/8])
assert {0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334} == @conn |> custom("::1, 2001:0db8:85a3:0000:0000:8A2E:0370:7334") |> remote_ip(headers: ~w[custom], proxies: ~w[fe80:0000:0000:0000:0202:b3ff:fe1e:8329/128])
end
test "from private to unknown" do
assert :peer == @conn |> forwarded("for=10.10.10.10,for=unknown") |> remote_ip
assert :peer == @conn |> x_forwarded_for("fc00::ABCD, _obf") |> remote_ip
assert :peer == @conn |> x_forwarded_for("192.168.0.4, not_an_ip") |> remote_ip
assert :peer == @conn |> custom("172.16.72.1, unknown") |> remote_ip(headers: ~w[custom])
end
test "from private to loopback" do
assert :peer == @conn |> forwarded("for=\"[fc00::1]\", for=127.0.0.10") |> remote_ip
assert :peer == @conn |> forwarded("for=10.10.10.1, for=127.1.2.3") |> remote_ip
assert :peer == @conn |> x_forwarded_for("192.168.1.2, ::1") |> remote_ip
assert :peer == @conn |> custom("172.16.0.1, 127.0.0.1") |> remote_ip(headers: ~w[custom])
end
test "from private to private" do
assert :peer == @conn |> forwarded("for=172.16.0.1, for=\"[fc00::1]\"") |> remote_ip
assert :peer == @conn |> x_forwarded_for("192.168.0.1, 192.168.0.2") |> remote_ip
assert :peer == @conn |> custom("10.0.0.1, 10.0.0.2") |> remote_ip(headers: ~w[custom])
end
test "from private to proxy" do
assert :peer == @conn |> forwarded("for=\"[fc00::1:2:3]\", for=1.2.3.4") |> remote_ip(proxies: ~w[0.0.0.0/0])
assert :peer == @conn |> forwarded("for=10.0.10.0, for=\"[::1.2.3.4]\"") |> remote_ip(proxies: ~w[::/64])
assert :peer == @conn |> x_forwarded_for("192.168.0.1,1.2.3.4") |> remote_ip(proxies: ~w[1.2.0.0/16])
assert :peer == @conn |> custom("172.16.1.2, 3.4.5.6") |> remote_ip(headers: ~w[custom], proxies: ~w[3.0.0.0/8])
end
test "from private to non-proxy" do
assert {1, 2, 3, 4} == @conn |> forwarded("for=\"[fc00::1:2:3]\", for=1.2.3.4") |> remote_ip
assert {0, 0, 0, 0, 0, 0, 258, 772} == @conn |> forwarded("for=10.0.10.0, for=\"[::1.2.3.4]\"") |> remote_ip(proxies: ~w[255.0.0.0/8])
assert {1, 2, 3, 4} == @conn |> x_forwarded_for("192.168.0.1,1.2.3.4") |> remote_ip
assert {3, 4, 5, 6} == @conn |> custom("172.16.1.2 , 3.4.5.6") |> remote_ip(headers: ~w[custom], proxies: ~w[1.2.3.4/32])
end
test "from proxy to unknown" do
assert :peer == @conn |> forwarded("for=1.2.3.4,for=_obf") |> remote_ip(proxies: ~w[1.2.3.4/32])
assert :peer == @conn |> x_forwarded_for("a:b:c:d:e:f::,unknown") |> remote_ip(proxies: ~w[::/0])
assert :peer == @conn |> custom("1.2.3.4,not_an_ip") |> remote_ip(headers: ~w[custom], proxies: ~w[1.0.0.0/8])
end
test "from proxy to loopback" do
assert :peer == @conn |> forwarded("for=1.2.3.4, for=127.0.0.1") |> remote_ip(proxies: ~w[1.2.3.4/32])
assert :peer == @conn |> x_forwarded_for("1.2.3.4, ::1") |> remote_ip(proxies: ~w[1.2.3.0/24])
assert :peer == @conn |> custom("2001:0db8:85a3:0000:0000:8A2E:0370:7334, 127.0.0.2") |> remote_ip(headers: ~w[custom], proxies: ~w[2001:0db8:85a3::8A2E:0370:7334/128])
end
test "from proxy to private" do
assert :peer == @conn |> forwarded("for=1.2.3.4, for=\"[fc00::1:2:3]\"") |> remote_ip(proxies: ~w[0.0.0.0/0])
assert :peer == @conn |> forwarded("for=\"[::1.2.3.4]\", for=10.0.10.0") |> remote_ip(proxies: ~w[::/64])
assert :peer == @conn |> x_forwarded_for("1.2.3.4,192.168.0.1") |> remote_ip(proxies: ~w[1.2.0.0/16])
assert :peer == @conn |> custom("3.4.5.6 , 172.16.1.2") |> remote_ip(headers: ~w[custom], proxies: ~w[3.0.0.0/8])
end
test "from proxy to proxy" do
assert :peer == @conn |> forwarded("for=1.2.3.4, for=1.2.3.5") |> remote_ip(proxies: ~w[1.2.3.0/24])
assert :peer == @conn |> x_forwarded_for("a:b:c:d::,1:2:3:4::") |> remote_ip(proxies: ~w[a:b:c:d::/128 1:2:3:4::/64])
assert :peer == @conn |> custom("1.2.3.4, 3.4.5.6") |> remote_ip(headers: ~w[custom], proxies: ~w[1.2.3.4/32 3.4.5.6/32])
end
test "from proxy to non-proxy" do
assert {3, 4, 5, 6} == @conn |> forwarded("for=1.2.3.4,for=3.4.5.6") |> remote_ip(proxies: ~w[1.2.3.4/32])
assert {0, 0, 0, 0, 3, 4, 5, 6} == @conn |> x_forwarded_for("::1:2:3:4, ::3:4:5:6") |> remote_ip(proxies: ~w[::1:2:3:4/128])
assert {3, 4, 5, 6} == @conn |> custom("1.2.3.4, 3.4.5.6") |> remote_ip(headers: ~w[custom], proxies: ~w[1.2.3.4/32])
end
test "from non-proxy to unknown" do
assert {1, 2, 3, 4} == @conn |> forwarded("for=1.2.3.4,for=not_an_ip") |> remote_ip
assert {0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x0, 0x0} == @conn |> x_forwarded_for("a:b:c:d:e:f::,unknown") |> remote_ip(proxies: ~w[b::/64])
assert {1, 2, 3, 4} == @conn |> custom("1.2.3.4,_obf") |> remote_ip(headers: ~w[custom])
end
test "from non-proxy to loopback" do
assert {1, 2, 3, 4} == @conn |> forwarded("for=1.2.3.4, for=127.0.0.1") |> remote_ip(proxies: ~w[abcd::/32])
assert {1, 2, 3, 4} == @conn |> x_forwarded_for("1.2.3.4, ::1") |> remote_ip(proxies: ~w[4.3.2.1/32])
assert {0x2001, 0x0db8, 0x85a3, 0x0000, 0x0000, 0x8a2e, 0x0370, 0x7334} == @conn |> custom("2001:0db8:85a3:0000:0000:8A2E:0370:7334, 127.0.0.2") |> remote_ip(headers: ~w[custom])
end
test "from non-proxy to private" do
assert {1, 2, 3, 4} == @conn |> forwarded("for=1.2.3.4, for=\"[fc00::1:2:3]\"") |> remote_ip
assert {0, 0, 0, 0, 0, 0, 258, 772} == @conn |> forwarded("for=\"[::1.2.3.4]\", for=10.0.10.0") |> remote_ip(proxies: ~w[1:2:3:4::/64])
assert {1, 2, 3, 4} == @conn |> x_forwarded_for("1.2.3.4,192.168.0.1") |> remote_ip(proxies: ~w[1.2.3.5/32])
assert {3, 4, 5, 6} == @conn |> custom("3.4.5.6 , 172.16.1.2") |> remote_ip(headers: ~w[custom])
end
test "from non-proxy to proxy" do
assert {1, 2, 3, 4} == @conn |> forwarded("for=1.2.3.4,for=3.4.5.6") |> remote_ip(proxies: ~w[3.4.5.6/32])
assert {0, 0, 0, 0, 1, 2, 3, 4} == @conn |> x_forwarded_for("::1:2:3:4, ::3:4:5:6") |> remote_ip(proxies: ~w[::3:4:5:6/128])
assert {1, 2, 3, 4} == @conn |> custom("1.2.3.4, 3.4.5.6") |> remote_ip(headers: ~w[custom], proxies: ~w[3.4.5.0/24])
end
test "from non-proxy to non-proxy" do
assert {3, 4, 5, 6} == @conn |> forwarded("for=1.2.3.4,for=3.4.5.6") |> remote_ip
assert {0, 0, 0, 0, 3, 4, 5, 6} == @conn |> x_forwarded_for("::1:2:3:4, ::3:4:5:6") |> remote_ip
assert {3, 4, 5, 6} == @conn |> custom("1.2.3.4, 3.4.5.6") |> remote_ip(headers: ~w[custom], proxies: ~w[5.6.7.8/32])
end
end
test "several hops" do
conn = @conn |> forwarded("for=3.4.5.6") |> forwarded("for=10.0.0.1") |> forwarded("for=192.168.0.1")
assert {3, 4, 5, 6} == conn |> remote_ip
conn = @conn |> x_forwarded_for("9.9.9.9, 172.31.4.4, 3.4.5.6, 10.0.0.1")
assert {3, 4, 5, 6} == conn |> remote_ip
conn = @conn |> custom("fe80::0202:b3ff:fe1e:8329") |> custom("::1") |> custom("::1")
assert {0xfe80, 0x0000, 0x0000, 0x0000, 0x0202, 0xb3ff, 0xfe1e, 0x8329} == conn |> remote_ip(headers: ~w[custom])
conn = @conn
|> x_forwarded_for("2001:0db8:85a3::8a2e:0370:7334")
|> x_forwarded_for("fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1")
|> x_forwarded_for("unknown, fc00::, fe00::, fdff::")
assert {0xfe80, 0x0000, 0x0000, 0x0000, 0x0202, 0xb3ff, 0xfe1e, 0x8329} == conn |> remote_ip(proxies: ~w[fe00::/128])
end
- test "header priority" do
+ test "allowed headers" do
conn = @conn
|> put_req_header("a", "1.2.3.4")
|> put_req_header("b", "2.3.4.5")
|> put_req_header("c", "3.4.5.6")
assert :peer == conn |> remote_ip(headers: ~w[])
assert {1, 2, 3, 4} == conn |> remote_ip(headers: ~w[a])
- assert {1, 2, 3, 4} == conn |> remote_ip(headers: ~w[a b])
- assert {1, 2, 3, 4} == conn |> remote_ip(headers: ~w[a c])
- assert {1, 2, 3, 4} == conn |> remote_ip(headers: ~w[a b c])
- assert {1, 2, 3, 4} == conn |> remote_ip(headers: ~w[a c b])
+ assert {2, 3, 4, 5} == conn |> remote_ip(headers: ~w[a b])
+ assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[a c])
+ assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[a b c])
+ assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[a c b])
assert {2, 3, 4, 5} == conn |> remote_ip(headers: ~w[b])
assert {2, 3, 4, 5} == conn |> remote_ip(headers: ~w[b a])
- assert {2, 3, 4, 5} == conn |> remote_ip(headers: ~w[b c])
- assert {2, 3, 4, 5} == conn |> remote_ip(headers: ~w[b a c])
- assert {2, 3, 4, 5} == conn |> remote_ip(headers: ~w[b c a])
+ assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[b c])
+ assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[b a c])
+ assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[b c a])
assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[c])
assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[c a])
assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[c b])
assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[c a b])
assert {3, 4, 5, 6} == conn |> remote_ip(headers: ~w[c b a])
end
- test "header fallback" do
+ test "allowed headers maintain relative ordering" do
headers = ~w[a b c]
a = fn conn -> put_req_header(conn, "a", "1.2.3.4") end
b = fn conn -> put_req_header(conn, "b", "2.3.4.5") end
c = fn conn -> put_req_header(conn, "c", "3.4.5.6") end
assert :peer == @conn |> remote_ip(headers: headers)
assert {1, 2, 3, 4} == @conn |> a.() |> remote_ip(headers: headers)
- assert {1, 2, 3, 4} == @conn |> a.() |> b.() |> remote_ip(headers: headers)
- assert {1, 2, 3, 4} == @conn |> a.() |> c.() |> remote_ip(headers: headers)
- assert {1, 2, 3, 4} == @conn |> a.() |> b.() |> c.() |> remote_ip(headers: headers)
- assert {1, 2, 3, 4} == @conn |> a.() |> c.() |> b.() |> remote_ip(headers: headers)
+ assert {2, 3, 4, 5} == @conn |> a.() |> b.() |> remote_ip(headers: headers)
+ assert {3, 4, 5, 6} == @conn |> a.() |> c.() |> remote_ip(headers: headers)
+ assert {3, 4, 5, 6} == @conn |> a.() |> b.() |> c.() |> remote_ip(headers: headers)
+ assert {2, 3, 4, 5} == @conn |> a.() |> c.() |> b.() |> remote_ip(headers: headers)
assert {2, 3, 4, 5} == @conn |> b.() |> remote_ip(headers: headers)
assert {1, 2, 3, 4} == @conn |> b.() |> a.() |> remote_ip(headers: headers)
- assert {2, 3, 4, 5} == @conn |> b.() |> c.() |> remote_ip(headers: headers)
- assert {1, 2, 3, 4} == @conn |> b.() |> a.() |> c.() |> remote_ip(headers: headers)
+ assert {3, 4, 5, 6} == @conn |> b.() |> c.() |> remote_ip(headers: headers)
+ assert {3, 4, 5, 6} == @conn |> b.() |> a.() |> c.() |> remote_ip(headers: headers)
assert {1, 2, 3, 4} == @conn |> b.() |> c.() |> a.() |> remote_ip(headers: headers)
assert {3, 4, 5, 6} == @conn |> c.() |> remote_ip(headers: headers)
assert {1, 2, 3, 4} == @conn |> c.() |> a.() |> remote_ip(headers: headers)
assert {2, 3, 4, 5} == @conn |> c.() |> b.() |> remote_ip(headers: headers)
- assert {1, 2, 3, 4} == @conn |> c.() |> a.() |> b.() |> remote_ip(headers: headers)
+ assert {2, 3, 4, 5} == @conn |> c.() |> a.() |> b.() |> remote_ip(headers: headers)
assert {1, 2, 3, 4} == @conn |> c.() |> b.() |> a.() |> remote_ip(headers: headers)
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 30, 3:41 AM (1 d, 19 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41360
Default Alt Text
(98 KB)
Attached To
Mode
R27 remote_ip
Attached
Detach File
Event Timeline
Log In to Comment