diff options
-rw-r--r-- | src/cowboy_http.erl | 177 | ||||
-rw-r--r-- | src/cowboy_http_rest.erl | 42 | ||||
-rw-r--r-- | src/cowboy_http_websocket.erl | 4 |
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, |