mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 12:20:24 +00:00
Centralize stream handler error reporting in cowboy_stream
This commit is contained in:
parent
17400f73b4
commit
a6126306a2
3 changed files with 93 additions and 44 deletions
|
@ -259,10 +259,10 @@ after_parse({request, Req=#{streamid := StreamID, headers := Headers, version :=
|
||||||
end,
|
end,
|
||||||
State = set_timeout(State1),
|
State = set_timeout(State1),
|
||||||
parse(Buffer, commands(State, StreamID, Commands))
|
parse(Buffer, commands(State, StreamID, Commands))
|
||||||
catch Class:Reason ->
|
catch Class:Exception ->
|
||||||
error_logger:error_msg("Exception occurred in "
|
cowboy_stream:report_error(init,
|
||||||
"cowboy_stream:init(~p, ~p, ~p) with reason ~p:~p.",
|
[StreamID, Req, Opts],
|
||||||
[StreamID, Req, Opts, Class, Reason]),
|
Class, Exception, erlang:get_stacktrace()),
|
||||||
ok %% @todo send a proper response, etc. note that terminate must NOT be called
|
ok %% @todo send a proper response, etc. note that terminate must NOT be called
|
||||||
%% @todo Status code.
|
%% @todo Status code.
|
||||||
% stream_reset(State, StreamID, {internal_error, {Class, Reason},
|
% stream_reset(State, StreamID, {internal_error, {Class, Reason},
|
||||||
|
@ -277,10 +277,10 @@ after_parse({data, StreamID, IsFin, Data, State=#state{
|
||||||
Streams = lists:keyreplace(StreamID, #stream.id, Streams0,
|
Streams = lists:keyreplace(StreamID, #stream.id, Streams0,
|
||||||
Stream#stream{state=StreamState}),
|
Stream#stream{state=StreamState}),
|
||||||
parse(Buffer, commands(State#state{streams=Streams}, StreamID, Commands))
|
parse(Buffer, commands(State#state{streams=Streams}, StreamID, Commands))
|
||||||
catch Class:Reason ->
|
catch Class:Exception ->
|
||||||
error_logger:error_msg("Exception occurred in "
|
cowboy_stream:report_error(data,
|
||||||
"cowboy_stream:data(~p, ~p, ~p, ~p) with reason ~p:~p.",
|
[StreamID, IsFin, Data, StreamState0],
|
||||||
[StreamID, IsFin, Data, StreamState0, Class, Reason]),
|
Class, Exception, erlang:get_stacktrace()),
|
||||||
%% @todo Bad value returned here. Crashes.
|
%% @todo Bad value returned here. Crashes.
|
||||||
ok
|
ok
|
||||||
%% @todo
|
%% @todo
|
||||||
|
@ -741,10 +741,10 @@ info(State=#state{streams=Streams0}, StreamID, Msg) ->
|
||||||
Streams = lists:keyreplace(StreamID, #stream.id, Streams0,
|
Streams = lists:keyreplace(StreamID, #stream.id, Streams0,
|
||||||
Stream#stream{state=StreamState}),
|
Stream#stream{state=StreamState}),
|
||||||
commands(State#state{streams=Streams}, StreamID, Commands)
|
commands(State#state{streams=Streams}, StreamID, Commands)
|
||||||
catch Class:Reason ->
|
catch Class:Exception ->
|
||||||
error_logger:error_msg("Exception occurred in "
|
cowboy_stream:report_error(info,
|
||||||
"cowboy_stream:info(~p, ~p, ~p) with reason ~p:~p.",
|
[StreamID, Msg, StreamState0],
|
||||||
[StreamID, Msg, StreamState0, Class, Reason]),
|
Class, Exception, erlang:get_stacktrace()),
|
||||||
ok
|
ok
|
||||||
%% @todo
|
%% @todo
|
||||||
% stream_reset(State, StreamID, {internal_error, {Class, Reason},
|
% stream_reset(State, StreamID, {internal_error, {Class, Reason},
|
||||||
|
@ -984,10 +984,10 @@ stream_terminate(State0=#state{socket=Socket, transport=Transport,
|
||||||
stream_call_terminate(StreamID, Reason, StreamState) ->
|
stream_call_terminate(StreamID, Reason, StreamState) ->
|
||||||
try
|
try
|
||||||
cowboy_stream:terminate(StreamID, Reason, StreamState)
|
cowboy_stream:terminate(StreamID, Reason, StreamState)
|
||||||
catch Class:Reason ->
|
catch Class:Exception ->
|
||||||
error_logger:error_msg("Exception occurred in "
|
cowboy_stream:report_error(terminate,
|
||||||
"cowboy_stream:terminate(~p, ~p, ~p) with reason ~p:~p.",
|
[StreamID, Reason, StreamState],
|
||||||
[StreamID, Reason, StreamState, Class, Reason])
|
Class, Exception, erlang:get_stacktrace())
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% @todo max_reqs also
|
%% @todo max_reqs also
|
||||||
|
@ -1051,15 +1051,18 @@ error_terminate(StatusCode0, State=#state{ref=Ref, socket=Socket, transport=Tran
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
{response, StatusCode, RespHeaders, RespBody}
|
Resp = {response, StatusCode0, #{<<"content-length">> => <<"0">>}, <<>>},
|
||||||
= cowboy_stream:early_error(StreamID, Reason, PartialReq,
|
try cowboy_stream:early_error(StreamID, Reason, PartialReq, Resp, Opts) of
|
||||||
{response, StatusCode0, #{
|
{response, StatusCode, RespHeaders, RespBody} ->
|
||||||
<<"content-length">> => <<"0">>
|
Transport:send(Socket, [
|
||||||
}, <<>>}, Opts),
|
cow_http:response(StatusCode, 'HTTP/1.1', maps:to_list(RespHeaders)),
|
||||||
Transport:send(Socket, [
|
RespBody
|
||||||
cow_http:response(StatusCode, 'HTTP/1.1', maps:to_list(RespHeaders)),
|
])
|
||||||
RespBody
|
catch Class:Exception ->
|
||||||
]),
|
cowboy_stream:report_error(early_error,
|
||||||
|
[StreamID, Reason, PartialReq, Resp, Opts],
|
||||||
|
Class, Exception, erlang:get_stacktrace())
|
||||||
|
end,
|
||||||
terminate(State, Reason).
|
terminate(State, Reason).
|
||||||
|
|
||||||
-spec terminate(_, _) -> no_return().
|
-spec terminate(_, _) -> no_return().
|
||||||
|
|
|
@ -305,11 +305,11 @@ frame(State0=#state{remote_window=ConnWindow, streams=Streams},
|
||||||
commands(State,
|
commands(State,
|
||||||
Stream#stream{state=StreamState, remote_window=StreamWindow - DataLen,
|
Stream#stream{state=StreamState, remote_window=StreamWindow - DataLen,
|
||||||
body_length=Len}, Commands)
|
body_length=Len}, Commands)
|
||||||
catch Class:Reason ->
|
catch Class:Exception ->
|
||||||
error_logger:error_msg("Exception occurred in "
|
cowboy_stream:report_error(data,
|
||||||
"cowboy_stream:data(~p, ~p, ~p, ~p) with reason ~p:~p.",
|
[StreamID, IsFin, Data, StreamState0],
|
||||||
[StreamID, IsFin0, Data, StreamState0, Class, Reason]),
|
Class, Exception, erlang:get_stacktrace()),
|
||||||
stream_reset(State, StreamID, {internal_error, {Class, Reason},
|
stream_reset(State, StreamID, {internal_error, {Class, Exception},
|
||||||
'Exception occurred in cowboy_stream:data/4.'})
|
'Exception occurred in cowboy_stream:data/4.'})
|
||||||
end;
|
end;
|
||||||
#stream{remote=fin} ->
|
#stream{remote=fin} ->
|
||||||
|
@ -441,11 +441,11 @@ info(State=#state{streams=Streams}, StreamID, Msg) ->
|
||||||
try cowboy_stream:info(StreamID, Msg, StreamState0) of
|
try cowboy_stream:info(StreamID, Msg, StreamState0) of
|
||||||
{Commands, StreamState} ->
|
{Commands, StreamState} ->
|
||||||
commands(State, Stream#stream{state=StreamState}, Commands)
|
commands(State, Stream#stream{state=StreamState}, Commands)
|
||||||
catch Class:Reason ->
|
catch Class:Exception ->
|
||||||
error_logger:error_msg("Exception occurred in "
|
cowboy_stream:report_error(info,
|
||||||
"cowboy_stream:info(~p, ~p, ~p) with reason ~p:~p.",
|
[StreamID, Msg, StreamState0],
|
||||||
[StreamID, Msg, StreamState0, Class, Reason]),
|
Class, Exception, erlang:get_stacktrace()),
|
||||||
stream_reset(State, StreamID, {internal_error, {Class, Reason},
|
stream_reset(State, StreamID, {internal_error, {Class, Exception},
|
||||||
'Exception occurred in cowboy_stream:info/3.'})
|
'Exception occurred in cowboy_stream:info/3.'})
|
||||||
end;
|
end;
|
||||||
false ->
|
false ->
|
||||||
|
@ -776,11 +776,11 @@ stream_handler_init(State=#state{opts=Opts,
|
||||||
remote=RemoteIsFin, local=LocalIsFin,
|
remote=RemoteIsFin, local=LocalIsFin,
|
||||||
local_window=LocalWindow, remote_window=RemoteWindow},
|
local_window=LocalWindow, remote_window=RemoteWindow},
|
||||||
Commands)
|
Commands)
|
||||||
catch Class:Reason ->
|
catch Class:Exception ->
|
||||||
error_logger:error_msg("Exception occurred in "
|
cowboy_stream:report_error(init,
|
||||||
"cowboy_stream:init(~p, ~p, ~p) with reason ~p:~p.",
|
[StreamID, Req, Opts],
|
||||||
[StreamID, Req, Opts, Class, Reason]),
|
Class, Exception, erlang:get_stacktrace()),
|
||||||
stream_reset(State, StreamID, {internal_error, {Class, Reason},
|
stream_reset(State, StreamID, {internal_error, {Class, Exception},
|
||||||
'Exception occurred in cowboy_stream:init/3.'})
|
'Exception occurred in cowboy_stream:init/3.'})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -832,10 +832,10 @@ stream_terminate(State=#state{socket=Socket, transport=Transport,
|
||||||
stream_call_terminate(StreamID, Reason, StreamState) ->
|
stream_call_terminate(StreamID, Reason, StreamState) ->
|
||||||
try
|
try
|
||||||
cowboy_stream:terminate(StreamID, Reason, StreamState)
|
cowboy_stream:terminate(StreamID, Reason, StreamState)
|
||||||
catch Class:Reason ->
|
catch Class:Exception ->
|
||||||
error_logger:error_msg("Exception occurred in "
|
cowboy_stream:report_error(terminate,
|
||||||
"cowboy_stream:terminate(~p, ~p, ~p) with reason ~p:~p.",
|
[StreamID, Reason, StreamState],
|
||||||
[StreamID, Reason, StreamState, Class, Reason])
|
Class, Exception, erlang:get_stacktrace())
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Headers encode/decode.
|
%% Headers encode/decode.
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
-export([info/3]).
|
-export([info/3]).
|
||||||
-export([terminate/3]).
|
-export([terminate/3]).
|
||||||
-export([early_error/5]).
|
-export([early_error/5]).
|
||||||
|
-export([report_error/5]).
|
||||||
|
|
||||||
%% Note that this and other functions in this module do NOT catch
|
%% Note that this and other functions in this module do NOT catch
|
||||||
%% exceptions. We want the exception to go all the way down to the
|
%% exceptions. We want the exception to go all the way down to the
|
||||||
|
@ -144,3 +145,48 @@ early_error(StreamID, Reason, PartialReq, Resp, Opts) ->
|
||||||
Handler:early_error(StreamID, Reason,
|
Handler:early_error(StreamID, Reason,
|
||||||
PartialReq, Resp, Opts#{stream_handlers => Tail})
|
PartialReq, Resp, Opts#{stream_handlers => Tail})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec report_error(atom(), list(), error | exit | throw, any(), list()) -> ok.
|
||||||
|
report_error(init, [StreamID, Req, Opts], Class, Exception, Stacktrace) ->
|
||||||
|
error_logger:error_msg(
|
||||||
|
"Unhandled exception ~p:~p in cowboy_stream:init(~p, Req, Opts)~n"
|
||||||
|
"Stacktrace: ~p~n"
|
||||||
|
"Req: ~p~n"
|
||||||
|
"Opts: ~p~n",
|
||||||
|
[Class, Exception, StreamID, Stacktrace, Req, Opts]);
|
||||||
|
report_error(data, [StreamID, IsFin, Data, State], Class, Exception, Stacktrace) ->
|
||||||
|
error_logger:error_msg(
|
||||||
|
"Unhandled exception ~p:~p in cowboy_stream:data(~p, ~p, Data, State)~n"
|
||||||
|
"Stacktrace: ~p~n"
|
||||||
|
"Data: ~p~n"
|
||||||
|
"State: ~p~n",
|
||||||
|
[Class, Exception, StreamID, IsFin, Stacktrace, Data, State]);
|
||||||
|
report_error(info, [StreamID, Msg, State], Class, Exception, Stacktrace) ->
|
||||||
|
error_logger:error_msg(
|
||||||
|
"Unhandled exception ~p:~p in cowboy_stream:info(~p, Msg, State)~n"
|
||||||
|
"Stacktrace: ~p~n"
|
||||||
|
"Msg: ~p~n"
|
||||||
|
"State: ~p~n",
|
||||||
|
[Class, Exception, StreamID, Stacktrace, Msg, State]);
|
||||||
|
report_error(terminate, [StreamID, Reason, State], Class, Exception, Stacktrace) ->
|
||||||
|
error_logger:error_msg(
|
||||||
|
"Unhandled exception ~p:~p in cowboy_stream:terminate(~p, Reason, State)~n"
|
||||||
|
"Stacktrace: ~p~n"
|
||||||
|
"Reason: ~p~n"
|
||||||
|
"State: ~p~n",
|
||||||
|
[Class, Exception, StreamID, Stacktrace, Reason, State]);
|
||||||
|
report_error(early_error, [StreamID, Reason, PartialReq, Resp, Opts], Class, Exception, Stacktrace) ->
|
||||||
|
error_logger:error_msg(
|
||||||
|
"Unhandled exception ~p:~p in cowboy_stream:early_error(~p, Reason, PartialReq, Resp, Opts)~n"
|
||||||
|
"Stacktrace: ~p~n"
|
||||||
|
"Reason: ~p~n"
|
||||||
|
"PartialReq: ~p~n"
|
||||||
|
"Resp: ~p~n"
|
||||||
|
"Opts: ~p~n",
|
||||||
|
[Class, Exception, StreamID, Stacktrace, Reason, PartialReq, Resp, Opts]);
|
||||||
|
report_error(Callback, _, Class, Reason, Stacktrace) ->
|
||||||
|
error_logger:error_msg(
|
||||||
|
"Exception occurred in unknown callback ~p~n"
|
||||||
|
"Reason: ~p:~p~n"
|
||||||
|
"Stacktrace: ~p~n",
|
||||||
|
[Callback, Class, Reason, Stacktrace]).
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue