0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 12:20:24 +00:00

Send a meaningful error to error_logger on handler crashes.

Inspired by gen_server and friends. Should fix issue #13.
This commit is contained in:
Loïc Hoguin 2011-05-20 01:28:55 +02:00
parent 548a9a15b8
commit 4c4030a792

View file

@ -172,40 +172,59 @@ dispatch(Req=#http_req{host=Host, path=Path},
-spec handler_init(Req::#http_req{}, State::#state{}) -> ok. -spec handler_init(Req::#http_req{}, State::#state{}) -> ok.
handler_init(Req, State=#state{ handler_init(Req, State=#state{
transport=Transport, handler={Handler, Opts}}) -> transport=Transport, handler={Handler, Opts}}) ->
case catch Handler:init({Transport:name(), http}, Req, Opts) of try Handler:init({Transport:name(), http}, Req, Opts) of
{ok, Req2, HandlerState} -> {ok, Req2, HandlerState} ->
handler_loop(HandlerState, Req2, State); handler_loop(HandlerState, Req2, State);
%% @todo {upgrade, transport, Module} %% @todo {upgrade, transport, Module}
{upgrade, protocol, Module} -> {upgrade, protocol, Module} ->
Module:upgrade(Handler, Opts, Req); Module:upgrade(Handler, Opts, Req)
{'EXIT', _Reason} -> catch Class:Reason ->
error_terminate(500, State) error_terminate(500, State),
error_logger:error_msg(
"** Handler ~p terminating in init/3 for the reason ~p:~p~n"
"** Options were ~p~n** Request was ~p~n** Stacktrace: ~p~n~n",
[Handler, Class, Reason, Opts, Req, erlang:get_stacktrace()])
end. end.
-spec handler_loop(HandlerState::term(), Req::#http_req{}, -spec handler_loop(HandlerState::term(), Req::#http_req{},
State::#state{}) -> ok. State::#state{}) -> ok.
handler_loop(HandlerState, Req, State=#state{handler={Handler, _Opts}}) -> handler_loop(HandlerState, Req, State=#state{handler={Handler, Opts}}) ->
case catch Handler:handle(Req#http_req{resp_state=waiting}, try Handler:handle(Req#http_req{resp_state=waiting}, HandlerState) of
HandlerState) of
{ok, Req2, HandlerState2} -> {ok, Req2, HandlerState2} ->
handler_terminate(HandlerState2, Req2, State); handler_terminate(HandlerState2, Req2, State)
{'EXIT', _Reason} -> catch Class:Reason ->
terminate(State) terminate(State),
error_logger:error_msg(
"** Handler ~p terminating in handle/2 for the reason ~p:~p~n"
"** Options were ~p~n** Handler state was ~p~n"
"** Request was ~p~n** Stacktrace: ~p~n~n",
[Handler, Class, Reason, Opts,
HandlerState, Req, erlang:get_stacktrace()])
end. end.
-spec handler_terminate(HandlerState::term(), Req::#http_req{}, -spec handler_terminate(HandlerState::term(), Req::#http_req{},
State::#state{}) -> ok. State::#state{}) -> ok.
handler_terminate(HandlerState, Req=#http_req{buffer=Buffer}, handler_terminate(HandlerState, Req=#http_req{buffer=Buffer},
State=#state{handler={Handler, _Opts}}) -> State=#state{handler={Handler, Opts}}) ->
HandlerRes = (catch Handler:terminate( try
Req#http_req{resp_state=locked}, HandlerState)), HandlerRes = Handler:terminate(Req#http_req{resp_state=locked},
BodyRes = ensure_body_processed(Req), HandlerState),
RespRes = ensure_response(Req, State), BodyRes = ensure_body_processed(Req),
case {HandlerRes, BodyRes, RespRes, State#state.connection} of RespRes = ensure_response(Req, State),
{ok, ok, ok, keepalive} -> case {HandlerRes, BodyRes, RespRes, State#state.connection} of
?MODULE:parse_request(State#state{buffer=Buffer}); {ok, ok, ok, keepalive} ->
_Closed -> ?MODULE:parse_request(State#state{buffer=Buffer});
terminate(State) _Closed ->
terminate(State)
end
catch Class:Reason ->
terminate(State),
error_logger:error_msg(
"** Handler ~p terminating in terminate/2 for the reason ~p:~p~n"
"** Options were ~p~n** Handler state was ~p~n"
"** Request was ~p~n** Stacktrace: ~p~n~n",
[Handler, Class, Reason, Opts,
HandlerState, Req, erlang:get_stacktrace()])
end. end.
-spec ensure_body_processed(Req::#http_req{}) -> ok | close. -spec ensure_body_processed(Req::#http_req{}) -> ok | close.