aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cowboy_http.erl177
-rw-r--r--src/cowboy_http_rest.erl42
-rw-r--r--src/cowboy_http_websocket.erl4
3 files changed, 153 insertions, 70 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index fd0d142..99536a3 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -23,7 +23,8 @@
digits/1, token/2, token_ci/2, quoted_string/2]).
%% 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_lib("eunit/include/eunit.hrl").
@@ -57,11 +58,11 @@ list(Data, Fun) ->
list(Data, Fun, Acc) ->
whitespace(Data,
fun (<<>>) -> Acc;
- (<< $,, Rest/bits >>) -> list(Rest, Fun, Acc);
+ (<< $,, Rest/binary >>) -> list(Rest, Fun, Acc);
(Rest) -> Fun(Rest,
fun (D, I) -> whitespace(D,
fun (<<>>) -> [I|Acc];
- (<< $,, R/bits >>) -> list(R, Fun, [I|Acc]);
+ (<< $,, R/binary >>) -> list(R, Fun, [I|Acc]);
(_Any) -> {error, badarg}
end)
end)
@@ -80,7 +81,7 @@ content_type(Data) ->
-> any().
content_type_params(Data, Fun, Acc) ->
whitespace(Data,
- fun (<< $;, Rest/bits >>) -> content_type_param(Rest, Fun, Acc);
+ fun (<< $;, Rest/binary >>) -> content_type_param(Rest, Fun, Acc);
(<<>>) -> Fun(lists:reverse(Acc));
(_Rest) -> {error, badarg}
end).
@@ -92,7 +93,7 @@ content_type_param(Data, Fun, Acc) ->
fun (Rest) ->
token_ci(Rest,
fun (_Rest2, <<>>) -> {error, badarg};
- (<< $=, Rest2/bits >>, Attr) ->
+ (<< $=, Rest2/binary >>, Attr) ->
word(Rest2,
fun (Rest3, Value) ->
content_type_params(Rest3, Fun,
@@ -114,7 +115,7 @@ media_range(Data, Fun) ->
[{binary(), binary()}]) -> any().
media_range_params(Data, Fun, Type, SubType, Acc) ->
whitespace(Data,
- fun (<< $;, Rest/bits >>) ->
+ fun (<< $;, Rest/binary >>) ->
whitespace(Rest,
fun (Rest2) ->
media_range_param_attr(Rest2, Fun, Type, SubType, Acc)
@@ -127,7 +128,7 @@ media_range_params(Data, Fun, Type, SubType, Acc) ->
media_range_param_attr(Data, Fun, Type, SubType, Acc) ->
token_ci(Data,
fun (_Rest, <<>>) -> {error, badarg};
- (<< $=, Rest/bits >>, Attr) ->
+ (<< $=, Rest/binary >>, Attr) ->
media_range_param_value(Rest, Fun, Type, SubType, Acc, Attr)
end).
@@ -150,7 +151,7 @@ media_range_param_value(Data, Fun, Type, SubType, Acc, Attr) ->
media_type(Data, Fun) ->
token_ci(Data,
fun (_Rest, <<>>) -> {error, badarg};
- (<< $/, Rest/bits >>, Type) ->
+ (<< $/, Rest/binary >>, Type) ->
token_ci(Rest,
fun (_Rest2, <<>>) -> {error, badarg};
(Rest2, SubType) -> Fun(Rest2, Type, SubType)
@@ -163,7 +164,7 @@ media_type(Data, Fun) ->
[{binary(), binary()} | binary()]) -> any().
accept_ext(Data, Fun, Type, SubType, Params, Quality, Acc) ->
whitespace(Data,
- fun (<< $;, Rest/bits >>) ->
+ fun (<< $;, Rest/binary >>) ->
whitespace(Rest,
fun (Rest2) ->
accept_ext_attr(Rest2, Fun,
@@ -180,7 +181,7 @@ accept_ext(Data, Fun, Type, SubType, Params, Quality, Acc) ->
accept_ext_attr(Data, Fun, Type, SubType, Params, Quality, Acc) ->
token_ci(Data,
fun (_Rest, <<>>) -> {error, badarg};
- (<< $=, Rest/bits >>, Attr) ->
+ (<< $=, Rest/binary >>, Attr) ->
accept_ext_value(Rest, Fun, Type, SubType, Params,
Quality, Acc, Attr);
(Rest, Attr) ->
@@ -213,7 +214,7 @@ conneg(Data, Fun) ->
%% @doc Parse a language range, followed by an optional quality value.
-spec language_range(binary(), fun()) -> any().
-language_range(<< $*, Rest/bits >>, Fun) ->
+language_range(<< $*, Rest/binary >>, Fun) ->
language_range_ret(Rest, Fun, '*');
language_range(Data, Fun) ->
language_tag(Data,
@@ -233,7 +234,7 @@ language_tag(Data, Fun) ->
alpha(Data,
fun (_Rest, Tag) when byte_size(Tag) =:= 0; byte_size(Tag) > 8 ->
{error, badarg};
- (<< $-, Rest/bits >>, Tag) ->
+ (<< $-, Rest/binary >>, Tag) ->
language_subtag(Rest, Fun, Tag, []);
(Rest, Tag) ->
Fun(Rest, Tag)
@@ -244,7 +245,7 @@ language_subtag(Data, Fun, Tag, Acc) ->
alpha(Data,
fun (_Rest, SubTag) when byte_size(SubTag) =:= 0;
byte_size(SubTag) > 8 -> {error, badarg};
- (<< $-, Rest/bits >>, SubTag) ->
+ (<< $-, Rest/binary >>, SubTag) ->
language_subtag(Rest, Fun, Tag, [SubTag|Acc]);
(Rest, SubTag) ->
%% Rebuild the full tag now that we know it's correct
@@ -255,7 +256,7 @@ language_subtag(Data, Fun, Tag, Acc) ->
-spec maybe_qparam(binary(), fun()) -> any().
maybe_qparam(Data, Fun) ->
whitespace(Data,
- fun (<< $;, Rest/bits >>) ->
+ fun (<< $;, Rest/binary >>) ->
whitespace(Rest,
fun (Rest2) ->
qparam(Rest2, Fun)
@@ -266,12 +267,12 @@ maybe_qparam(Data, Fun) ->
%% @doc Parse a quality parameter string (for example q=0.500).
-spec qparam(binary(), fun()) -> any().
-qparam(<< Q, $=, Data/bits >>, Fun) when Q =:= $q; Q =:= $Q ->
+qparam(<< Q, $=, Data/binary >>, Fun) when Q =:= $q; Q =:= $Q ->
qvalue(Data, Fun).
%% @doc Parse either a list of entity tags or a "*".
-spec entity_tag_match(binary()) -> any().
-entity_tag_match(<< $*, Rest/bits >>) ->
+entity_tag_match(<< $*, Rest/binary >>) ->
whitespace(Rest,
fun (<<>>) -> '*';
(_Any) -> {error, badarg}
@@ -281,7 +282,7 @@ entity_tag_match(Data) ->
%% @doc Parse an entity-tag.
-spec entity_tag(binary(), fun()) -> any().
-entity_tag(<< "W/", Rest/bits >>, Fun) ->
+entity_tag(<< "W/", Rest/binary >>, Fun) ->
opaque_tag(Rest, Fun, weak);
entity_tag(Data, Fun) ->
opaque_tag(Data, Fun, strong).
@@ -322,11 +323,11 @@ http_date(Data) ->
-spec rfc1123_date(binary()) -> any().
rfc1123_date(Data) ->
wkday(Data,
- fun (<< ", ", Rest/bits >>, _WkDay) ->
+ fun (<< ", ", Rest/binary >>, _WkDay) ->
date1(Rest,
- fun (<< " ", Rest2/bits >>, Date) ->
+ fun (<< " ", Rest2/binary >>, Date) ->
time(Rest2,
- fun (<< " GMT", Rest3/bits >>, Time) ->
+ fun (<< " GMT", Rest3/binary >>, Time) ->
http_date_ret(Rest3, {Date, Time});
(_Any, _Time) ->
{error, badarg}
@@ -346,11 +347,11 @@ rfc1123_date(Data) ->
%% in the past (this helps solve the "year 2000" problem).
rfc850_date(Data) ->
weekday(Data,
- fun (<< ", ", Rest/bits >>, _WeekDay) ->
+ fun (<< ", ", Rest/binary >>, _WeekDay) ->
date2(Rest,
- fun (<< " ", Rest2/bits >>, Date) ->
+ fun (<< " ", Rest2/binary >>, Date) ->
time(Rest2,
- fun (<< " GMT", Rest3/bits >>, Time) ->
+ fun (<< " GMT", Rest3/binary >>, Time) ->
http_date_ret(Rest3, {Date, Time});
(_Any, _Time) ->
{error, badarg}
@@ -366,11 +367,11 @@ rfc850_date(Data) ->
-spec asctime_date(binary()) -> any().
asctime_date(Data) ->
wkday(Data,
- fun (<< " ", Rest/bits >>, _WkDay) ->
+ fun (<< " ", Rest/binary >>, _WkDay) ->
date3(Rest,
- fun (<< " ", Rest2/bits >>, PartialDate) ->
+ fun (<< " ", Rest2/binary >>, PartialDate) ->
time(Rest2,
- fun (<< " ", Rest3/bits >>, Time) ->
+ fun (<< " ", Rest3/binary >>, Time) ->
asctime_year(Rest3,
PartialDate, Time);
(_Any, _Time) ->
@@ -384,7 +385,7 @@ asctime_date(Data) ->
end).
-spec asctime_year(binary(), tuple(), tuple()) -> any().
-asctime_year(<< Y1, Y2, Y3, Y4, Rest/bits >>, {Month, Day}, Time)
+asctime_year(<< Y1, Y2, Y3, Y4, Rest/binary >>, {Month, Day}, Time)
when Y1 >= $0, Y1 =< $9, Y2 >= $0, Y2 =< $9,
Y3 >= $0, Y3 =< $9, Y4 >= $0, Y4 =< $9 ->
Year = (Y1 - $0) * 1000 + (Y2 - $0) * 100 + (Y3 - $0) * 10 + (Y4 - $0),
@@ -404,7 +405,7 @@ http_date_ret(Data, DateTime = {Date, _Time}) ->
%% We never use it, pretty much just checks the wkday is right.
-spec wkday(binary(), fun()) -> any().
-wkday(<< WkDay:3/binary, Rest/bits >>, Fun)
+wkday(<< WkDay:3/binary, Rest/binary >>, Fun)
when WkDay =:= <<"Mon">>; WkDay =:= <<"Tue">>; WkDay =:= <<"Wed">>;
WkDay =:= <<"Thu">>; WkDay =:= <<"Fri">>; WkDay =:= <<"Sat">>;
WkDay =:= <<"Sun">> ->
@@ -432,7 +433,7 @@ weekday(_Any, _Fun) ->
{error, badarg}.
-spec date1(binary(), fun()) -> any().
-date1(<< D1, D2, " ", M:3/binary, " ", Y1, Y2, Y3, Y4, Rest/bits >>, Fun)
+date1(<< D1, D2, " ", M:3/binary, " ", Y1, Y2, Y3, Y4, Rest/binary >>, Fun)
when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9,
Y1 >= $0, Y1 =< $9, Y2 >= $0, Y2 =< $9,
Y3 >= $0, Y3 =< $9, Y4 >= $0, Y4 =< $9 ->
@@ -450,7 +451,7 @@ date1(_Data, _Fun) ->
{error, badarg}.
-spec date2(binary(), fun()) -> any().
-date2(<< D1, D2, "-", M:3/binary, "-", Y1, Y2, Rest/bits >>, Fun)
+date2(<< D1, D2, "-", M:3/binary, "-", Y1, Y2, Rest/binary >>, Fun)
when D1 >= $0, D1 =< $9, D2 >= $0, D2 =< $9,
Y1 >= $0, Y1 =< $9, Y2 >= $0, Y2 =< $9 ->
case month(M) of
@@ -472,7 +473,7 @@ date2(_Data, _Fun) ->
{error, badarg}.
-spec date3(binary(), fun()) -> any().
-date3(<< M:3/binary, " ", D1, D2, Rest/bits >>, Fun)
+date3(<< M:3/binary, " ", D1, D2, Rest/binary >>, Fun)
when (D1 >= $0 andalso D1 =< $3) orelse D1 =:= $\s,
D2 >= $0, D2 =< $9 ->
case month(M) of
@@ -504,7 +505,7 @@ month(<<"Dec">>) -> 12;
month(_Any) -> {error, badarg}.
-spec time(binary(), fun()) -> any().
-time(<< H1, H2, ":", M1, M2, ":", S1, S2, Rest/bits >>, Fun)
+time(<< H1, H2, ":", M1, M2, ":", S1, S2, Rest/binary >>, Fun)
when H1 >= $0, H1 =< $2, H2 >= $0, H2 =< $9,
M1 >= $0, M1 =< $5, M2 >= $0, M2 =< $9,
S1 >= $0, S1 =< $5, S2 >= $0, S2 =< $9 ->
@@ -523,7 +524,7 @@ time(<< H1, H2, ":", M1, M2, ":", S1, S2, Rest/bits >>, Fun)
%% @doc Skip whitespace.
-spec whitespace(binary(), fun()) -> any().
-whitespace(<< C, Rest/bits >>, Fun)
+whitespace(<< C, Rest/binary >>, Fun)
when C =:= $\s; C =:= $\t ->
whitespace(Rest, Fun);
whitespace(Data, Fun) ->
@@ -543,14 +544,14 @@ digits(Data) ->
end).
-spec digits(binary(), fun()) -> any().
-digits(<< C, Rest/bits >>, Fun)
+digits(<< C, Rest/binary >>, Fun)
when C >= $0, C =< $9 ->
digits(Rest, Fun, C - $0);
digits(_Data, _Fun) ->
{error, badarg}.
-spec digits(binary(), fun(), non_neg_integer()) -> any().
-digits(<< C, Rest/bits >>, Fun, Acc)
+digits(<< C, Rest/binary >>, Fun, Acc)
when C >= $0, C =< $9 ->
digits(Rest, Fun, Acc * 10 + (C - $0));
digits(Data, Fun, Acc) ->
@@ -566,7 +567,7 @@ alpha(Data, Fun) ->
-spec alpha(binary(), fun(), binary()) -> any().
alpha(<<>>, Fun, Acc) ->
Fun(<<>>, Acc);
-alpha(<< C, Rest/bits >>, Fun, Acc)
+alpha(<< C, Rest/binary >>, Fun, Acc)
when C >= $a andalso C =< $z;
C >= $A andalso C =< $Z ->
C2 = cowboy_bstr:char_to_lower(C),
@@ -576,7 +577,7 @@ alpha(Data, Fun, Acc) ->
%% @doc Parse either a token or a quoted string.
-spec word(binary(), fun()) -> any().
-word(Data = << $", _/bits >>, Fun) ->
+word(Data = << $", _/binary >>, Fun) ->
quoted_string(Data, Fun);
word(Data, Fun) ->
token(Data,
@@ -599,47 +600,47 @@ token(Data, Fun) ->
-spec token(binary(), fun(), ci | cs, binary()) -> any().
token(<<>>, Fun, _Case, Acc) ->
Fun(<<>>, Acc);
-token(Data = << C, _Rest/bits >>, Fun, _Case, Acc)
+token(Data = << C, _Rest/binary >>, Fun, _Case, Acc)
when C =:= $(; C =:= $); C =:= $<; C =:= $>; C =:= $@;
C =:= $,; C =:= $;; C =:= $:; C =:= $\\; C =:= $";
C =:= $/; C =:= $[; C =:= $]; C =:= $?; C =:= $=;
C =:= ${; C =:= $}; C =:= $\s; C =:= $\t;
C < 32; C =:= 127 ->
Fun(Data, Acc);
-token(<< C, Rest/bits >>, Fun, Case = ci, Acc) ->
+token(<< C, Rest/binary >>, Fun, Case = ci, Acc) ->
C2 = cowboy_bstr:char_to_lower(C),
token(Rest, Fun, Case, << Acc/binary, C2 >>);
-token(<< C, Rest/bits >>, Fun, Case, Acc) ->
+token(<< C, Rest/binary >>, Fun, Case, Acc) ->
token(Rest, Fun, Case, << Acc/binary, C >>).
%% @doc Parse a quoted string.
-spec quoted_string(binary(), fun()) -> any().
-quoted_string(<< $", Rest/bits >>, Fun) ->
+quoted_string(<< $", Rest/binary >>, Fun) ->
quoted_string(Rest, Fun, <<>>).
-spec quoted_string(binary(), fun(), binary()) -> any().
quoted_string(<<>>, _Fun, _Acc) ->
{error, badarg};
-quoted_string(<< $", Rest/bits >>, Fun, Acc) ->
+quoted_string(<< $", Rest/binary >>, Fun, Acc) ->
Fun(Rest, Acc);
-quoted_string(<< $\\, C, Rest/bits >>, Fun, Acc) ->
+quoted_string(<< $\\, C, Rest/binary >>, Fun, Acc) ->
quoted_string(Rest, Fun, << Acc/binary, C >>);
-quoted_string(<< C, Rest/bits >>, Fun, Acc) ->
+quoted_string(<< C, Rest/binary >>, Fun, Acc) ->
quoted_string(Rest, Fun, << Acc/binary, C >>).
%% @doc Parse a quality value.
-spec qvalue(binary(), fun()) -> any().
-qvalue(<< $0, $., Rest/bits >>, Fun) ->
+qvalue(<< $0, $., Rest/binary >>, Fun) ->
qvalue(Rest, Fun, 0, 100);
-qvalue(<< $0, Rest/bits >>, Fun) ->
+qvalue(<< $0, Rest/binary >>, Fun) ->
Fun(Rest, 0);
-qvalue(<< $1, $., $0, $0, $0, Rest/bits >>, Fun) ->
+qvalue(<< $1, $., $0, $0, $0, Rest/binary >>, Fun) ->
Fun(Rest, 1000);
-qvalue(<< $1, $., $0, $0, Rest/bits >>, Fun) ->
+qvalue(<< $1, $., $0, $0, Rest/binary >>, Fun) ->
Fun(Rest, 1000);
-qvalue(<< $1, $., $0, Rest/bits >>, Fun) ->
+qvalue(<< $1, $., $0, Rest/binary >>, Fun) ->
Fun(Rest, 1000);
-qvalue(<< $1, Rest/bits >>, Fun) ->
+qvalue(<< $1, Rest/binary >>, Fun) ->
Fun(Rest, 1000);
qvalue(_Data, _Fun) ->
{error, badarg}.
@@ -647,7 +648,7 @@ qvalue(_Data, _Fun) ->
-spec qvalue(binary(), fun(), integer(), 1 | 10 | 100) -> any().
qvalue(Data, Fun, Q, 0) ->
Fun(Data, Q);
-qvalue(<< C, Rest/bits >>, Fun, Q, M)
+qvalue(<< C, Rest/binary >>, Fun, Q, M)
when C >= $0, C =< $9 ->
qvalue(Rest, Fun, Q + (C - $0) * M, M div 10);
qvalue(Data, Fun, Q, _M) ->
@@ -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(_) -> 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.
-ifdef(TEST).
@@ -877,12 +923,27 @@ 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].
+ 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.
diff --git a/src/cowboy_http_rest.erl b/src/cowboy_http_rest.erl
index ba0701c..474964f 100644
--- a/src/cowboy_http_rest.erl
+++ b/src/cowboy_http_rest.erl
@@ -176,25 +176,39 @@ options(Req, State) ->
%%
%% An example of such return value would be:
%% {{<<"text">>, <<"html">>, []}, to_html}
+%%
+%% Note that it is also possible to return a binary content type that will
+%% then be parsed by Cowboy. However note that while this may make your
+%% resources a little more readable, this is a lot less efficient. An example
+%% of such a return value would be:
+%% {<<"text/html">>, to_html}
content_types_provided(Req, State) ->
case call(Req, State, content_types_provided) of
no_call ->
not_acceptable(Req, State);
- {[], Req2, HandlerState2} ->
- not_acceptable(Req2, State#state{handler_state=HandlerState2});
- {CTP, Req2, HandlerState2} ->
- State2 = State#state{handler_state=HandlerState2, content_types_p=CTP},
+ {[], Req2, HandlerState} ->
+ not_acceptable(Req2, State#state{handler_state=HandlerState});
+ {CTP, Req2, HandlerState} ->
+ CTP2 = [normalize_content_types_provided(P) || P <- CTP],
+ State2 = State#state{
+ handler_state=HandlerState, content_types_p=CTP2},
{Accept, Req3} = cowboy_http_req:parse_header('Accept', Req2),
case Accept of
undefined ->
languages_provided(Req3,
- State2#state{content_type_a=hd(CTP)});
+ State2#state{content_type_a=hd(CTP2)});
Accept ->
Accept2 = prioritize_accept(Accept),
choose_media_type(Req3, State2, Accept2)
end
end.
+normalize_content_types_provided({ContentType, Handler})
+ when is_binary(ContentType) ->
+ {cowboy_http:content_type(ContentType), Handler};
+normalize_content_types_provided(Provided) ->
+ Provided.
+
prioritize_accept(Accept) ->
lists:sort(
fun ({MediaTypeA, Quality, _AcceptParamsA},
@@ -233,18 +247,26 @@ choose_media_type(Req, State=#state{content_types_p=CTP},
match_media_type(Req, State, Accept, [], _MediaType) ->
choose_media_type(Req, State, Accept);
+match_media_type(Req, State, Accept, CTP,
+ MediaType = {{<<"*">>, <<"*">>, _Params_A}, _QA, _APA}) ->
+ match_media_type_params(Req, State, Accept, CTP, MediaType);
match_media_type(Req, State, Accept,
- [Provided = {{Type, SubType_P, Params_P}, _Fun}|Tail],
- MediaType = {{Type, SubType_A, Params_A}, _Quality, _AcceptParams})
+ CTP = [{{Type, SubType_P, _PP}, _Fun}|_Tail],
+ MediaType = {{Type, SubType_A, _PA}, _QA, _APA})
when SubType_P =:= SubType_A; SubType_A =:= <<"*">> ->
+ match_media_type_params(Req, State, Accept, CTP, MediaType);
+match_media_type(Req, State, Accept, [_Any|Tail], MediaType) ->
+ match_media_type(Req, State, Accept, Tail, MediaType).
+
+match_media_type_params(Req, State, Accept,
+ [Provided = {{_TP, _STP, Params_P}, _Fun}|Tail],
+ MediaType = {{_TA, _STA, Params_A}, _QA, _APA}) ->
case lists:sort(Params_P) =:= lists:sort(Params_A) of
true ->
languages_provided(Req, State#state{content_type_a=Provided});
false ->
match_media_type(Req, State, Accept, Tail, MediaType)
- end;
-match_media_type(Req, State, Accept, [_Any|Tail], MediaType) ->
- match_media_type(Req, State, Accept, Tail, MediaType).
+ end.
%% languages_provided should return a list of binary values indicating
%% which languages are accepted by the resource.
diff --git a/src/cowboy_http_websocket.erl b/src/cowboy_http_websocket.erl
index 7013d7f..20060e6 100644
--- a/src/cowboy_http_websocket.erl
+++ b/src/cowboy_http_websocket.erl
@@ -244,11 +244,11 @@ websocket_data(State, Req, HandlerState, <<>>) ->
handler_before_loop(State, Req, HandlerState, <<>>);
%% hixie-76 close frame.
websocket_data(State=#state{version=0}, Req, HandlerState,
- << 255, 0, _Rest/bits >>) ->
+ << 255, 0, _Rest/binary >>) ->
websocket_close(State, Req, HandlerState, {normal, closed});
%% hixie-76 data frame. We only support the frame type 0, same as the specs.
websocket_data(State=#state{version=0, eop=EOP}, Req, HandlerState,
- Data = << 0, _/bits >>) ->
+ Data = << 0, _/binary >>) ->
case binary:match(Data, EOP) of
{Pos, 1} ->
Pos2 = Pos - 1,