Skip to content

Commit ffa2abd

Browse files
committed
Introduce URI.encode/2 function
`URI.encode/1` escapes character if it is not satisfied `URI.char_unescaped?/1`
1 parent 14722ba commit ffa2abd

File tree

2 files changed

+40
-16
lines changed

2 files changed

+40
-16
lines changed

lib/elixir/lib/uri.ex

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -145,30 +145,53 @@ defmodule URI do
145145
encode(to_string(k)) <> "=" <> encode(to_string(v))
146146
end
147147

148+
# RFC3986, section 2.2
149+
@doc """
150+
Returns true if the character is a "reserved" character in a URI.
151+
"""
152+
def char_reserved?(c) do
153+
c in ':/?#[]@!$&\'()*+,;='
154+
end
155+
156+
# RFC3986, section 2.3
157+
@doc """
158+
Returns true if the character is a "unreserved" character in a URI.
159+
"""
160+
def char_unreserved?(c) do
161+
c in ?0..?9 or
162+
c in ?a..?z or
163+
c in ?A..?Z or
164+
c in '~_-.'
165+
end
166+
167+
@doc """
168+
Returns true if the character is allowed unescaped in a URI.
169+
"""
170+
def char_unescaped?(c) do
171+
char_reserved?(c) or char_unreserved?(c)
172+
end
173+
148174
@doc """
149175
Percent-escape a URI.
176+
Accepts `predicate` function as an argument to specify if char can be left as is.
150177
151178
## Example
152179
153-
iex> URI.encode("http://elixir-lang.org/getting_started/2.html")
154-
"http%3A%2F%2Felixir-lang.org%2Fgetting_started%2F2.html"
180+
iex> URI.encode("ftp://s-ite.tld/?value=put it+й")
181+
"ftp://s-ite.tld/?value=put%20it+%D0%B9"
155182
156183
"""
157-
def encode(s), do: for(<<c <- s>>, into: "", do: percent(c))
158-
159-
defp percent(?~), do: <<?~>>
160-
defp percent(?-), do: <<?->>
161-
defp percent(?_), do: <<?_>>
162-
defp percent(?.), do: <<?.>>
163-
164-
defp percent(c)
165-
when c in ?0..?9
166-
when c in ?a..?z
167-
when c in ?A..?Z do
168-
<<c>>
184+
def encode(str, predicate \\ &char_unescaped?/1) do
185+
for <<c <- str>>, into: "", do: percent(c, predicate)
169186
end
170187

171-
defp percent(c), do: "%" <> hex(bsr(c, 4)) <> hex(band(c, 15))
188+
defp percent(c, predicate) do
189+
if predicate.(c) do
190+
<<c>>
191+
else
192+
"%" <> hex(bsr(c, 4)) <> hex(band(c, 15))
193+
end
194+
end
172195

173196
defp hex(n) when n <= 9, do: <<n + ?0>>
174197
defp hex(n), do: <<n + ?A - 10>>

lib/elixir/test/elixir/uri_test.exs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ defmodule URITest do
55

66
test :encode do
77
assert URI.encode("4_test.is-s~") == "4_test.is-s~"
8-
assert URI.encode("\r\n&<%>\" ゆ") == "%0D%0A%26%3C%25%3E%22%20%E3%82%86"
8+
assert URI.encode("\r\n&<%>\" ゆ", &URI.char_unreserved?/1) ==
9+
"%0D%0A%26%3C%25%3E%22%20%E3%82%86"
910
end
1011

1112
test :encode_query do

0 commit comments

Comments
 (0)