@@ -58,7 +58,7 @@ defmodule URI do
5858 new URIs.
5959 """
6060 @ spec default_port ( binary , pos_integer ) :: :ok
61- def default_port ( scheme , port ) when is_binary ( scheme ) and port > 0 do
61+ def default_port ( scheme , port ) when is_binary ( scheme ) and is_integer ( port ) and port > 0 do
6262 :elixir_config . put ( { :uri , scheme } , port )
6363 end
6464
@@ -88,7 +88,22 @@ defmodule URI do
8888
8989 """
9090 @ spec encode_query ( term ) :: binary
91- def encode_query ( l ) , do: Enum . map_join ( l , "&" , & pair / 1 )
91+ def encode_query ( enumerable ) do
92+ Enum . map_join ( enumerable , "&" , & encode_kv_pair / 1 )
93+ end
94+
95+ defp encode_kv_pair ( { key , _ } ) when is_list ( key ) do
96+ raise ArgumentError , "encode_query/1 keys cannot be lists, got: #{ inspect key } "
97+ end
98+
99+ defp encode_kv_pair ( { _ , value } ) when is_list ( value ) do
100+ raise ArgumentError , "encode_query/1 values cannot be lists, got: #{ inspect value } "
101+ end
102+
103+ defp encode_kv_pair ( { key , value } ) do
104+ encode_www_form ( Kernel . to_string ( key ) ) <>
105+ "=" <> encode_www_form ( Kernel . to_string ( value ) )
106+ end
92107
93108 @ doc """
94109 Decodes a query string into a map.
@@ -110,33 +125,37 @@ defmodule URI do
110125
111126 """
112127 @ spec decode_query ( binary , map ) :: map
113- def decode_query ( q , map \\ % { } )
128+ def decode_query ( query , map \\ % { } )
114129
115- def decode_query ( q , % { __struct__: _ } = dict ) when is_binary ( q ) do
130+ def decode_query ( query , % { __struct__: _ } = dict ) when is_binary ( query ) do
116131 IO . warn "URI.decode_query/2 is deprecated, please use URI.decode_query/1"
117- decode_query_dict ( q , dict )
132+ decode_query_into_dict ( query , dict )
118133 end
119134
120- def decode_query ( q , map ) when is_binary ( q ) and is_map ( map ) do
121- decode_query_map ( q , map )
135+ def decode_query ( query , map ) when is_binary ( query ) and is_map ( map ) do
136+ decode_query_into_map ( query , map )
122137 end
123138
124- def decode_query ( q , dict ) when is_binary ( q ) do
139+ def decode_query ( query , dict ) when is_binary ( query ) do
125140 IO . warn "URI.decode_query/2 is deprecated, please use URI.decode_query/1"
126- decode_query_dict ( q , dict )
141+ decode_query_into_dict ( query , dict )
127142 end
128143
129- defp decode_query_map ( q , map ) do
130- case do_decode_query ( q ) do
131- nil -> map
132- { { k , v } , q } -> decode_query_map ( q , Map . put ( map , k , v ) )
144+ defp decode_query_into_map ( query , map ) do
145+ case decode_next_query_pair ( query ) do
146+ nil ->
147+ map
148+ { { key , value } , rest } ->
149+ decode_query_into_map ( rest , Map . put ( map , key , value ) )
133150 end
134151 end
135152
136- defp decode_query_dict ( q , dict ) do
137- case do_decode_query ( q ) do
138- nil -> dict
139- { { k , v } , q } -> decode_query_dict ( q , Dict . put ( dict , k , v ) )
153+ defp decode_query_into_dict ( query , dict ) do
154+ case decode_next_query_pair ( query ) do
155+ nil ->
156+ dict
157+ { { key , value } , rest } ->
158+ decode_query_into_dict ( rest , Dict . put ( dict , key , value ) )
140159 end
141160 end
142161
@@ -153,43 +172,28 @@ defmodule URI do
153172
154173 """
155174 @ spec query_decoder ( binary ) :: Enumerable . t
156- def query_decoder ( q ) when is_binary ( q ) do
157- Stream . unfold ( q , & do_decode_query / 1 )
175+ def query_decoder ( query ) when is_binary ( query ) do
176+ Stream . unfold ( query , & decode_next_query_pair / 1 )
158177 end
159178
160- defp do_decode_query ( "" ) do
179+ defp decode_next_query_pair ( "" ) do
161180 nil
162181 end
163182
164- defp do_decode_query ( q ) do
165- { first , next } =
166- case :binary . split ( q , "&" ) do
167- [ first , rest ] -> { first , rest }
168- [ first ] -> { first , "" }
183+ defp decode_next_query_pair ( query ) do
184+ { undecoded_next_pair , rest } =
185+ case :binary . split ( query , "&" ) do
186+ [ next_pair , rest ] -> { next_pair , rest }
187+ [ next_pair ] -> { next_pair , "" }
169188 end
170189
171- current =
172- case :binary . split ( first , "=" ) do
173- [ key , value ] ->
174- { decode_www_form ( key ) , decode_www_form ( value ) }
175- [ key ] ->
176- { decode_www_form ( key ) , nil }
190+ next_pair =
191+ case :binary . split ( undecoded_next_pair , "=" ) do
192+ [ key , value ] -> { decode_www_form ( key ) , decode_www_form ( value ) }
193+ [ key ] -> { decode_www_form ( key ) , nil }
177194 end
178195
179- { current , next }
180- end
181-
182- defp pair ( { k , _ } ) when is_list ( k ) do
183- raise ArgumentError , "encode_query/1 keys cannot be lists, got: #{ inspect k } "
184- end
185-
186- defp pair ( { _ , v } ) when is_list ( v ) do
187- raise ArgumentError , "encode_query/1 values cannot be lists, got: #{ inspect v } "
188- end
189-
190- defp pair ( { k , v } ) do
191- encode_www_form ( Kernel . to_string ( k ) ) <>
192- "=" <> encode_www_form ( Kernel . to_string ( v ) )
196+ { next_pair , rest }
193197 end
194198
195199 @ doc """
@@ -204,9 +208,9 @@ defmodule URI do
204208 true
205209
206210 """
207- @ spec char_reserved? ( term ) :: boolean
208- def char_reserved? ( c ) do
209- c in ':/?#[]@!$&\' ()*+,;='
211+ @ spec char_reserved? ( char ) :: boolean
212+ def char_reserved? ( char ) when char in 0 .. 0x10ffff do
213+ char in ':/?#[]@!$&\' ()*+,;='
210214 end
211215
212216 @ doc """
@@ -221,12 +225,12 @@ defmodule URI do
221225 true
222226
223227 """
224- @ spec char_unreserved? ( term ) :: boolean
225- def char_unreserved? ( c ) do
226- c in ?0 .. ?9 or
227- c in ?a .. ?z or
228- c in ?A .. ?Z or
229- c in '~_-.'
228+ @ spec char_unreserved? ( char ) :: boolean
229+ def char_unreserved? ( char ) when char in 0 .. 0x10ffff do
230+ char in ?0 .. ?9 or
231+ char in ?a .. ?z or
232+ char in ?A .. ?Z or
233+ char in '~_-.'
230234 end
231235
232236 @ doc """
@@ -241,9 +245,9 @@ defmodule URI do
241245 false
242246
243247 """
244- @ spec char_unescaped? ( term ) :: boolean
245- def char_unescaped? ( c ) do
246- char_reserved? ( c ) or char_unreserved? ( c )
248+ @ spec char_unescaped? ( char ) :: boolean
249+ def char_unescaped? ( char ) when char in 0 .. 0x10ffff do
250+ char_reserved? ( char ) or char_unreserved? ( char )
247251 end
248252
249253 @ doc """
@@ -264,8 +268,9 @@ defmodule URI do
264268
265269 """
266270 @ spec encode ( binary , ( byte -> boolean ) ) :: binary
267- def encode ( str , predicate \\ & char_unescaped? / 1 ) when is_binary ( str ) do
268- for << c <- str >> , into: "" , do: percent ( c , predicate )
271+ def encode ( string , predicate \\ & char_unescaped? / 1 )
272+ when is_binary ( string ) and is_function ( predicate , 1 ) do
273+ for << char <- string >> , into: "" , do: percent ( char , predicate )
269274 end
270275
271276 @ doc """
@@ -278,20 +283,20 @@ defmodule URI do
278283
279284 """
280285 @ spec encode_www_form ( binary ) :: binary
281- def encode_www_form ( str ) when is_binary ( str ) do
282- for << c <- str >> , into: "" do
283- case percent ( c , & char_unreserved? / 1 ) do
286+ def encode_www_form ( string ) when is_binary ( string ) do
287+ for << char <- string >> , into: "" do
288+ case percent ( char , & char_unreserved? / 1 ) do
284289 "%20" -> "+"
285- pct -> pct
290+ percent -> percent
286291 end
287292 end
288293 end
289294
290- defp percent ( c , predicate ) do
291- if predicate . ( c ) do
292- << c >>
295+ defp percent ( char , predicate ) do
296+ if predicate . ( char ) do
297+ << char >>
293298 else
294- "%" <> hex ( bsr ( c , 4 ) ) <> hex ( band ( c , 15 ) )
299+ "%" <> hex ( bsr ( char , 4 ) ) <> hex ( band ( char , 15 ) )
295300 end
296301 end
297302
@@ -325,11 +330,11 @@ defmodule URI do
325330
326331 """
327332 @ spec decode_www_form ( binary ) :: binary
328- def decode_www_form ( str ) do
329- unpercent ( str , "" , true )
333+ def decode_www_form ( string ) do
334+ unpercent ( string , "" , true )
330335 catch
331336 :malformed_uri ->
332- raise ArgumentError , "malformed URI #{ inspect str } "
337+ raise ArgumentError , "malformed URI #{ inspect string } "
333338 end
334339
335340 defp unpercent ( << ?+ , tail :: binary >> , acc , spaces = true ) do
@@ -392,15 +397,15 @@ defmodule URI do
392397
393398 def parse ( % URI { } = uri ) , do: uri
394399
395- def parse ( s ) when is_binary ( s ) do
400+ def parse ( string ) when is_binary ( string ) do
396401 # From http://tools.ietf.org/html/rfc3986#appendix-B
397402 regex = ~r/ ^(([a-z][a-z0-9\+ \- \. ]*):)?(\/ \/ ([^\/ ?#]*))?([^?#]*)(\? ([^#]*))?(#(.*))?/ i
398- parts = nillify ( Regex . run ( regex , s ) )
403+ parts = nillify ( Regex . run ( regex , string ) )
399404
400405 destructure [ _ , _ , scheme , _ , authority , path , _ , query , _ , fragment ] , parts
401406 { userinfo , host , port } = split_authority ( authority )
402407
403- scheme = normalize_scheme ( scheme )
408+ scheme = scheme && String . downcase ( scheme )
404409 port = port || ( scheme && default_port ( scheme ) )
405410
406411 % URI {
@@ -411,9 +416,8 @@ defmodule URI do
411416 end
412417
413418 # Split an authority into its userinfo, host and port parts.
414- defp split_authority ( s ) do
415- s = s || ""
416- components = Regex . run ~r/ (^(.*)@)?(\[ [a-zA-Z0-9:.]*\] |[^:]*)(:(\d *))?/ , s
419+ defp split_authority ( string ) do
420+ components = Regex . run ( ~r/ (^(.*)@)?(\[ [a-zA-Z0-9:.]*\] |[^:]*)(:(\d *))?/ , string || "" )
417421
418422 destructure [ _ , _ , userinfo , host , _ , port ] , nillify ( components )
419423 host = if host , do: host |> String . trim_leading ( "[" ) |> String . trim_trailing ( "]" )
@@ -422,14 +426,11 @@ defmodule URI do
422426 { userinfo , host , port }
423427 end
424428
425- defp normalize_scheme ( nil ) , do: nil
426- defp normalize_scheme ( scheme ) , do: String . downcase ( scheme )
427-
428429 # Regex.run returns empty strings sometimes. We want
429430 # to replace those with nil for consistency.
430- defp nillify ( l ) do
431- for s <- l do
432- if byte_size ( s ) > 0 , do: s
431+ defp nillify ( list ) do
432+ for string <- list do
433+ if byte_size ( string ) > 0 , do: string
433434 end
434435 end
435436
0 commit comments