Skip to content

Commit

Permalink
Merge pull request elixir-lang#284 from alco/uri-query-parsing
Browse files Browse the repository at this point in the history
Implement decode_query in URI
  • Loading branch information
josevalim committed May 6, 2012
2 parents da67254 + e31cca0 commit 463c588
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
31 changes: 31 additions & 0 deletions lib/uri.ex
Expand Up @@ -21,6 +21,37 @@ defmodule URI do
"""
def encode_query(l), do: Enum.join(Enum.map(l, pair(&1)), "&")

@doc """
Given a query string of the form "key1=value1&key=value2...", produces an
orddict with one entry for each key-value pair. Each key and value will be a
binary. It also does percent-unescaping of both keys and values.
Returns nil if the query string is malformed.
"""
def decode_query(q) do
# If the string is blank, return an empty dict
empty_dict = Orddict.new
if Regex.match?(%r"^\s*$", q) do
empty_dict
else:
parts = Regex.split %r/&/, to_binary(q)
# Set up a try block to return quickly from List.foldl in case of an error
try do
List.foldl parts, empty_dict, fn(kvstr, dict) ->
pair = case Regex.split(%r/=/, kvstr) do
match: [ key, value ] when size(key) > 0
{ decode(key), decode(value) }
else:
throw { :error, "Malformed query string" }
end
Dict.Orddict.Record.put dict, pair
end
catch: x
x
end
end
end

defp pair({k, v}) do
encode(to_binary(k)) <> "=" <> encode(to_binary(v))
end
Expand Down
15 changes: 15 additions & 0 deletions test/elixir/uri_test.exs
Expand Up @@ -28,6 +28,21 @@ defmodule URITest do
assert URI.encode_query([{:foo, 'bar'}]) == "foo=bar"
end

test :decode_query do
error = { :error, "Malformed query string" }

assert URI.decode_query("q=search%20query&cookie=ab%26cd&block%20buster=") ==
Orddict.new [{"block buster", ""}, {"cookie", "ab&cd"}, {"q", "search query"}]
assert URI.decode_query("") == Orddict.new
assert URI.decode_query('list=works') == Orddict.new [{"list", "works"}]
assert URI.decode_query("garbage") == error
assert URI.decode_query("=value") == error

assert URI.decode_query("something=weird=happening") == error
assert URI.decode_query("something=weird%3Dhappening") == Orddict.new [{"something", "weird=happening"}]

end

test :decode do
data_to_be_decoded = "%26%3C%3E%22+%E3%82%86%E3%82%93%E3%82%86%E3%82%93"
assert URI.decode(data_to_be_decoded) == "&<>\" ゆんゆん"
Expand Down

0 comments on commit 463c588

Please sign in to comment.