diff options
Diffstat (limited to 'src/cowboy_http.erl')
-rw-r--r-- | src/cowboy_http.erl | 106 |
1 files changed, 76 insertions, 30 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index 32b0ca9..93b83e5 100644 --- a/src/cowboy_http.erl +++ b/src/cowboy_http.erl @@ -17,14 +17,14 @@ -module(cowboy_http). %% Parsing. --export([list/2, nonempty_list/2, content_type/1, content_type_params/3, - media_range/2, conneg/2, language_range/2, entity_tag_match/1, +-export([list/2, nonempty_list/2, content_type/1, media_range/2, conneg/2, + language_range/2, entity_tag_match/1, expectation/2, params/2, http_date/1, rfc1123_date/1, rfc850_date/1, asctime_date/1, whitespace/2, digits/1, token/2, token_ci/2, quoted_string/2]). %% Interpretation. -export([connection_to_atom/1, urldecode/1, urldecode/2, urlencode/1, - urlencode/2]). + urlencode/2, x_www_form_urlencoded/2]). -type method() :: 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | binary(). @@ -98,33 +98,9 @@ list(Data, Fun, Acc) -> content_type(Data) -> media_type(Data, fun (Rest, Type, SubType) -> - content_type_params(Rest, - fun (Params) -> {Type, SubType, Params} end, []) - end). - --spec content_type_params(binary(), fun(), list({binary(), binary()})) - -> any(). -content_type_params(Data, Fun, Acc) -> - whitespace(Data, - fun (<< $;, Rest/binary >>) -> content_type_param(Rest, Fun, Acc); - (<<>>) -> Fun(lists:reverse(Acc)); - (_Rest) -> {error, badarg} - end). - --spec content_type_param(binary(), fun(), list({binary(), binary()})) - -> any(). -content_type_param(Data, Fun, Acc) -> - whitespace(Data, - fun (Rest) -> - token_ci(Rest, - fun (_Rest2, <<>>) -> {error, badarg}; - (<< $=, Rest2/binary >>, Attr) -> - word(Rest2, - fun (Rest3, Value) -> - content_type_params(Rest3, Fun, - [{Attr, Value}|Acc]) - end); - (_Rest2, _Attr) -> {error, badarg} + params(Rest, + fun (<<>>, Params) -> {Type, SubType, Params}; + (_Rest2, _) -> {error, badarg} end) end). @@ -319,6 +295,50 @@ opaque_tag(Data, Fun, Strength) -> (Rest, OpaqueTag) -> Fun(Rest, {Strength, OpaqueTag}) end). +%% @doc Parse an expectation. +-spec expectation(binary(), fun()) -> any(). +expectation(Data, Fun) -> + token_ci(Data, + fun (_Rest, <<>>) -> {error, badarg}; + (<< $=, Rest/binary >>, Expectation) -> + word(Rest, + fun (Rest2, ExtValue) -> + params(Rest2, fun (Rest3, ExtParams) -> + Fun(Rest3, {Expectation, ExtValue, ExtParams}) + end) + end); + (Rest, Expectation) -> + Fun(Rest, Expectation) + end). + +%% @doc Parse a list of parameters (a=b;c=d). +-spec params(binary(), fun()) -> any(). +params(Data, Fun) -> + params(Data, Fun, []). + +-spec params(binary(), fun(), [{binary(), binary()}]) -> any(). +params(Data, Fun, Acc) -> + whitespace(Data, + fun (<< $;, Rest/binary >>) -> param(Rest, Fun, Acc); + (Rest) -> Fun(Rest, lists:reverse(Acc)) + end). + +-spec param(binary(), fun(), [{binary(), binary()}]) -> any(). +param(Data, Fun, Acc) -> + whitespace(Data, + fun (Rest) -> + token_ci(Rest, + fun (_Rest2, <<>>) -> {error, badarg}; + (<< $=, Rest2/binary >>, Attr) -> + word(Rest2, + fun (Rest3, Value) -> + params(Rest3, Fun, + [{Attr, Value}|Acc]) + end); + (_Rest2, _Attr) -> {error, badarg} + end) + end). + %% @doc Parse an HTTP date (RFC1123, RFC850 or asctime date). %% @end %% @@ -780,6 +800,16 @@ tohexu(C) when C < 17 -> $A + C - 10. tohexl(C) when C < 10 -> $0 + C; tohexl(C) when C < 17 -> $a + C - 10. +-spec x_www_form_urlencoded(binary(), fun((binary()) -> binary())) -> + list({binary(), binary() | true}). +x_www_form_urlencoded(<<>>, _URLDecode) -> + []; +x_www_form_urlencoded(Qs, URLDecode) -> + Tokens = binary:split(Qs, <<"&">>, [global, trim]), + [case binary:split(Token, <<"=">>) of + [Token] -> {URLDecode(Token), true}; + [Name, Value] -> {URLDecode(Name), URLDecode(Value)} + end || Token <- Tokens]. %% Tests. @@ -947,6 +977,22 @@ digits_test_() -> ], [{V, fun() -> R = digits(V) end} || {V, R} <- Tests]. +x_www_form_urlencoded_test_() -> + %% {Qs, Result} + Tests = [ + {<<"">>, []}, + {<<"a=b">>, [{<<"a">>, <<"b">>}]}, + {<<"aaa=bbb">>, [{<<"aaa">>, <<"bbb">>}]}, + {<<"a&b">>, [{<<"a">>, true}, {<<"b">>, true}]}, + {<<"a=b&c&d=e">>, [{<<"a">>, <<"b">>}, + {<<"c">>, true}, {<<"d">>, <<"e">>}]}, + {<<"a=b=c=d=e&f=g">>, [{<<"a">>, <<"b=c=d=e">>}, {<<"f">>, <<"g">>}]}, + {<<"a+b=c+d">>, [{<<"a b">>, <<"c d">>}]} + ], + URLDecode = fun urldecode/1, + [{Qs, fun() -> R = x_www_form_urlencoded( + Qs, URLDecode) end} || {Qs, R} <- Tests]. + urldecode_test_() -> U = fun urldecode/2, [?_assertEqual(<<" ">>, U(<<"%20">>, crash)), |