Skip to content

Commit

Permalink
Implement decode_query in URI
Browse files Browse the repository at this point in the history
  • Loading branch information
alco committed May 6, 2012
1 parent da67254 commit fa96466
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 0 deletions.
27 changes: 27 additions & 0 deletions lib/uri.ex
Expand Up @@ -21,6 +21,33 @@ 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
parts = Regex.split %r/&/, q
# Set up a try block to return quickly from List.foldl in case of an error
try do
List.foldl parts, Orddict.new, fn(kvstr, dict) ->
pair = case Regex.split(%r/=/, kvstr) do
match: [ key, value ]
{ decode(key), decode(value) }
match: [ key ]
{ decode(key), "" }
else:
raise "bad query"
end
Dict.Orddict.Record.put dict, pair
end
rescue: RuntimeError
nil
end
end

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

test :decode_query do
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("something=weird=happening") == nil
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 fa96466

Please sign in to comment.