diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | rebar.config | 2 | ||||
-rw-r--r-- | src/cowboy_clock.erl | 20 | ||||
-rw-r--r-- | src/cowboy_http.erl | 211 | ||||
-rw-r--r-- | src/cowboy_req.erl | 14 |
5 files changed, 6 insertions, 243 deletions
@@ -11,7 +11,7 @@ PLT_APPS = crypto public_key ssl # Dependencies. DEPS = cowlib ranch -dep_cowlib = pkg://cowlib 0.1.0 +dep_cowlib = pkg://cowlib 0.2.0 dep_ranch = pkg://ranch 0.8.5 TEST_DEPS = ct_helper gun diff --git a/rebar.config b/rebar.config index d31efe7..91179db 100644 --- a/rebar.config +++ b/rebar.config @@ -1,4 +1,4 @@ {deps, [ - {cowlib, ".*", {git, "git://github.com/extend/cowlib.git", "0.1.0"}}, + {cowlib, ".*", {git, "git://github.com/extend/cowlib.git", "0.2.0"}}, {ranch, ".*", {git, "git://github.com/extend/ranch.git", "0.8.5"}} ]}. diff --git a/src/cowboy_clock.erl b/src/cowboy_clock.erl index f21616c..6fb522b 100644 --- a/src/cowboy_clock.erl +++ b/src/cowboy_clock.erl @@ -26,7 +26,6 @@ -export([stop/0]). -export([rfc1123/0]). -export([rfc1123/1]). --export([rfc2109/1]). %% gen_server. -export([init/1]). @@ -67,18 +66,6 @@ rfc1123() -> rfc1123(DateTime) -> update_rfc1123(<<>>, undefined, DateTime). -%% @doc Return the given date and time formatted according to RFC-2109. -%% -%% This format is used in the <em>set-cookie</em> header sent with -%% HTTP responses. --spec rfc2109(calendar:datetime()) -> binary(). -rfc2109({Date = {Y, Mo, D}, {H, Mi, S}}) -> - Wday = calendar:day_of_the_week(Date), - << (weekday(Wday))/binary, ", ", (pad_int(D))/binary, "-", - (month(Mo))/binary, "-", (list_to_binary(integer_to_list(Y)))/binary, - " ", (pad_int(H))/binary, $:, (pad_int(Mi))/binary, - $:, (pad_int(S))/binary, " GMT" >>. - %% gen_server. %% @private @@ -188,13 +175,6 @@ month(12) -> <<"Dec">>. -ifdef(TEST). -rfc2109_test_() -> - Tests = [ - {<<"Sat, 14-May-2011 14:25:33 GMT">>, {{2011, 5, 14}, {14, 25, 33}}}, - {<<"Sun, 01-Jan-2012 00:00:00 GMT">>, {{2012, 1, 1}, { 0, 0, 0}}} - ], - [{R, fun() -> R = rfc2109(D) end} || {R, D} <- Tests]. - update_rfc1123_test_() -> Tests = [ {<<"Sat, 14 May 2011 14:25:33 GMT">>, undefined, 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 = [ diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl index 32ff7b0..34302c4 100644 --- a/src/cowboy_req.erl +++ b/src/cowboy_req.erl @@ -115,10 +115,7 @@ -export([lock/1]). -export([to_list/1]). --type cookie_option() :: {max_age, non_neg_integer()} - | {domain, binary()} | {path, binary()} - | {secure, boolean()} | {http_only, boolean()}. --type cookie_opts() :: [cookie_option()]. +-type cookie_opts() :: cow_cookie:cookie_opts(). -export_type([cookie_opts/0]). -type content_decode_fun() :: fun((binary()) @@ -430,7 +427,7 @@ parse_header(Name = <<"content-length">>, Req, Default) -> parse_header(Name = <<"content-type">>, Req, Default) -> parse_header(Name, Req, Default, fun cowboy_http:content_type/1); parse_header(Name = <<"cookie">>, Req, Default) -> - parse_header(Name, Req, Default, fun cowboy_http:cookie_list/1); + parse_header(Name, Req, Default, fun cow_cookie:parse_cookie/1); parse_header(Name = <<"expect">>, Req, Default) -> parse_header(Name, Req, Default, fun (Value) -> @@ -495,10 +492,7 @@ cookie(Name, Req=#http_req{cookies=undefined}, Default) when is_binary(Name) -> {ok, undefined, Req2} -> {Default, Req2#http_req{cookies=[]}}; {ok, Cookies, Req2} -> - cookie(Name, Req2#http_req{cookies=Cookies}, Default); - %% Flash player incorrectly sends an empty Cookie header. - {error, badarg} -> - {Default, Req#http_req{cookies=[]}} + cookie(Name, Req2#http_req{cookies=Cookies}, Default) end; cookie(Name, Req, Default) -> case lists:keyfind(Name, 1, Req#http_req.cookies) of @@ -854,7 +848,7 @@ multipart_skip(Req) -> -spec set_resp_cookie(iodata(), iodata(), cookie_opts(), Req) -> Req when Req::req(). set_resp_cookie(Name, Value, Opts, Req) -> - Cookie = cowboy_http:cookie_to_iodata(Name, Value, Opts), + Cookie = cow_cookie:setcookie(Name, Value, Opts), set_resp_header(<<"set-cookie">>, Cookie, Req). %% @doc Add a header to the response. |