mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-15 04:30:25 +00:00
Merge branch 'rest_patch' of https://github.com/treetopllc/cowboy
This commit is contained in:
commit
a59c5d6e91
3 changed files with 80 additions and 1 deletions
|
@ -91,7 +91,8 @@ known_methods(Req, State=#state{method=Method}) ->
|
||||||
no_call when Method =:= <<"HEAD">>; Method =:= <<"GET">>;
|
no_call when Method =:= <<"HEAD">>; Method =:= <<"GET">>;
|
||||||
Method =:= <<"POST">>; Method =:= <<"PUT">>;
|
Method =:= <<"POST">>; Method =:= <<"PUT">>;
|
||||||
Method =:= <<"DELETE">>; Method =:= <<"TRACE">>;
|
Method =:= <<"DELETE">>; Method =:= <<"TRACE">>;
|
||||||
Method =:= <<"CONNECT">>; Method =:= <<"OPTIONS">> ->
|
Method =:= <<"CONNECT">>; Method =:= <<"OPTIONS">>;
|
||||||
|
Method =:= <<"PATCH">> ->
|
||||||
next(Req, State, fun uri_too_long/2);
|
next(Req, State, fun uri_too_long/2);
|
||||||
no_call ->
|
no_call ->
|
||||||
next(Req, State, 501);
|
next(Req, State, 501);
|
||||||
|
@ -644,6 +645,8 @@ method(Req, State=#state{method= <<"POST">>}) ->
|
||||||
post_is_create(Req, State);
|
post_is_create(Req, State);
|
||||||
method(Req, State=#state{method= <<"PUT">>}) ->
|
method(Req, State=#state{method= <<"PUT">>}) ->
|
||||||
is_conflict(Req, State);
|
is_conflict(Req, State);
|
||||||
|
method(Req, State=#state{method= <<"PATCH">>}) ->
|
||||||
|
patch_resource(Req, State);
|
||||||
method(Req, State=#state{method=Method})
|
method(Req, State=#state{method=Method})
|
||||||
when Method =:= <<"GET">>; Method =:= <<"HEAD">> ->
|
when Method =:= <<"GET">>; Method =:= <<"HEAD">> ->
|
||||||
set_resp_body(Req, State);
|
set_resp_body(Req, State);
|
||||||
|
@ -708,6 +711,9 @@ put_resource(Req, State) ->
|
||||||
%% may be different from the request path, and is stored as request metadata.
|
%% may be different from the request path, and is stored as request metadata.
|
||||||
%% It is always defined past this point. It can be retrieved as demonstrated:
|
%% It is always defined past this point. It can be retrieved as demonstrated:
|
||||||
%% {PutPath, Req2} = cowboy_req:meta(put_path, Req)
|
%% {PutPath, Req2} = cowboy_req:meta(put_path, Req)
|
||||||
|
%%
|
||||||
|
%%content_types_accepted SHOULD return a different list
|
||||||
|
%% for each HTTP method.
|
||||||
put_resource(Req, State, OnTrue) ->
|
put_resource(Req, State, OnTrue) ->
|
||||||
case call(Req, State, content_types_accepted) of
|
case call(Req, State, content_types_accepted) of
|
||||||
no_call ->
|
no_call ->
|
||||||
|
@ -722,6 +728,27 @@ put_resource(Req, State, OnTrue) ->
|
||||||
choose_content_type(Req3, State2, OnTrue, ContentType, CTA2)
|
choose_content_type(Req3, State2, OnTrue, ContentType, CTA2)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
%% content_types_accepted should return a list of media types and their
|
||||||
|
%% associated callback functions in the same format as content_types_provided.
|
||||||
|
%%
|
||||||
|
%% The callback will then be called and is expected to process the content
|
||||||
|
%% pushed to the resource in the request body.
|
||||||
|
%%
|
||||||
|
%% content_types_accepted SHOULD return a different list
|
||||||
|
%% for each HTTP method.
|
||||||
|
patch_resource(Req, State) ->
|
||||||
|
case call(Req, State, content_types_accepted) of
|
||||||
|
no_call ->
|
||||||
|
respond(Req, State, 415);
|
||||||
|
{halt, Req2, HandlerState} ->
|
||||||
|
terminate(Req2, State#state{handler_state=HandlerState});
|
||||||
|
{CTM, Req2, HandlerState} ->
|
||||||
|
State2 = State#state{handler_state=HandlerState},
|
||||||
|
{ok, ContentType, Req3}
|
||||||
|
= cowboy_req:parse_header(<<"content-type">>, Req2),
|
||||||
|
choose_content_type(Req3, State2, 204, ContentType, CTM)
|
||||||
|
end.
|
||||||
|
|
||||||
%% The special content type '*' will always match. It can be used as a
|
%% The special content type '*' will always match. It can be used as a
|
||||||
%% catch-all content type for accepting any kind of request content.
|
%% catch-all content type for accepting any kind of request content.
|
||||||
%% Note that because it will always match, it should be the last of the
|
%% Note that because it will always match, it should be the last of the
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
-export([rest_missing_get_callbacks/1]).
|
-export([rest_missing_get_callbacks/1]).
|
||||||
-export([rest_missing_put_callbacks/1]).
|
-export([rest_missing_put_callbacks/1]).
|
||||||
-export([rest_nodelete/1]).
|
-export([rest_nodelete/1]).
|
||||||
|
-export([rest_patch/1]).
|
||||||
-export([rest_resource_etags/1]).
|
-export([rest_resource_etags/1]).
|
||||||
-export([rest_resource_etags_if_none_match/1]).
|
-export([rest_resource_etags_if_none_match/1]).
|
||||||
-export([set_resp_body/1]).
|
-export([set_resp_body/1]).
|
||||||
|
@ -117,6 +118,7 @@ groups() ->
|
||||||
rest_missing_get_callbacks,
|
rest_missing_get_callbacks,
|
||||||
rest_missing_put_callbacks,
|
rest_missing_put_callbacks,
|
||||||
rest_nodelete,
|
rest_nodelete,
|
||||||
|
rest_patch,
|
||||||
rest_resource_etags,
|
rest_resource_etags,
|
||||||
rest_resource_etags_if_none_match,
|
rest_resource_etags_if_none_match,
|
||||||
set_resp_body,
|
set_resp_body,
|
||||||
|
@ -331,6 +333,7 @@ init_dispatch(Config) ->
|
||||||
{"/missing_get_callbacks", rest_missing_callbacks, []},
|
{"/missing_get_callbacks", rest_missing_callbacks, []},
|
||||||
{"/missing_put_callbacks", rest_missing_callbacks, []},
|
{"/missing_put_callbacks", rest_missing_callbacks, []},
|
||||||
{"/nodelete", rest_nodelete_resource, []},
|
{"/nodelete", rest_nodelete_resource, []},
|
||||||
|
{"/patch", rest_patch_resource, []},
|
||||||
{"/resetags", rest_resource_etags, []},
|
{"/resetags", rest_resource_etags, []},
|
||||||
{"/rest_expires", rest_expires, []},
|
{"/rest_expires", rest_expires, []},
|
||||||
{"/loop_timeout", http_handler_loop_timeout, []},
|
{"/loop_timeout", http_handler_loop_timeout, []},
|
||||||
|
@ -834,6 +837,21 @@ rest_nodelete(Config) ->
|
||||||
build_url("/nodelete", Config), Client),
|
build_url("/nodelete", Config), Client),
|
||||||
{ok, 500, _, _} = cowboy_client:response(Client2).
|
{ok, 500, _, _} = cowboy_client:response(Client2).
|
||||||
|
|
||||||
|
rest_patch(Config) ->
|
||||||
|
Tests = [
|
||||||
|
{204, [{<<"content-type">>, <<"text/plain">>}], <<"whatever">>},
|
||||||
|
{500, [{<<"content-type">>, <<"text/plain">>}], <<"false">>},
|
||||||
|
{400, [{<<"content-type">>, <<"text/plain">>}], <<"halt">>},
|
||||||
|
{415, [{<<"content-type">>, <<"application/json">>}], <<"bad_content_type">>}
|
||||||
|
],
|
||||||
|
Client = ?config(client, Config),
|
||||||
|
_ = [begin
|
||||||
|
{ok, Client2} = cowboy_client:request(<<"PATCH">>,
|
||||||
|
build_url("/patch", Config), Headers, Body, Client),
|
||||||
|
{ok, Status, _, _} = cowboy_client:response(Client2),
|
||||||
|
ok
|
||||||
|
end || {Status, Headers, Body} <- Tests].
|
||||||
|
|
||||||
rest_resource_get_etag(Config, Type) ->
|
rest_resource_get_etag(Config, Type) ->
|
||||||
rest_resource_get_etag(Config, Type, []).
|
rest_resource_get_etag(Config, Type, []).
|
||||||
|
|
||||||
|
|
34
test/rest_patch_resource.erl
Normal file
34
test/rest_patch_resource.erl
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
-module(rest_patch_resource).
|
||||||
|
-export([init/3, allowed_methods/2, content_types_provided/2, get_text_plain/2,
|
||||||
|
content_types_accepted/2, patch_text_plain/2]).
|
||||||
|
|
||||||
|
init(_Transport, _Req, _Opts) ->
|
||||||
|
{upgrade, protocol, cowboy_rest}.
|
||||||
|
|
||||||
|
allowed_methods(Req, State) ->
|
||||||
|
{[<<"HEAD">>, <<"GET">>, <<"PATCH">>], Req, State}.
|
||||||
|
|
||||||
|
content_types_provided(Req, State) ->
|
||||||
|
{[{{<<"text">>, <<"plain">>, []}, get_text_plain}], Req, State}.
|
||||||
|
|
||||||
|
get_text_plain(Req, State) ->
|
||||||
|
{<<"This is REST!">>, Req, State}.
|
||||||
|
|
||||||
|
content_types_accepted(Req, State) ->
|
||||||
|
case cowboy_req:method(Req) of
|
||||||
|
{<<"PATCH">>, Req0} ->
|
||||||
|
{[{{<<"text">>, <<"plain">>, []}, patch_text_plain}], Req0, State};
|
||||||
|
{_, Req0} ->
|
||||||
|
{[], Req0, State}
|
||||||
|
end.
|
||||||
|
|
||||||
|
patch_text_plain(Req, State) ->
|
||||||
|
case cowboy_req:body(Req) of
|
||||||
|
{ok, <<"halt">>, Req0} ->
|
||||||
|
{ok, Req1} = cowboy_req:reply(400, Req0),
|
||||||
|
{halt, Req1, State};
|
||||||
|
{ok, <<"false">>, Req0} ->
|
||||||
|
{false, Req0, State};
|
||||||
|
{ok, _Body, Req0} ->
|
||||||
|
{true, Req0, State}
|
||||||
|
end.
|
Loading…
Add table
Add a link
Reference in a new issue