Просмотр исходного кода

add cowboy_http:urlencode/2 and urlencode/1

This function complements the cowboy_http:urldecode/2
and urldecode/1 functions. We should have this encoding
covered now. urldecode is only expected to be invoked
by user code, no further changes needed to integrate this.
Magnus Klaar 13 лет назад
Родитель
Сommit
ef7b41c8ce
1 измененных файлов с 69 добавлено и 8 удалено
  1. 69 8
      src/cowboy_http.erl

+ 69 - 8
src/cowboy_http.erl

@@ -23,7 +23,8 @@
 	digits/1, token/2, token_ci/2, quoted_string/2]).
 	digits/1, token/2, token_ci/2, quoted_string/2]).
 
 
 %% Interpretation.
 %% Interpretation.
--export([connection_to_atom/1, urldecode/1, urldecode/2]).
+-export([connection_to_atom/1, urldecode/1, urldecode/2, urlencode/1,
+	urlencode/2]).
 
 
 -include("include/http.hrl").
 -include("include/http.hrl").
 -include_lib("eunit/include/eunit.hrl").
 -include_lib("eunit/include/eunit.hrl").
@@ -710,6 +711,51 @@ unhex(C) when C >= $A, C =< $F -> C - $A + 10;
 unhex(C) when C >= $a, C =< $f -> C - $a + 10;
 unhex(C) when C >= $a, C =< $f -> C - $a + 10;
 unhex(_) -> error.
 unhex(_) -> error.
 
 
+
+%% @doc URL encode a string binary.
+%% @equiv urlencode(Bin, [])
+-spec urlencode(binary()) -> binary().
+urlencode(Bin) ->
+	urlencode(Bin, []).
+
+%% @doc URL encode a string binary.
+%% The `noplus' option disables the default behaviour of quoting space
+%% characters, `\s', as `+'. The `upper' option overrides the default behaviour
+%% of writing hex numbers using lowecase letters to using uppercase letters
+%% instead.
+-spec urlencode(binary(), [noplus|upper]) -> binary().
+urlencode(Bin, Opts) ->
+	Plus = not proplists:get_value(noplus, Opts, false),
+	Upper = proplists:get_value(upper, Opts, false),
+	urlencode(Bin, <<>>, Plus, Upper).
+
+-spec urlencode(binary(), binary(), boolean(), boolean()) -> binary().
+urlencode(<<C, Rest/binary>>, Acc, P=Plus, U=Upper) ->
+	if	C >= $0, C =< $9 -> urlencode(Rest, <<Acc/binary, C>>, P, U);
+		C >= $A, C =< $Z -> urlencode(Rest, <<Acc/binary, C>>, P, U);
+		C >= $a, C =< $z -> urlencode(Rest, <<Acc/binary, C>>, P, U);
+		C =:= $.; C =:= $-; C =:= $~; C =:= $_ ->
+		urlencode(Rest, <<Acc/binary, C>>, P, U);
+		C =:= $ , Plus ->
+		urlencode(Rest, <<Acc/binary, $+>>, P, U);
+		true ->
+		H = C band 16#F0 bsr 4, L = C band 16#0F,
+		H1 = if Upper -> tohexu(H); true -> tohexl(H) end,
+		L1 = if Upper -> tohexu(L); true -> tohexl(L) end,
+		urlencode(Rest, <<Acc/binary, $%, H1, L1>>, P, U)
+	end;
+urlencode(<<>>, Acc, _Plus, _Upper) ->
+	Acc.
+
+-spec tohexu(byte()) -> byte().
+tohexu(C) when C < 10 -> $0 + C;
+tohexu(C) when C < 17 -> $A + C - 10.
+
+-spec tohexl(byte()) -> byte().
+tohexl(C) when C < 10 -> $0 + C;
+tohexl(C) when C < 17 -> $a + C - 10.
+
+
 %% Tests.
 %% Tests.
 
 
 -ifdef(TEST).
 -ifdef(TEST).
@@ -877,12 +923,27 @@ digits_test_() ->
 	[{V, fun() -> R = digits(V) end} || {V, R} <- Tests].
 	[{V, fun() -> R = digits(V) end} || {V, R} <- Tests].
 
 
 urldecode_test_() ->
 urldecode_test_() ->
-	Tests = [
-		{<<" ">>, <<"%20">>},
-		{<<" ">>, <<"+">>},
-		{<<0>>, <<"%00">>},
-		{<<255>>, <<"%fF">>}
-	],
-	[{I, ?_assertEqual(E, urldecode(I))} || {E, I} <- Tests].
+	U = fun urldecode/2,
+	[?_assertEqual(<<" ">>, U(<<"%20">>, crash)),
+	 ?_assertEqual(<<" ">>, U(<<"+">>, crash)),
+	 ?_assertEqual(<<0>>, U(<<"%00">>, crash)),
+	 ?_assertEqual(<<255>>, U(<<"%fF">>, crash)),
+	 ?_assertEqual(<<"123">>, U(<<"123">>, crash)),
+	 ?_assertEqual(<<"%i5">>, U(<<"%i5">>, skip)),
+	 ?_assertEqual(<<"%5">>, U(<<"%5">>, skip)),
+	 ?_assertError(badarg, U(<<"%i5">>, crash)),
+	 ?_assertError(badarg, U(<<"%5">>, crash))
+	].
+
+urlencode_test_() ->
+	U = fun urlencode/2,
+	[?_assertEqual(<<"%ff%00">>, U(<<255,0>>, [])),
+	 ?_assertEqual(<<"%FF%00">>, U(<<255,0>>, [upper])),
+	 ?_assertEqual(<<"+">>, U(<<" ">>, [])),
+	 ?_assertEqual(<<"%20">>, U(<<" ">>, [noplus])),
+	 ?_assertEqual(<<"aBc">>, U(<<"aBc">>, [])),
+	 ?_assertEqual(<<".-~_">>, U(<<".-~_">>, [])),
+	 ?_assertEqual(<<"%ff+">>, urlencode(<<255, " ">>))
+	].
 
 
 -endif.
 -endif.