diff options
Diffstat (limited to 'src/cowboy_websocket.erl')
-rw-r--r-- | src/cowboy_websocket.erl | 58 |
1 files changed, 39 insertions, 19 deletions
diff --git a/src/cowboy_websocket.erl b/src/cowboy_websocket.erl index e0b20ca..c700af9 100644 --- a/src/cowboy_websocket.erl +++ b/src/cowboy_websocket.erl @@ -33,8 +33,32 @@ -type frag_state() :: undefined | {nofin, opcode(), binary()} | {fin, opcode(), binary()}. -type rsv() :: << _:3 >>. --type terminate_reason() :: {normal | error | remote, atom()} - | {remote, close_code(), binary()}. +-type terminate_reason() :: normal | shutdown | timeout + | remote | {remote, close_code(), binary()} + | {error, badencoding | badframe | closed | atom()} + | {crash, error | exit | throw, any()}. + +-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(). +-callback websocket_handle({text | binary | ping | pong, binary()}, Req, State) + -> {ok, Req, State} + | {ok, Req, State, hibernate} + | {reply, frame() | [frame()], Req, State} + | {reply, frame() | [frame()], Req, State, hibernate} + | {shutdown, Req, State} + when Req::cowboy_req:req(), State::any(). +-callback websocket_info(any(), Req, State) + -> {ok, Req, State} + | {ok, Req, State, hibernate} + | {reply, frame() | [frame()], Req, State} + | {reply, frame() | [frame()], Req, State, hibernate} + | {shutdown, Req, State} + when Req::cowboy_req:req(), State::any(). +%% @todo optional -callback terminate(terminate_reason(), cowboy_req:req(), state()) -> ok. -record(state, { env :: cowboy_middleware:env(), @@ -181,7 +205,7 @@ handler_loop(State=#state{socket=Socket, messages={OK, Closed, Error}, {Error, Socket, Reason} -> handler_terminate(State, Req, HandlerState, {error, Reason}); {timeout, TRef, ?MODULE} -> - websocket_close(State, Req, HandlerState, {normal, timeout}); + websocket_close(State, Req, HandlerState, timeout); {timeout, OlderTRef, ?MODULE} when is_reference(OlderTRef) -> handler_loop(State, Req, HandlerState, SoFar); Message -> @@ -487,7 +511,7 @@ websocket_payload_loop(State=#state{socket=Socket, transport=Transport, {Error, Socket, Reason} -> handler_terminate(State, Req, HandlerState, {error, Reason}); {timeout, TRef, ?MODULE} -> - websocket_close(State, Req, HandlerState, {normal, timeout}); + websocket_close(State, Req, HandlerState, timeout); {timeout, OlderTRef, ?MODULE} when is_reference(OlderTRef) -> websocket_payload_loop(State, Req, HandlerState, Opcode, Len, MaskKey, Unmasked, UnmaskedLen, Rsv); @@ -524,7 +548,7 @@ websocket_dispatch(State, Req, HandlerState, RemainingData, 2, Payload) -> websocket_handle, {binary, Payload}, fun websocket_data/4); %% Close control frame. websocket_dispatch(State, Req, HandlerState, _RemainingData, 8, <<>>) -> - websocket_close(State, Req, HandlerState, {remote, closed}); + websocket_close(State, Req, HandlerState, remote); websocket_dispatch(State, Req, HandlerState, _RemainingData, 8, << Code:16, Payload/bits >>) -> websocket_close(State, Req, HandlerState, {remote, Code, Payload}); @@ -558,8 +582,7 @@ handler_call(State=#state{handler=Handler}, Req, HandlerState, {ok, State2} -> NextState(State2, Req2, HandlerState2, RemainingData); {shutdown, State2} -> - handler_terminate(State2, Req2, HandlerState2, - {normal, shutdown}); + handler_terminate(State2, Req2, HandlerState2, shutdown); {{error, _} = Error, State2} -> handler_terminate(State2, Req2, HandlerState2, Error) end; @@ -570,8 +593,7 @@ handler_call(State=#state{handler=Handler}, Req, HandlerState, NextState(State2#state{hibernate=true}, Req2, HandlerState2, RemainingData); {shutdown, State2} -> - handler_terminate(State2, Req2, HandlerState2, - {normal, shutdown}); + handler_terminate(State2, Req2, HandlerState2, shutdown); {{error, _} = Error, State2} -> handler_terminate(State2, Req2, HandlerState2, Error) end; @@ -580,8 +602,7 @@ handler_call(State=#state{handler=Handler}, Req, HandlerState, {ok, State2} -> NextState(State2, Req2, HandlerState2, RemainingData); {shutdown, State2} -> - handler_terminate(State2, Req2, HandlerState2, - {normal, shutdown}); + handler_terminate(State2, Req2, HandlerState2, shutdown); {{error, _} = Error, State2} -> handler_terminate(State2, Req2, HandlerState2, Error) end; @@ -591,15 +612,14 @@ handler_call(State=#state{handler=Handler}, Req, HandlerState, NextState(State2#state{hibernate=true}, Req2, HandlerState2, RemainingData); {shutdown, State2} -> - handler_terminate(State2, Req2, HandlerState2, - {normal, shutdown}); + handler_terminate(State2, Req2, HandlerState2, shutdown); {{error, _} = Error, State2} -> handler_terminate(State2, Req2, HandlerState2, Error) end; {shutdown, Req2, HandlerState2} -> - websocket_close(State, Req2, HandlerState2, {normal, shutdown}) + websocket_close(State, Req2, HandlerState2, shutdown) catch Class:Reason -> - _ = websocket_close(State, Req, HandlerState, {error, handler}), + _ = websocket_close(State, Req, HandlerState, {crash, Class, Reason}), erlang:Class([ {reason, Reason}, {mfa, {Handler, Callback, 3}}, @@ -696,15 +716,15 @@ websocket_send_many([Frame|Tail], State) -> websocket_close(State=#state{socket=Socket, transport=Transport}, Req, HandlerState, Reason) -> case Reason of - {normal, _} -> + Normal when Normal =:= shutdown; Normal =:= timeout -> Transport:send(Socket, << 1:1, 0:3, 8:4, 0:1, 2:7, 1000:16 >>); {error, badframe} -> Transport:send(Socket, << 1:1, 0:3, 8:4, 0:1, 2:7, 1002:16 >>); {error, badencoding} -> Transport:send(Socket, << 1:1, 0:3, 8:4, 0:1, 2:7, 1007:16 >>); - {error, handler} -> + {crash, _, _} -> Transport:send(Socket, << 1:1, 0:3, 8:4, 0:1, 2:7, 1011:16 >>); - {remote, closed} -> + remote -> Transport:send(Socket, << 1:1, 0:3, 8:4, 0:8 >>); {remote, Code, _} -> Transport:send(Socket, << 1:1, 0:3, 8:4, 0:1, 2:7, Code:16 >>) @@ -716,5 +736,5 @@ websocket_close(State=#state{socket=Socket, transport=Transport}, when Req::cowboy_req:req(). handler_terminate(#state{env=Env, handler=Handler}, Req, HandlerState, Reason) -> - _ = cowboy_handler:terminate(Req, Env, Handler, HandlerState, Reason), + cowboy_handler:terminate(Reason, Req, HandlerState, Handler), {ok, Req, [{result, closed}|Env]}. |