From bb1362c744ec24a72fbb2fa3e1cc8e44ef51ab2d Mon Sep 17 00:00:00 2001 From: Slava Yurin Date: Fri, 15 Feb 2013 22:41:55 +0700 Subject: Add '*' matcher for parameters For get_type_provided: '*' will be match any parameters of media-range in "accept" header. If '*' matched, then '*' is replaced by the matching parameters. If Accept header is missing and '*' using, then in media_type in parameters will be '*' and reply content-type will be without any parameters. For content_types_accepted: '*' will be match any parameters in "content-type" header. --- src/cowboy_rest.erl | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl index a40e1c6..cb4fffb 100644 --- a/src/cowboy_rest.erl +++ b/src/cowboy_rest.erl @@ -33,9 +33,11 @@ %% Media type. content_types_p = [] :: - [{binary() | {binary(), binary(), [{binary(), binary()}]}, atom()}], + [{binary() | {binary(), binary(), [{binary(), binary()}] | '*'}, + atom()}], content_type_a :: undefined - | {binary() | {binary(), binary(), [{binary(), binary()}]}, atom()}, + | {binary() | {binary(), binary(), [{binary(), binary()}] | '*'}, + atom()}, %% Language. languages_p = [] :: [binary()], @@ -286,6 +288,12 @@ match_media_type(Req, State, Accept, 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, '*'}, _Fun}|_Tail], + {{_TA, _STA, Params_A}, _QA, _APA}) -> + PMT = {TP, STP, Params_A}, + languages_provided(cowboy_req:set_meta(media_type, PMT, Req), + State#state{content_type_a=Provided}); match_media_type_params(Req, State, Accept, [Provided = {PMT = {_TP, _STP, Params_P}, _Fun}|Tail], MediaType = {{_TA, _STA, Params_A}, _QA, _APA}) -> @@ -426,6 +434,8 @@ set_content_type(Req, State=#state{ Req2 = cowboy_req:set_resp_header(<<"content-type">>, ContentType2, Req), encodings_provided(cowboy_req:set_meta(charset, Charset, Req2), State). +set_content_type_build_params('*', []) -> + <<>>; set_content_type_build_params([], []) -> <<>>; set_content_type_build_params([], Acc) -> @@ -855,10 +865,24 @@ patch_resource(Req, State) -> %% list of content types, otherwise it'll shadow the ones following. choose_content_type(Req, State, _OnTrue, _ContentType, []) -> respond(Req, State, 415); -choose_content_type(Req, +choose_content_type(Req, State, OnTrue, ContentType, [{Accepted, Fun}|_Tail]) + when Accepted =:= '*'; Accepted =:= ContentType -> + process_content_type(Req, State, OnTrue, Fun); +%% The special parameter '*' will always match any kind of content type +%% parameters. +%% Note that because it will always match, it should be the last of the +%% list for specific content type, otherwise it'll shadow the ones following. +choose_content_type(Req, State, OnTrue, + {Type, SubType, Param}, + [{{Type, SubType, AcceptedParam}, Fun}|_Tail]) + when AcceptedParam =:= '*'; AcceptedParam =:= Param -> + process_content_type(Req, State, OnTrue, Fun); +choose_content_type(Req, State, OnTrue, ContentType, [_Any|Tail]) -> + choose_content_type(Req, State, OnTrue, ContentType, Tail). + +process_content_type(Req, State=#state{handler=Handler, handler_state=HandlerState}, - OnTrue, ContentType, [{Accepted, Fun}|_Tail]) - when Accepted =:= '*' orelse Accepted =:= ContentType -> + OnTrue, Fun) -> case call(Req, State, Fun) of no_call -> error_logger:error_msg( @@ -875,9 +899,7 @@ choose_content_type(Req, {false, Req2, HandlerState2} -> State2 = State#state{handler_state=HandlerState2}, respond(Req2, State2, 422) - end; -choose_content_type(Req, State, OnTrue, ContentType, [_Any|Tail]) -> - choose_content_type(Req, State, OnTrue, ContentType, Tail). + end. %% Whether we created a new resource, either through PUT or POST. %% This is easily testable because we would have set the Location -- cgit v1.2.3