diff options
-rw-r--r-- | src/cowboy_http.erl | 2 | ||||
-rw-r--r-- | src/cowboy_http2.erl | 2 | ||||
-rw-r--r-- | src/cowboy_websocket.erl | 35 | ||||
-rw-r--r-- | test/sys_SUITE.erl | 5 |
4 files changed, 39 insertions, 5 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index 62e5176..6a75a1a 100644 --- a/src/cowboy_http.erl +++ b/src/cowboy_http.erl @@ -192,6 +192,7 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport, opts=Opts, loop(State, Buffer); %% System messages. {'EXIT', Parent, Reason} -> + %% @todo We should exit gracefully, if possible. exit(Reason); {system, From, Request} -> sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {State, Buffer}); @@ -1224,6 +1225,7 @@ system_continue(_, _, {State, Buffer}) -> -spec system_terminate(any(), _, _, {#state{}, binary()}) -> no_return(). system_terminate(Reason, _, _, {State, _}) -> + %% @todo We should exit gracefully, if possible. terminate(State, Reason). -spec system_code_change(Misc, _, _, _) -> {ok, Misc} when Misc::{#state{}, binary()}. diff --git a/src/cowboy_http2.erl b/src/cowboy_http2.erl index 7dbfb24..b21d6da 100644 --- a/src/cowboy_http2.erl +++ b/src/cowboy_http2.erl @@ -225,6 +225,7 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport, terminate(State, {socket_error, Reason, 'An error has occurred on the socket.'}); %% System messages. {'EXIT', Parent, Reason} -> + %% @todo We should exit gracefully. exit(Reason); {system, From, Request} -> sys:handle_system_msg(Request, From, Parent, ?MODULE, [], {State, Buffer}); @@ -1125,6 +1126,7 @@ system_continue(_, _, {State, Buffer}) -> -spec system_terminate(any(), _, _, {#state{}, binary()}) -> no_return(). system_terminate(Reason, _, _, {State, _}) -> + %% @todo We should exit gracefully, if possible. terminate(State, Reason). -spec system_code_change(Misc, _, _, _) -> {ok, Misc} when Misc::{#state{}, binary()}. diff --git a/src/cowboy_websocket.erl b/src/cowboy_websocket.erl index 6b59689..45e96b6 100644 --- a/src/cowboy_websocket.erl +++ b/src/cowboy_websocket.erl @@ -22,6 +22,10 @@ -export([takeover/7]). -export([handler_loop/3]). +-export([system_continue/3]). +-export([system_terminate/4]). +-export([system_code_change/4]). + -type call_result(State) :: {ok, State} | {ok, State, hibernate} | {reply, cow_ws:frame() | [cow_ws:frame()], State} @@ -58,6 +62,8 @@ -export_type([opts/0]). -record(state, { + parent = undefined :: pid(), + ref :: ranch:ref(), socket = undefined :: inet:socket() | undefined, transport = undefined :: module(), handler :: module(), @@ -199,11 +205,12 @@ websocket_handshake(State=#state{key=Key}, %% @todo Keep parent and handle system messages. -spec takeover(pid(), ranch:ref(), inet:socket(), module(), any(), binary(), {#state{}, any()}) -> ok. -takeover(_Parent, Ref, Socket, Transport, _Opts, Buffer, +takeover(Parent, Ref, Socket, Transport, _Opts, Buffer, {State0=#state{handler=Handler}, HandlerState}) -> %% @todo We should have an option to disable this behavior. ranch:remove_connection(Ref), - State1 = handler_loop_timeout(State0#state{socket=Socket, transport=Transport}), + State1 = handler_loop_timeout(State0#state{parent=Parent, + ref=Ref, socket=Socket, transport=Transport}), State = State1#state{key=undefined, messages=Transport:messages()}, case erlang:function_exported(Handler, websocket_init, 1) of true -> handler_call(State, HandlerState, Buffer, websocket_init, undefined, fun handler_before_loop/3); @@ -235,7 +242,7 @@ handler_loop_timeout(State=#state{timeout=Timeout, timeout_ref=PrevRef}) -> -spec handler_loop(#state{}, any(), binary()) -> {ok, cowboy_middleware:env()}. -handler_loop(State=#state{socket=Socket, messages={OK, Closed, Error}, +handler_loop(State=#state{parent=Parent, socket=Socket, messages={OK, Closed, Error}, timeout_ref=TRef}, HandlerState, SoFar) -> receive {OK, Socket, Data} -> @@ -250,6 +257,13 @@ handler_loop(State=#state{socket=Socket, messages={OK, Closed, Error}, websocket_close(State, HandlerState, timeout); {timeout, OlderTRef, ?MODULE} when is_reference(OlderTRef) -> handler_loop(State, HandlerState, SoFar); + %% System messages. + {'EXIT', Parent, Reason} -> + %% @todo We should exit gracefully. + exit(Reason); + {system, From, Request} -> + sys:handle_system_msg(Request, From, Parent, ?MODULE, [], + {State, HandlerState, SoFar}); %% Calls from supervisor module. {'$gen_call', From, Call} -> cowboy_children:handle_supervisor_call(Call, From, [], ?MODULE), @@ -441,3 +455,18 @@ terminate(State, HandlerState, Reason) -> handler_terminate(#state{handler=Handler, req=Req}, HandlerState, Reason) -> cowboy_handler:terminate(Reason, Req, HandlerState, Handler). + +%% System callbacks. + +-spec system_continue(_, _, {#state{}, any(), binary()}) -> ok. +system_continue(_, _, {State, HandlerState, SoFar}) -> + handler_loop(State, HandlerState, SoFar). + +-spec system_terminate(any(), _, _, {#state{}, any(), binary()}) -> no_return(). +system_terminate(Reason, _, _, {State, HandlerState, _}) -> + %% @todo We should exit gracefully, if possible. + terminate(State, HandlerState, Reason). + +-spec system_code_change(Misc, _, _, _) -> {ok, Misc} when Misc::{#state{}, any(), binary()}. +system_code_change(Misc, _, _, _) -> + {ok, Misc}. diff --git a/test/sys_SUITE.erl b/test/sys_SUITE.erl index 86a5dc1..3850796 100644 --- a/test/sys_SUITE.erl +++ b/test/sys_SUITE.erl @@ -27,6 +27,8 @@ groups() -> [{sys, [parallel], ct_helper:all(?MODULE)}]. init_per_suite(Config) -> + ct:print("This test suite will produce error reports about " + "EXIT signals for unknown processes."), ProtoOpts = #{ env => #{dispatch => init_dispatch(Config)} }, @@ -467,8 +469,7 @@ trap_exit_other_exit_ws(Config) -> {ok, {http_response, {1, 1}, 101, _}, _} = erlang:decode_packet(http, Handshake, []), timer:sleep(100), Pid = do_get_remote_pid_tcp(Socket), - Parent = do_get_parent_pid(Pid), - Pid ! {'EXIT', Parent, shutdown}, + Pid ! {'EXIT', self(), shutdown}, %% The process stays alive. {error, timeout} = gen_tcp:recv(Socket, 0, 1000), true = is_process_alive(Pid), |