aboutsummaryrefslogtreecommitdiffstats
path: root/src/cowboy_http.erl
diff options
context:
space:
mode:
authorMagnus Klaar <[email protected]>2011-12-05 01:08:38 +0100
committerMagnus Klaar <[email protected]>2011-12-07 19:02:10 +0100
commitc747efbd7533c3b4dd7caa267070c36608c4c0d2 (patch)
treeeef8cf0ca68d0ed63229b013160a2dac8e77bf2e /src/cowboy_http.erl
parenta12a910341dd22bd27096b50edf3d9820bc90384 (diff)
downloadcowboy-c747efbd7533c3b4dd7caa267070c36608c4c0d2.tar.gz
cowboy-c747efbd7533c3b4dd7caa267070c36608c4c0d2.tar.bz2
cowboy-c747efbd7533c3b4dd7caa267070c36608c4c0d2.zip
replace quoted:from_url with cowboy_http:urldecode
This change makes the dependency on quoted optional by adding a minimal urldecode function to cowboy. A protocol option for setting the urldecoding function has been added to the cowboy_http_protocol module. The default value for this option is set to be equivalent to the default settings for quoted. {fun cowboy_http:urldecode/2, crash} A note has been added in the README to document how to use quoted instead of this function. A field to store this option value has been added to the state record in the cowboy_http_protocol module and the http_req record in include/http.hrl Functions that previously used quoted:from_url/1 has been updated to require an equivalent function in addition to the previously required arguments. This change removes a C compiler from the build requirements of cowboy. It also removes the requirement to cross compile the code if the target arch/OS is different from the arch/OS used to build it.
Diffstat (limited to 'src/cowboy_http.erl')
-rw-r--r--src/cowboy_http.erl51
1 files changed, 50 insertions, 1 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index 4bb7c2c..fd0d142 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -23,7 +23,7 @@
digits/1, token/2, token_ci/2, quoted_string/2]).
%% Interpretation.
--export([connection_to_atom/1]).
+-export([connection_to_atom/1, urldecode/1, urldecode/2]).
-include("include/http.hrl").
-include_lib("eunit/include/eunit.hrl").
@@ -670,6 +670,46 @@ connection_to_atom([<<"close">>|_Tail]) ->
connection_to_atom([_Any|Tail]) ->
connection_to_atom(Tail).
+%% @doc Decode a URL encoded binary.
+%% @equiv urldecode(Bin, crash)
+-spec urldecode(binary()) -> binary().
+urldecode(Bin) when is_binary(Bin) ->
+ urldecode(Bin, <<>>, crash).
+
+%% @doc Decode a URL encoded binary.
+%% The second argument specifies how to handle percent characters that are not
+%% followed by two valid hex characters. Use `skip' to ignore such errors,
+%% if `crash' is used the function will fail with the reason `badarg'.
+-spec urldecode(binary(), crash | skip) -> binary().
+urldecode(Bin, OnError) when is_binary(Bin) ->
+ urldecode(Bin, <<>>, OnError).
+
+-spec urldecode(binary(), binary(), crash | skip) -> binary().
+urldecode(<<$%, H, L, Rest/binary>>, Acc, OnError) ->
+ G = unhex(H),
+ M = unhex(L),
+ if G =:= error; M =:= error ->
+ case OnError of skip -> ok; crash -> erlang:error(badarg) end,
+ urldecode(<<H, L, Rest/binary>>, <<Acc/binary, $%>>, OnError);
+ true ->
+ urldecode(Rest, <<Acc/binary, (G bsl 4 bor M)>>, OnError)
+ end;
+urldecode(<<$%, Rest/binary>>, Acc, OnError) ->
+ case OnError of skip -> ok; crash -> erlang:error(badarg) end,
+ urldecode(Rest, <<Acc/binary, $%>>, OnError);
+urldecode(<<$+, Rest/binary>>, Acc, OnError) ->
+ urldecode(Rest, <<Acc/binary, $ >>, OnError);
+urldecode(<<C, Rest/binary>>, Acc, OnError) ->
+ urldecode(Rest, <<Acc/binary, C>>, OnError);
+urldecode(<<>>, Acc, _OnError) ->
+ Acc.
+
+-spec unhex(byte()) -> byte() | error.
+unhex(C) when C >= $0, C =< $9 -> C - $0;
+unhex(C) when C >= $A, C =< $F -> C - $A + 10;
+unhex(C) when C >= $a, C =< $f -> C - $a + 10;
+unhex(_) -> error.
+
%% Tests.
-ifdef(TEST).
@@ -836,4 +876,13 @@ digits_test_() ->
],
[{V, fun() -> R = digits(V) end} || {V, R} <- Tests].
+urldecode_test_() ->
+ Tests = [
+ {<<" ">>, <<"%20">>},
+ {<<" ">>, <<"+">>},
+ {<<0>>, <<"%00">>},
+ {<<255>>, <<"%fF">>}
+ ],
+ [{I, ?_assertEqual(E, urldecode(I))} || {E, I} <- Tests].
+
-endif.