From e25634cd9db82a4760087a2ba68d4c6a76353d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Mon, 27 Jul 2015 23:58:58 +0200 Subject: Add optional callbacks Mostly useful for REST, which has a ton. This is an initial commit, it still needs to be tested, but it's time to sleep. --- doc/src/manual/cowboy_rest.ezdoc | 12 +++ src/cowboy_handler.erl | 4 +- src/cowboy_loop.erl | 4 +- src/cowboy_rest.erl | 173 ++++++++++++++++++++++++++++++++++++++- src/cowboy_websocket.erl | 4 +- 5 files changed, 192 insertions(+), 5 deletions(-) diff --git a/doc/src/manual/cowboy_rest.ezdoc b/doc/src/manual/cowboy_rest.ezdoc index eef622a..35131c7 100644 --- a/doc/src/manual/cowboy_rest.ezdoc +++ b/doc/src/manual/cowboy_rest.ezdoc @@ -290,6 +290,10 @@ the same format as the etag header, including quotes. * Value type: true | {false, AuthHeader} * Default value: true +Types: + +* AuthHead = iodata() + Return whether the user is authorized to perform the action. This function should be used to perform any necessary @@ -380,6 +384,10 @@ the request body, which is processed later. * Value type: {true, URL} | false * Default value: false +Types: + +* URL = iodata() + Return whether the resource was permanently moved. If it was, its new URL is also returned and sent in the @@ -391,6 +399,10 @@ location header in the response. * Value type: {true, URL} | false * Default value: false +Types: + +* URL = iodata() + Return whether the resource was temporarily moved. If it was, its new URL is also returned and sent in the diff --git a/src/cowboy_handler.erl b/src/cowboy_handler.erl index 952c238..165888e 100644 --- a/src/cowboy_handler.erl +++ b/src/cowboy_handler.erl @@ -29,7 +29,9 @@ | {module(), Req, any(), timeout()} | {module(), Req, any(), timeout(), hibernate} when Req::cowboy_req:req(). -%% @todo optional -callback terminate(terminate_reason(), cowboy_req:req(), state()) -> ok. + +-callback terminate(any(), cowboy_req:req(), any()) -> ok. +-optional_callbacks([terminate/3]). -spec execute(Req, Env) -> {ok, Req, Env} when Req::cowboy_req:req(), Env::cowboy_middleware:env(). diff --git a/src/cowboy_loop.erl b/src/cowboy_loop.erl index f0b2886..695439a 100644 --- a/src/cowboy_loop.erl +++ b/src/cowboy_loop.erl @@ -38,7 +38,9 @@ | {ok, Req, State, hibernate} | {stop, Req, State} when Req::cowboy_req:req(), State::any(). -%% @todo optional -callback terminate(terminate_reason(), cowboy_req:req(), state()) -> ok. + +-callback terminate(any(), cowboy_req:req(), any()) -> ok. +-optional_callbacks([terminate/3]). -record(state, { env :: cowboy_middleware:env(), diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl index 0ca9ec0..75e8e63 100644 --- a/src/cowboy_rest.erl +++ b/src/cowboy_rest.erl @@ -19,14 +19,183 @@ -export([upgrade/6]). +%% Common handler callbacks. + -callback init(Req, any()) -> {ok | module(), Req, any()} | {module(), Req, any(), hibernate} | {module(), Req, any(), timeout()} | {module(), Req, any(), timeout(), hibernate} when Req::cowboy_req:req(). -%% @todo optional REST callbacks -%% @todo optional -callback terminate(terminate_reason(), cowboy_req:req(), state()) -> ok. + +-callback terminate(any(), cowboy_req:req(), any()) -> ok. +-optional_callbacks([terminate/3]). + +%% REST handler callbacks. + +-callback allowed_methods(Req, State) + -> {[binary()], Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([allowed_methods/2]). + +-callback allow_missing_post(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([allow_missing_post/2]). + +-callback charsets_provided(Req, State) + -> {[binary()], Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([charsets_provided/2]). + +-callback content_types_accepted(Req, State) + -> {[{binary() | {binary(), binary(), '*' | [{binary(), binary()}]}, atom()}], Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([content_types_accepted/2]). + +-callback content_types_provided(Req, State) + -> {[{binary() | {binary(), binary(), '*' | [{binary(), binary()}]}, atom()}], Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([content_types_provided/2]). + +-callback delete_completed(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([delete_completed/2]). + +-callback delete_resource(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([delete_resource/2]). + +-callback expires(Req, State) + -> {calendar:datetime() | binary() | undefined, Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([expires/2]). + +-callback forbidden(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([forbidden/2]). + +-callback generate_etag(Req, State) + -> {binary() | {weak | strong, binary()}, Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([generate_etag/2]). + +-callback is_authorized(Req, State) + -> {true | {false, iodata()}, Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([is_authorized/2]). + +-callback is_conflict(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([is_conflict/2]). + +-callback known_methods(Req, State) + -> {[binary()], Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([known_methods/2]). + +-callback languages_provided(Req, State) + -> {[binary()], Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([languages_provided/2]). + +-callback last_modified(Req, State) + -> {calendar:datetime(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([last_modified/2]). + +-callback malformed_request(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([malformed_request/2]). + +-callback moved_permanently(Req, State) + -> {{true, iodata()} | false, Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([moved_permanently/2]). + +-callback moved_temporarily(Req, State) + -> {{true, iodata()} | false, Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([moved_temporarily/2]). + +-callback multiple_choices(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([multiple_choices/2]). + +-callback options(Req, State) + -> {ok, Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([options/2]). + +-callback previously_existed(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([previously_existed/2]). + +-callback resource_exists(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([resource_exists/2]). + +-callback service_available(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([service_available/2]). + +-callback uri_too_long(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([uri_too_long/2]). + +-callback valid_content_headers(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([valid_content_headers/2]). + +-callback valid_entity_length(Req, State) + -> {boolean(), Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([valid_entity_length/2]). + +-callback variances(Req, State) + -> {[binary()], Req, State} + | {stop, Req, State} + when Req::cowboy_req:req(), State::any(). +-optional_callbacks([variances/2]). + +%% End of REST callbacks. Whew! -record(state, { env :: cowboy_middleware:env(), diff --git a/src/cowboy_websocket.erl b/src/cowboy_websocket.erl index 12728d0..3c34908 100644 --- a/src/cowboy_websocket.erl +++ b/src/cowboy_websocket.erl @@ -45,7 +45,9 @@ | {reply, cow_ws:frame() | [cow_ws:frame()], Req, State, hibernate} | {stop, Req, State} when Req::cowboy_req:req(), State::any(). -%% @todo optional -callback terminate(terminate_reason(), cowboy_req:req(), state()) -> ok. + +-callback terminate(any(), cowboy_req:req(), any()) -> ok. +-optional_callbacks([terminate/3]). -record(state, { env :: cowboy_middleware:env(), -- cgit v1.2.3