aboutsummaryrefslogtreecommitdiffstats
path: root/src/cowboy_http.erl
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2013-10-23 11:21:31 +0200
committerLoïc Hoguin <[email protected]>2013-10-23 16:35:23 +0200
commitfaf64524c6758ae1e27404d2ae1383a23538c538 (patch)
tree1aed9b3434d9b38e67ceca1c1e09cd05f5222967 /src/cowboy_http.erl
parentaab63d605c595d8d0cd33646d13942d6cb372b60 (diff)
downloadcowboy-faf64524c6758ae1e27404d2ae1383a23538c538.tar.gz
cowboy-faf64524c6758ae1e27404d2ae1383a23538c538.tar.bz2
cowboy-faf64524c6758ae1e27404d2ae1383a23538c538.zip
Move cookie parsing/building code to cowlib
The code for parsing has also been rewritten to be more efficient and to be able to handle cookie values with space inside them properly. Update cowlib to 0.2.0.
Diffstat (limited to 'src/cowboy_http.erl')
-rw-r--r--src/cowboy_http.erl211
1 files changed, 0 insertions, 211 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index f2defdc..9f06522 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -19,7 +19,6 @@
%% Parsing.
-export([list/2]).
-export([nonempty_list/2]).
--export([cookie_list/1]).
-export([content_type/1]).
-export([media_range/2]).
-export([conneg/2]).
@@ -46,7 +45,6 @@
-export([ce_identity/1]).
%% Interpretation.
--export([cookie_to_iodata/3]).
-export([urldecode/1]).
-export([urldecode/2]).
-export([urlencode/1]).
@@ -92,76 +90,6 @@ list(Data, Fun, Acc) ->
end)
end).
-%% @doc Parse a list of cookies.
-%%
-%% We need a special function for this because we need to support both
-%% $; and $, as separators as per RFC2109.
--spec cookie_list(binary()) -> [{binary(), binary()}] | {error, badarg}.
-cookie_list(Data) ->
- case cookie_list(Data, []) of
- {error, badarg} -> {error, badarg};
- [] -> {error, badarg};
- L -> lists:reverse(L)
- end.
-
--spec cookie_list(binary(), Acc) -> Acc | {error, badarg}
- when Acc::[{binary(), binary()}].
-cookie_list(Data, Acc) ->
- whitespace(Data,
- fun (<<>>) -> Acc;
- (<< $,, Rest/binary >>) -> cookie_list(Rest, Acc);
- (<< $;, Rest/binary >>) -> cookie_list(Rest, Acc);
- (Rest) -> cookie(Rest,
- fun (Rest2, << $$, _/binary >>, _) ->
- cookie_list(Rest2, Acc);
- (Rest2, Name, Value) ->
- cookie_list(Rest2, [{Name, Value}|Acc])
- end)
- end).
-
--spec cookie(binary(), fun()) -> any().
-cookie(Data, Fun) ->
- whitespace(Data,
- fun (Rest) ->
- cookie_name(Rest,
- fun (_Rest2, <<>>) -> {error, badarg};
- (<< $=, Rest2/binary >>, Name) ->
- cookie_value(Rest2,
- fun (Rest3, Value) ->
- Fun(Rest3, Name, Value)
- end);
- (_Rest2, _Attr) -> {error, badarg}
- end)
- end).
-
--spec cookie_name(binary(), fun()) -> any().
-cookie_name(Data, Fun) ->
- cookie_name(Data, Fun, <<>>).
-
--spec cookie_name(binary(), fun(), binary()) -> any().
-cookie_name(<<>>, Fun, Acc) ->
- Fun(<<>>, Acc);
-cookie_name(Data = << C, _Rest/binary >>, Fun, Acc)
- when C =:= $=; C =:= $,; C =:= $;; C =:= $\s; C =:= $\t;
- C =:= $\r; C =:= $\n; C =:= $\013; C =:= $\014 ->
- Fun(Data, Acc);
-cookie_name(<< C, Rest/binary >>, Fun, Acc) ->
- cookie_name(Rest, Fun, << Acc/binary, C >>).
-
--spec cookie_value(binary(), fun()) -> any().
-cookie_value(Data, Fun) ->
- cookie_value(Data, Fun, <<>>).
-
--spec cookie_value(binary(), fun(), binary()) -> any().
-cookie_value(<<>>, Fun, Acc) ->
- Fun(<<>>, Acc);
-cookie_value(Data = << C, _Rest/binary >>, Fun, Acc)
- when C =:= $,; C =:= $;; C =:= $\s; C =:= $\t;
- C =:= $\r; C =:= $\n; C =:= $\013; C =:= $\014 ->
- Fun(Data, Acc);
-cookie_value(<< C, Rest/binary >>, Fun, Acc) ->
- cookie_value(Rest, Fun, << Acc/binary, C >>).
-
%% @doc Parse a content type.
%%
%% We lowercase the charset header as we know it's case insensitive.
@@ -1025,55 +953,6 @@ ce_identity(Data) ->
%% Interpretation.
-%% @doc Convert a cookie name, value and options to its iodata form.
-%% @end
-%%
-%% Initially from Mochiweb:
-%% * Copyright 2007 Mochi Media, Inc.
-%% Initial binary implementation:
-%% * Copyright 2011 Thomas Burdick <[email protected]>
--spec cookie_to_iodata(iodata(), iodata(), cowboy_req:cookie_opts())
- -> iodata().
-cookie_to_iodata(Name, Value, Opts) ->
- case binary:match(iolist_to_binary(Name), [<<$=>>, <<$,>>, <<$;>>,
- <<$\s>>, <<$\t>>, <<$\r>>, <<$\n>>, <<$\013>>, <<$\014>>]) of
- nomatch -> ok
- end,
- case binary:match(iolist_to_binary(Value), [<<$,>>, <<$;>>,
- <<$\s>>, <<$\t>>, <<$\r>>, <<$\n>>, <<$\013>>, <<$\014>>]) of
- nomatch -> ok
- end,
- MaxAgeBin = case lists:keyfind(max_age, 1, Opts) of
- false -> <<>>;
- {_, 0} ->
- %% MSIE requires an Expires date in the past to delete a cookie.
- <<"; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0">>;
- {_, MaxAge} when is_integer(MaxAge), MaxAge > 0 ->
- UTC = calendar:universal_time(),
- Secs = calendar:datetime_to_gregorian_seconds(UTC),
- Expires = calendar:gregorian_seconds_to_datetime(Secs + MaxAge),
- [<<"; Expires=">>, cowboy_clock:rfc2109(Expires),
- <<"; Max-Age=">>, integer_to_list(MaxAge)]
- end,
- DomainBin = case lists:keyfind(domain, 1, Opts) of
- false -> <<>>;
- {_, Domain} -> [<<"; Domain=">>, Domain]
- end,
- PathBin = case lists:keyfind(path, 1, Opts) of
- false -> <<>>;
- {_, Path} -> [<<"; Path=">>, Path]
- end,
- SecureBin = case lists:keyfind(secure, 1, Opts) of
- false -> <<>>;
- {_, true} -> <<"; Secure">>
- end,
- HttpOnlyBin = case lists:keyfind(http_only, 1, Opts) of
- false -> <<>>;
- {_, true} -> <<"; HttpOnly">>
- end,
- [Name, <<"=">>, Value, <<"; Version=1">>,
- MaxAgeBin, DomainBin, PathBin, SecureBin, HttpOnlyBin].
-
%% @doc Decode a URL encoded binary.
%% @equiv urldecode(Bin, crash)
-spec urldecode(binary()) -> binary().
@@ -1224,38 +1103,6 @@ nonempty_token_list_test_() ->
],
[{V, fun() -> R = nonempty_list(V, fun token/2) end} || {V, R} <- Tests].
-cookie_list_test_() ->
- %% {Value, Result}.
- Tests = [
- {<<"name=value; name2=value2">>, [
- {<<"name">>, <<"value">>},
- {<<"name2">>, <<"value2">>}
- ]},
- {<<"$Version=1; Customer=WILE_E_COYOTE; $Path=/acme">>, [
- {<<"Customer">>, <<"WILE_E_COYOTE">>}
- ]},
- {<<"$Version=1; Customer=WILE_E_COYOTE; $Path=/acme; "
- "Part_Number=Rocket_Launcher_0001; $Path=/acme; "
- "Shipping=FedEx; $Path=/acme">>, [
- {<<"Customer">>, <<"WILE_E_COYOTE">>},
- {<<"Part_Number">>, <<"Rocket_Launcher_0001">>},
- {<<"Shipping">>, <<"FedEx">>}
- ]},
- %% Potential edge cases (initially from Mochiweb).
- {<<"foo=\\x">>, [{<<"foo">>, <<"\\x">>}]},
- {<<"=">>, {error, badarg}},
- {<<" foo ; bar ">>, {error, badarg}},
- {<<"foo=;bar=">>, [{<<"foo">>, <<>>}, {<<"bar">>, <<>>}]},
- {<<"foo=\\\";;bar ">>, {error, badarg}},
- {<<"foo=\\\";;bar=good ">>,
- [{<<"foo">>, <<"\\\"">>}, {<<"bar">>, <<"good">>}]},
- {<<"foo=\"\\\";bar">>, {error, badarg}},
- {<<"">>, {error, badarg}},
- {<<"foo=bar , baz=wibble ">>,
- [{<<"foo">>, <<"bar">>}, {<<"baz">>, <<"wibble">>}]}
- ],
- [{V, fun() -> R = cookie_list(V) end} || {V, R} <- Tests].
-
media_range_list_test_() ->
%% {Tokens, Result}
Tests = [
@@ -1380,64 +1227,6 @@ digits_test_() ->
],
[{V, fun() -> R = digits(V) end} || {V, R} <- Tests].
-cookie_to_iodata_test_() ->
- %% {Name, Value, Opts, Result}
- Tests = [
- {<<"Customer">>, <<"WILE_E_COYOTE">>,
- [{http_only, true}, {domain, <<"acme.com">>}],
- <<"Customer=WILE_E_COYOTE; Version=1; "
- "Domain=acme.com; HttpOnly">>},
- {<<"Customer">>, <<"WILE_E_COYOTE">>,
- [{path, <<"/acme">>}],
- <<"Customer=WILE_E_COYOTE; Version=1; Path=/acme">>},
- {<<"Customer">>, <<"WILE_E_COYOTE">>,
- [{path, <<"/acme">>}, {badoption, <<"negatory">>}],
- <<"Customer=WILE_E_COYOTE; Version=1; Path=/acme">>}
- ],
- [{R, fun() -> R = iolist_to_binary(cookie_to_iodata(N, V, O)) end}
- || {N, V, O, R} <- Tests].
-
-cookie_to_iodata_max_age_test() ->
- F = fun(N, V, O) ->
- binary:split(iolist_to_binary(
- cookie_to_iodata(N, V, O)), <<";">>, [global])
- end,
- [<<"Customer=WILE_E_COYOTE">>,
- <<" Version=1">>,
- <<" Expires=", _/binary>>,
- <<" Max-Age=111">>,
- <<" Secure">>] = F(<<"Customer">>, <<"WILE_E_COYOTE">>,
- [{max_age, 111}, {secure, true}]),
- case catch F(<<"Customer">>, <<"WILE_E_COYOTE">>, [{max_age, -111}]) of
- {'EXIT', {{case_clause, {max_age, -111}}, _}} -> ok
- end,
- [<<"Customer=WILE_E_COYOTE">>,
- <<" Version=1">>,
- <<" Expires=", _/binary>>,
- <<" Max-Age=86417">>] = F(<<"Customer">>, <<"WILE_E_COYOTE">>,
- [{max_age, 86417}]),
- ok.
-
-cookie_to_iodata_failures_test_() ->
- F = fun(N, V) ->
- try cookie_to_iodata(N, V, []) of
- _ ->
- false
- catch _:_ ->
- true
- end
- end,
- Tests = [
- {<<"Na=me">>, <<"Value">>},
- {<<"Name;">>, <<"Value">>},
- {<<"\r\name">>, <<"Value">>},
- {<<"Name">>, <<"Value;">>},
- {<<"Name">>, <<"\value">>}
- ],
- [{iolist_to_binary(io_lib:format("{~p, ~p} failure", [N, V])),
- fun() -> true = F(N, V) end}
- || {N, V} <- Tests].
-
x_www_form_urlencoded_test_() ->
%% {Qs, Result}
Tests = [