Просмотр исходного кода

Update behaviours for R15B+

This effectively drops the R14B compatibility.

The cowboy_req:req() type will be introduced in a future commit.
It refers to the #http_req{} record.
Loïc Hoguin 12 лет назад
Родитель
Сommit
cc2e084d45

+ 0 - 5
src/cowboy_app.erl

@@ -20,15 +20,10 @@
 -export([start/2]).
 -export([stop/1]).
 
--type application_start_type() :: normal
-	| {takeover, node()} | {failover, node()}.
-
 %% API.
 
--spec start(application_start_type(), any()) -> {ok, pid()}.
 start(_Type, _Args) ->
 	cowboy_sup:start_link().
 
--spec stop(any()) -> ok.
 stop(_State) ->
 	ok.

+ 0 - 7
src/cowboy_clock.erl

@@ -107,7 +107,6 @@ rfc2109(LocalTime) ->
 %% gen_server.
 
 %% @private
--spec init([]) -> {ok, #state{}}.
 init([]) ->
 	?TABLE = ets:new(?TABLE, [set, protected,
 		named_table, {read_concurrency, true}]),
@@ -118,8 +117,6 @@ init([]) ->
 	{ok, #state{universaltime=T, rfc1123=B, tref=TRef}}.
 
 %% @private
--spec handle_call(_, _, State)
-	-> {reply, ignored, State} | {stop, normal, stopped, State}.
 handle_call(stop, _From, State=#state{tref=TRef}) ->
 	{ok, cancel} = timer:cancel(TRef),
 	{stop, normal, stopped, State};
@@ -127,12 +124,10 @@ handle_call(_Request, _From, State) ->
 	{reply, ignored, State}.
 
 %% @private
--spec handle_cast(_, State) -> {noreply, State}.
 handle_cast(_Msg, State) ->
 	{noreply, State}.
 
 %% @private
--spec handle_info(_, State) -> {noreply, State}.
 handle_info(update, #state{universaltime=Prev, rfc1123=B1, tref=TRef}) ->
 	T = erlang:universaltime(),
 	B2 = update_rfc1123(B1, Prev, T),
@@ -142,12 +137,10 @@ handle_info(_Info, State) ->
 	{noreply, State}.
 
 %% @private
--spec terminate(_, _) -> ok.
 terminate(_Reason, _State) ->
 	ok.
 
 %% @private
--spec code_change(_, State, _) -> {ok, State}.
 code_change(_OldVsn, State, _Extra) ->
 	{ok, State}.
 

+ 27 - 27
src/cowboy_http_handler.erl

@@ -12,37 +12,37 @@
 %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-%% @doc Handler for HTTP requests.
+%% @doc Behaviour for short-lived HTTP handlers.
 %%
-%% HTTP handlers must implement three callbacks: <em>init/3</em>,
-%% <em>handle/2</em> and <em>terminate/2</em>, called one after another in
-%% that order.
+%% <em>init/3</em> allows you to initialize a state for all subsequent
+%% callbacks, and indicate to Cowboy whether you accept to handle the
+%% request or want to shutdown without handling it, in which case the
+%% <em>handle/2</em> call will simply be skipped.
 %%
-%% <em>init/3</em> is meant for initialization. It receives information about
-%% the transport and protocol used, along with the handler options from the
-%% dispatch list, and allows you to upgrade the protocol if needed. You can
-%% define a request-wide state here.
+%% <em>handle/2</em> allows you to handle the request. It receives the
+%% state previously defined.
 %%
-%% <em>handle/2</em> is meant for handling the request. It receives the
-%% request and the state previously defined.
+%% <em>terminate/2</em> allows you to clean up. It receives the state
+%% previously defined.
 %%
-%% <em>terminate/2</em> is meant for cleaning up. It also receives the
-%% request and the state previously defined.
-%%
-%% You do not have to read the request body or even send a reply if you do
-%% not need to. Cowboy will properly handle these cases and clean-up afterwards.
-%% In doubt it'll simply close the connection.
-%%
-%% Note that when upgrading the connection to WebSocket you do not need to
-%% define the <em>handle/2</em> and <em>terminate/2</em> callbacks.
+%% There is no required operation to perform in any of these callbacks
+%% other than returning the proper values. Make sure you always return
+%% the last modified Req so that Cowboy has the up to date information
+%% about the request.
 -module(cowboy_http_handler).
 
--export([behaviour_info/1]).
+-type opts() :: any().
+-type state() :: any().
 
-%% @private
--spec behaviour_info(_)
-	-> undefined | [{handle, 2} | {init, 3} | {terminate, 2}, ...].
-behaviour_info(callbacks) ->
-	[{init, 3}, {handle, 2}, {terminate, 2}];
-behaviour_info(_Other) ->
-	undefined.
+-callback init({atom(), http}, Req, opts())
+	-> {ok, Req, state()}
+	| {loop, Req, state()}
+	| {loop, Req, state(), hibernate}
+	| {loop, Req, state(), timeout()}
+	| {loop, Req, state(), timeout(), hibernate}
+	| {shutdown, Req, state()}
+	| {upgrade, protocol, module()}
+	when Req::cowboy_req:req().
+-callback handle(Req, State) -> {ok, Req, State}
+	when Req::cowboy_req:req(), State::state().
+-callback terminate(cowboy_req:req(), state()) -> ok.

+ 57 - 0
src/cowboy_loop_handler.erl

@@ -0,0 +1,57 @@
+%% Copyright (c) 2011-2012, Loïc Hoguin <essen@ninenines.eu>
+%%
+%% Permission to use, copy, modify, and/or distribute this software for any
+%% purpose with or without fee is hereby granted, provided that the above
+%% copyright notice and this permission notice appear in all copies.
+%%
+%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+%% @doc Behaviour for long-lived HTTP handlers.
+%%
+%% <em>init/3</em> allows you to initialize a state for all subsequent
+%% callbacks, and indicate to Cowboy whether you accept to handle the
+%% request or want to shutdown without handling it, in which case the
+%% receive loop and <em>info/3</em> calls will simply be skipped.
+%%
+%% <em>info/3</em> allows you to handle the messages this process will
+%% receive. It receives the message and the state previously defined.
+%% It can decide to stop the receive loop or continue receiving.
+%%
+%% <em>terminate/2</em> allows you to clean up. It receives the state
+%% previously defined.
+%%
+%% There is no required operation to perform in any of these callbacks
+%% other than returning the proper values. Make sure you always return
+%% the last modified Req so that Cowboy has the up to date information
+%% about the request.
+%%
+%% It is recommended to use hibernate if this process is not going to
+%% receive a lot of messages. It is also recommended to use a timeout
+%% value so that the connection gets closed after a long period of
+%% inactivity.
+-module(cowboy_loop_handler).
+
+-type opts() :: any().
+-type state() :: any().
+
+-callback init({atom(), http}, Req, opts())
+	-> {ok, Req, state()}
+	| {loop, Req, state()}
+	| {loop, Req, state(), hibernate}
+	| {loop, Req, state(), timeout()}
+	| {loop, Req, state(), timeout(), hibernate}
+	| {shutdown, Req, state()}
+	| {upgrade, protocol, module()}
+	when Req::cowboy_req:req().
+-callback info(any(), Req, State)
+	-> {ok, Req, State}
+	| {loop, Req, State}
+	| {loop, Req, State, hibernate}
+	when Req::cowboy_req:req(), State::state().
+-callback terminate(cowboy_req:req(), state()) -> ok.

+ 0 - 7
src/cowboy_sup.erl

@@ -32,13 +32,6 @@ start_link() ->
 
 %% supervisor.
 
--spec init([]) -> {'ok', {{'one_for_one', 10, 10}, [{
-	any(), {atom() | tuple(), atom(), 'undefined' | [any()]},
-	'permanent' | 'temporary' | 'transient',
-	'brutal_kill' | 'infinity' | non_neg_integer(),
-	'supervisor' | 'worker',
-	'dynamic' | [atom() | tuple()]}]
-}}.
 init([]) ->
 	Procs = [{cowboy_clock, {cowboy_clock, start_link, []},
 		permanent, 5000, worker, [cowboy_clock]}],

+ 39 - 18
src/cowboy_http_websocket_handler.erl → src/cowboy_websocket_handler.erl

@@ -14,13 +14,14 @@
 
 %% @doc Handler for HTTP WebSocket requests.
 %%
-%% WebSocket handlers must implement four callbacks: <em>websocket_init/3</em>,
-%% <em>websocket_handle/3</em>, <em>websocket_info/3</em> and
-%% <em>websocket_terminate/3</em>. These callbacks will only be called if the
-%% connection is upgraded to WebSocket in the HTTP handler's <em>init/3</em>
-%% callback. They are then called in that order, although
-%% <em>websocket_handle/3</em> will be called for each packet received,
-%% and <em>websocket_info</em> for each message received.
+%% WebSocket handlers must implement five callbacks: <em>init/3</em>,
+%% <em>websocket_init/3</em>, <em>websocket_handle/3</em>,
+%% <em>websocket_info/3</em> and <em>websocket_terminate/3</em>.
+%% These callbacks will only be called if the connection is upgraded
+%% to WebSocket in the HTTP handler's <em>init/3</em> callback.
+%% They are then called in that order, although <em>websocket_handle/3</em>
+%% will be called for each packet received, and <em>websocket_info</em>
+%% for each message received.
 %%
 %% <em>websocket_init/3</em> is meant for initialization. It receives
 %% information about the transport and protocol used, along with the handler
@@ -45,16 +46,36 @@
 %% <em>websocket_info/3</em> can decide to hibernate the process by adding
 %% an extra element to the returned tuple, containing the atom
 %% <em>hibernate</em>. Doing so helps save memory and improve CPU usage.
--module(cowboy_http_websocket_handler).
+-module(cowboy_websocket_handler).
 
--export([behaviour_info/1]).
+-type opts() :: any().
+-type state() :: any().
+-type terminate_reason() :: {normal, closed}
+	| {normal, timeout}
+	| {error, closed}
+	| {error, badframe}
+	| {error, atom()}.
 
-%% @private
--spec behaviour_info(_)
-	-> undefined | [{websocket_handle, 3} | {websocket_info, 3}
-		| {websocket_init, 3} | {websocket_terminate, 3}, ...].
-behaviour_info(callbacks) ->
-	[{websocket_init, 3}, {websocket_handle, 3},
-	 {websocket_info, 3}, {websocket_terminate, 3}];
-behaviour_info(_Other) ->
-	undefined.
+-callback websocket_init(atom(), Req, opts())
+	-> {ok, Req, state()}
+	| {ok, Req, state(), hibernate}
+	| {ok, Req, state(), timeout()}
+	| {ok, Req, state(), timeout(), hibernate}
+	| {shutdown, Req}
+	when Req::cowboy_req:req().
+-callback websocket_handle({text | binary | ping | pong, binary()}, Req, State)
+	-> {ok, Req, State}
+	| {ok, Req, State, hibernate}
+	| {reply, {text | binary | ping | pong, binary()}, Req, State}
+	| {reply, {text | binary | ping | pong, binary()}, Req, State, hibernate}
+	| {shutdown, Req, State}
+	when Req::cowboy_req:req(), State::state().
+-callback websocket_info(any(), Req, State)
+	-> {ok, Req, State}
+	| {ok, Req, State, hibernate}
+	| {reply, {text | binary | ping | pong, binary()}, Req, State}
+	| {reply, {text | binary | ping | pong, binary()}, Req, State, hibernate}
+	| {shutdown, Req, State}
+	when Req::cowboy_req:req(), State::state().
+-callback websocket_terminate(terminate_reason(), cowboy_req:req(), state())
+	-> ok.

+ 1 - 0
test/http_handler_loop_timeout.erl

@@ -1,6 +1,7 @@
 %% Feel free to use, reuse and abuse the code in this file.
 
 -module(http_handler_loop_timeout).
+-behaviour(cowboy_loop_handler).
 -export([init/3, info/3, terminate/2]).
 
 init({_, http}, Req, _) ->

+ 1 - 1
test/websocket_echo_handler.erl

@@ -2,7 +2,7 @@
 
 -module(websocket_echo_handler).
 -behaviour(cowboy_http_handler).
--behaviour(cowboy_http_websocket_handler).
+-behaviour(cowboy_websocket_handler).
 -export([init/3, handle/2, terminate/2]).
 -export([websocket_init/3, websocket_handle/3,
 	websocket_info/3, websocket_terminate/3]).

+ 1 - 1
test/websocket_handler.erl

@@ -2,7 +2,7 @@
 
 -module(websocket_handler).
 -behaviour(cowboy_http_handler).
--behaviour(cowboy_http_websocket_handler).
+-behaviour(cowboy_websocket_handler).
 -export([init/3, handle/2, terminate/2]).
 -export([websocket_init/3, websocket_handle/3,
 	websocket_info/3, websocket_terminate/3]).

+ 1 - 1
test/websocket_handler_init_shutdown.erl

@@ -2,7 +2,7 @@
 
 -module(websocket_handler_init_shutdown).
 -behaviour(cowboy_http_handler).
--behaviour(cowboy_http_websocket_handler).
+-behaviour(cowboy_websocket_handler).
 -export([init/3, handle/2, terminate/2]).
 -export([websocket_init/3, websocket_handle/3,
 	websocket_info/3, websocket_terminate/3]).

+ 1 - 1
test/ws_timeout_hibernate_handler.erl

@@ -2,7 +2,7 @@
 
 -module(ws_timeout_hibernate_handler).
 -behaviour(cowboy_http_handler).
--behaviour(cowboy_http_websocket_handler).
+-behaviour(cowboy_websocket_handler).
 -export([init/3, handle/2, terminate/2]).
 -export([websocket_init/3, websocket_handle/3,
 	websocket_info/3, websocket_terminate/3]).