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

Move recursion out of a try .. catch block.

Fixes issue #31.

Recursion shouldn't happen in a single catch statement or inside
a try .. catch statement. The only safe construct for catching
exceptions and perform recursion when everything goes well is
to put the recursive call inside a try .. of .. catch construct
in the of .. catch block.

Otherwise the stack gets filled with exception-related information
since they can still be caught if we were to send them and unfold
the whole thing.

Thanks go to lpgauth for reporting the issue and people on IRC
for explaining the hows and whys.
This commit is contained in:
Loïc Hoguin 2011-07-06 20:00:08 +02:00
parent 108a491f55
commit aa0a66749e

View file

@ -223,25 +223,24 @@ handler_loop(HandlerState, Req, State=#state{handler={Handler, Opts}}) ->
-spec handler_terminate(any(), #http_req{}, #state{}) -> ok. -spec handler_terminate(any(), #http_req{}, #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}}) ->
try HandlerRes = try
HandlerRes = Handler:terminate(Req#http_req{resp_state=locked}, Handler:terminate(Req#http_req{resp_state=locked}, HandlerState)
HandlerState),
BodyRes = ensure_body_processed(Req),
RespRes = ensure_response(Req, State),
case {HandlerRes, BodyRes, RespRes, State#state.connection} of
{ok, ok, ok, keepalive} ->
?MODULE:parse_request(State#state{buffer=Buffer});
_Closed ->
terminate(State)
end
catch Class:Reason -> catch Class:Reason ->
terminate(State),
error_logger:error_msg( error_logger:error_msg(
"** Handler ~p terminating in terminate/2 for the reason ~p:~p~n" "** Handler ~p terminating in terminate/2 for the reason ~p:~p~n"
"** Options were ~p~n** Handler state was ~p~n" "** Options were ~p~n** Handler state was ~p~n"
"** Request was ~p~n** Stacktrace: ~p~n~n", "** Request was ~p~n** Stacktrace: ~p~n~n",
[Handler, Class, Reason, Opts, [Handler, Class, Reason, Opts,
HandlerState, Req, erlang:get_stacktrace()]) HandlerState, Req, erlang:get_stacktrace()]),
error
end,
BodyRes = ensure_body_processed(Req),
RespRes = ensure_response(Req, State),
case {HandlerRes, BodyRes, RespRes, State#state.connection} of
{ok, ok, ok, keepalive} ->
?MODULE:parse_request(State#state{buffer=Buffer});
_Closed ->
terminate(State)
end. end.
-spec ensure_body_processed(#http_req{}) -> ok | close. -spec ensure_body_processed(#http_req{}) -> ok | close.