From 3a7232b019f975a594a696eace46abcbfeec5b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Tue, 31 Dec 2019 15:10:38 +0100 Subject: No longer use erlang:get_stacktrace/0 It has been deprecated in OTP and the new way is available on all supported OTP versions. --- src/cowboy_handler.erl | 9 ++---- src/cowboy_http.erl | 24 +++++++--------- src/cowboy_http2.erl | 24 +++++++--------- src/cowboy_loop.erl | 9 ++---- src/cowboy_req.erl | 20 ++++++------- src/cowboy_rest.erl | 74 +++++++++++++++++++++++------------------------- src/cowboy_stream_h.erl | 31 ++++---------------- src/cowboy_websocket.erl | 9 ++---- 8 files changed, 75 insertions(+), 125 deletions(-) (limited to 'src') diff --git a/src/cowboy_handler.erl b/src/cowboy_handler.erl index bf42b77..c0f7ff7 100644 --- a/src/cowboy_handler.erl +++ b/src/cowboy_handler.erl @@ -20,10 +20,6 @@ -module(cowboy_handler). -behaviour(cowboy_middleware). --ifdef(OTP_RELEASE). --compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). --endif. - -export([execute/2]). -export([terminate/4]). @@ -46,10 +42,9 @@ execute(Req, Env=#{handler := Handler, handler_opts := HandlerOpts}) -> Mod:upgrade(Req2, Env, Handler, State); {Mod, Req2, State, Opts} -> Mod:upgrade(Req2, Env, Handler, State, Opts) - catch Class:Reason -> - StackTrace = erlang:get_stacktrace(), + catch Class:Reason:Stacktrace -> terminate({crash, Class, Reason}, Req, HandlerOpts, Handler), - erlang:raise(Class, Reason, StackTrace) + erlang:raise(Class, Reason, Stacktrace) end. -spec terminate(any(), Req | undefined, any(), module()) -> ok when Req::cowboy_req:req(). diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index f128a44..90e3203 100644 --- a/src/cowboy_http.erl +++ b/src/cowboy_http.erl @@ -14,10 +14,6 @@ -module(cowboy_http). --ifdef(OTP_RELEASE). --compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). --endif. - -export([init/6]). -export([system_continue/3]). @@ -335,10 +331,10 @@ after_parse({request, Req=#{streamid := StreamID, method := Method, end, State = set_timeout(State1, idle_timeout), parse(Buffer, commands(State, StreamID, Commands)) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(init, [StreamID, Req, Opts], - Class, Exception, erlang:get_stacktrace()), Opts), + Class, Exception, Stacktrace), Opts), early_error(500, State0, {internal_error, {Class, Exception}, 'Unhandled exception in cowboy_stream:init/3.'}, Req), parse(Buffer, State0) @@ -357,10 +353,10 @@ after_parse({data, StreamID, IsFin, Data, State0=#state{opts=Opts, buffer=Buffer end), State = update_flow(IsFin, Data, State1#state{streams=Streams}), parse(Buffer, commands(State, StreamID, Commands)) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(data, [StreamID, IsFin, Data, StreamState0], - Class, Exception, erlang:get_stacktrace()), Opts), + Class, Exception, Stacktrace), Opts), %% @todo Should call parse after this. stream_terminate(State0, StreamID, {internal_error, {Class, Exception}, 'Unhandled exception in cowboy_stream:data/4.'}) @@ -904,10 +900,10 @@ info(State=#state{opts=Opts, streams=Streams0}, StreamID, Msg) -> Streams = lists:keyreplace(StreamID, #stream.id, Streams0, Stream#stream{state=StreamState}), commands(State#state{streams=Streams}, StreamID, Commands) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(info, [StreamID, Msg, StreamState0], - Class, Exception, erlang:get_stacktrace()), Opts), + Class, Exception, Stacktrace), Opts), stream_terminate(State, StreamID, {internal_error, {Class, Exception}, 'Unhandled exception in cowboy_stream:info/3.'}) end; @@ -1286,10 +1282,10 @@ stream_terminate(State0=#state{opts=Opts, in_streamid=InStreamID, in_state=InSta stream_call_terminate(StreamID, Reason, StreamState, #state{opts=Opts}) -> try cowboy_stream:terminate(StreamID, Reason, StreamState) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(terminate, [StreamID, Reason, StreamState], - Class, Exception, erlang:get_stacktrace()), Opts) + Class, Exception, Stacktrace), Opts) end. maybe_req_close(#state{opts=#{http10_keepalive := false}}, _, 'HTTP/1.0') -> @@ -1386,10 +1382,10 @@ early_error(StatusCode0, #state{socket=Socket, transport=Transport, %% @todo Technically we allow the sendfile tuple. RespBody ]) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(early_error, [StreamID, Reason, PartialReq, Resp, Opts], - Class, Exception, erlang:get_stacktrace()), Opts), + Class, Exception, Stacktrace), Opts), %% We still need to send an error response, so send what we initially %% wanted to send. It's better than nothing. Transport:send(Socket, cow_http:response(StatusCode0, diff --git a/src/cowboy_http2.erl b/src/cowboy_http2.erl index 2754e9c..aa2dfbc 100644 --- a/src/cowboy_http2.erl +++ b/src/cowboy_http2.erl @@ -14,10 +14,6 @@ -module(cowboy_http2). --ifdef(OTP_RELEASE). --compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). --endif. - -export([init/6]). -export([init/10]). -export([init/12]). @@ -384,10 +380,10 @@ data_frame(State0=#state{opts=Opts, flow=Flow, streams=Streams}, StreamID, IsFin flow=max(0, StreamFlow - Size), state=StreamState}}}, StreamID), commands(State, StreamID, Commands) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(data, [StreamID, IsFin, Data, StreamState0], - Class, Exception, erlang:get_stacktrace()), Opts), + Class, Exception, Stacktrace), Opts), reset_stream(State0, StreamID, {internal_error, {Class, Exception}, 'Unhandled exception in cowboy_stream:data/4.'}) end; @@ -491,10 +487,10 @@ headers_frame(State=#state{opts=Opts, streams=Streams}, StreamID, Req) -> commands(State#state{ streams=Streams#{StreamID => #stream{state=StreamState}}}, StreamID, Commands) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(init, [StreamID, Req, Opts], - Class, Exception, erlang:get_stacktrace()), Opts), + Class, Exception, Stacktrace), Opts), reset_stream(State, StreamID, {internal_error, {Class, Exception}, 'Unhandled exception in cowboy_stream:init/3.'}) end. @@ -518,10 +514,10 @@ early_error(State0=#state{ref=Ref, opts=Opts, peer=Peer}, try cowboy_stream:early_error(StreamID, Reason, PartialReq, Resp, Opts) of {response, StatusCode, RespHeaders, RespBody} -> send_response(State0, StreamID, StatusCode, RespHeaders, RespBody) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(early_error, [StreamID, Reason, PartialReq, Resp, Opts], - Class, Exception, erlang:get_stacktrace()), Opts), + Class, Exception, Stacktrace), Opts), %% We still need to send an error response, so send what we initially %% wanted to send. It's better than nothing. send_headers(State0, StreamID, fin, StatusCode0, RespHeaders0) @@ -579,10 +575,10 @@ info(State=#state{opts=Opts, http2_machine=HTTP2Machine, streams=Streams}, Strea {Commands, StreamState} -> commands(State#state{streams=Streams#{StreamID => Stream#stream{state=StreamState}}}, StreamID, Commands) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(info, [StreamID, Msg, StreamState0], - Class, Exception, erlang:get_stacktrace()), Opts), + Class, Exception, Stacktrace), Opts), reset_stream(State, StreamID, {internal_error, {Class, Exception}, 'Unhandled exception in cowboy_stream:info/3.'}) end; @@ -1030,10 +1026,10 @@ terminate_stream(State=#state{flow=Flow, streams=Streams0, children=Children0}, terminate_stream_handler(#state{opts=Opts}, StreamID, Reason, StreamState) -> try cowboy_stream:terminate(StreamID, Reason, StreamState) - catch Class:Exception -> + catch Class:Exception:Stacktrace -> cowboy:log(cowboy_stream:make_error_log(terminate, [StreamID, Reason, StreamState], - Class, Exception, erlang:get_stacktrace()), Opts) + Class, Exception, Stacktrace), Opts) end. %% System callbacks. diff --git a/src/cowboy_loop.erl b/src/cowboy_loop.erl index 603c939..21eb96e 100644 --- a/src/cowboy_loop.erl +++ b/src/cowboy_loop.erl @@ -15,10 +15,6 @@ -module(cowboy_loop). -behaviour(cowboy_sub_protocol). --ifdef(OTP_RELEASE). --compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). --endif. - -export([upgrade/4]). -export([upgrade/5]). -export([loop/4]). @@ -81,10 +77,9 @@ call(Req0, Env, Handler, HandlerState0, Message) -> suspend(Req, Env, Handler, HandlerState); {stop, Req, HandlerState} -> terminate(Req, Env, Handler, HandlerState, stop) - catch Class:Reason -> - StackTrace = erlang:get_stacktrace(), + catch Class:Reason:Stacktrace -> cowboy_handler:terminate({crash, Class, Reason}, Req0, HandlerState0, Handler), - erlang:raise(Class, Reason, StackTrace) + erlang:raise(Class, Reason, Stacktrace) end. suspend(Req, Env, Handler, HandlerState) -> diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl index ea61194..8c60698 100644 --- a/src/cowboy_req.erl +++ b/src/cowboy_req.erl @@ -15,10 +15,6 @@ -module(cowboy_req). --ifdef(OTP_RELEASE). --compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). --endif. - %% Request. -export([method/1]). -export([version/1]). @@ -224,10 +220,10 @@ qs(#{qs := Qs}) -> parse_qs(#{qs := Qs}) -> try cow_qs:parse_qs(Qs) - catch _:_ -> + catch _:_:Stacktrace -> erlang:raise(exit, {request_error, qs, 'Malformed query string; application/x-www-form-urlencoded expected.' - }, erlang:get_stacktrace()) + }, Stacktrace) end. -spec match_qs(cowboy:fields(), req()) -> map(). @@ -415,10 +411,10 @@ parse_header(Name, Req) -> parse_header(Name, Req, Default) -> try parse_header(Name, Req, Default, parse_header_fun(Name)) - catch _:_ -> + catch _:_:Stacktrace -> erlang:raise(exit, {request_error, {header, Name}, 'Malformed header. Please consult the relevant specification.' - }, erlang:get_stacktrace()) + }, Stacktrace) end. parse_header_fun(<<"accept">>) -> fun cow_http_hd:parse_accept/1; @@ -546,10 +542,10 @@ read_urlencoded_body(Req0, Opts) -> {ok, Body, Req} -> try {ok, cow_qs:parse_qs(Body), Req} - catch _:_ -> + catch _:_:Stacktrace -> erlang:raise(exit, {request_error, urlencoded_body, 'Malformed body; application/x-www-form-urlencoded expected.' - }, erlang:get_stacktrace()) + }, Stacktrace) end; {more, Body, _} -> Length = maps:get(length, Opts, 64000), @@ -616,10 +612,10 @@ read_part(Buffer, Opts, Req=#{multipart := {Boundary, _}}) -> %% Ignore epilogue. {done, _} -> {done, Req#{multipart => done}} - catch _:_ -> + catch _:_:Stacktrace -> erlang:raise(exit, {request_error, {multipart, headers}, 'Malformed body; multipart expected.' - }, erlang:get_stacktrace()) + }, Stacktrace) end. -spec read_part_body(Req) diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl index 9a73374..468f9ab 100644 --- a/src/cowboy_rest.erl +++ b/src/cowboy_rest.erl @@ -17,10 +17,6 @@ -module(cowboy_rest). -behaviour(cowboy_sub_protocol). --ifdef(OTP_RELEASE). --compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). --endif. - -export([upgrade/4]). -export([upgrade/5]). @@ -812,8 +808,8 @@ variances(Req, State=#state{content_types_p=CTP, <<"vary">>, [H|Variances5], Req2), resource_exists(Req3, State2) end - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. variances(Req, State, Variances) -> @@ -850,8 +846,8 @@ if_match(Req, State, EtagsList) -> %% Etag may be `undefined' which cannot be a member. false -> precondition_failed(Req2, State2) end - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. if_match_must_not_exist(Req, State) -> @@ -878,8 +874,8 @@ if_unmodified_since(Req, State, IfUnmodifiedSince) -> true -> precondition_failed(Req2, State2); false -> if_none_match_exists(Req2, State2) end - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. if_none_match_exists(Req, State) -> @@ -904,8 +900,8 @@ if_none_match(Req, State, EtagsList) -> false -> method(Req2, State2) end end - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. %% Weak Etag comparison: only check the opaque tag. @@ -947,8 +943,8 @@ if_modified_since(Req, State, IfModifiedSince) -> true -> method(Req2, State2); false -> not_modified(Req2, State2) end - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. not_modified(Req, State) -> @@ -958,11 +954,11 @@ not_modified(Req, State) -> try set_resp_expires(Req3, State2) of {Req4, State3} -> respond(Req4, State3, 304) - catch Class:Reason -> - error_terminate(Req, State2, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State2, Class, Reason, Stacktrace) end - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. precondition_failed(Req, State) -> @@ -1115,8 +1111,8 @@ process_content_type(Req, State=#state{method=Method, exists=Exists}, Fun) -> Exists -> respond(Req3, State2, 303); true -> respond(Req3, State2, 201) end - end catch Class:Reason = {case_clause, no_call} -> - error_terminate(Req, State, Class, Reason) + end catch Class:Reason = {case_clause, no_call}:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. %% If PUT was used then the resource has been created at the current URL. @@ -1142,8 +1138,8 @@ set_resp_body_etag(Req, State) -> try set_resp_etag(Req, State) of {Req2, State2} -> set_resp_body_last_modified(Req2, State2) - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. %% Set the Last-Modified header if any for the response provided. @@ -1159,8 +1155,8 @@ set_resp_body_last_modified(Req, State) -> <<"last-modified">>, LastModifiedBin, Req2), set_resp_body_expires(Req3, State2) end - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. %% Set the Expires header if any for the response provided. @@ -1168,8 +1164,8 @@ set_resp_body_expires(Req, State) -> try set_resp_expires(Req, State) of {Req2, State2} -> if_range(Req2, State2) - catch Class:Reason -> - error_terminate(Req, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req, State, Class, Reason, Stacktrace) end. %% When both the if-range and range headers are set, we perform @@ -1254,9 +1250,10 @@ set_ranged_body_auto(Req, State=#state{handler=Handler, content_type_a={_, Callb switch_handler(Switch, Req2, State2); {Body, Req2, State2} -> maybe_set_ranged_body_auto(Req2, State2, Body) - end catch Class:{case_clause, no_call} -> + end catch Class:{case_clause, no_call}:Stacktrace -> error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}}, - 'A callback specified in content_types_provided/2 is not exported.'}) + 'A callback specified in content_types_provided/2 is not exported.'}, + Stacktrace) end. maybe_set_ranged_body_auto(Req=#{range := {_, Ranges}}, State, Body) -> @@ -1379,9 +1376,10 @@ set_ranged_body_callback(Req, State=#state{handler=Handler}, Callback) -> true -> send_multipart_ranged_body(Req2, State2, Ranges); false -> set_multipart_ranged_body(Req2, State2, Ranges) end - end catch Class:{case_clause, no_call} -> + end catch Class:{case_clause, no_call}:Stacktrace -> error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}}, - 'A callback specified in ranges_provided/2 is not exported.'}) + 'A callback specified in ranges_provided/2 is not exported.'}, + Stacktrace) end. set_one_ranged_body(Req0, State, OneRange) -> @@ -1471,9 +1469,10 @@ set_resp_body(Req, State=#state{handler=Handler, content_type_a={_, Callback}}) {Body, Req2, State2} -> Req3 = cowboy_req:set_resp_body(Body, Req2), multiple_choices(Req3, State2) - end catch Class:{case_clause, no_call} -> + end catch Class:{case_clause, no_call}:Stacktrace -> error_terminate(Req, State, Class, {error, {missing_callback, {Handler, Callback, 2}}, - 'A callback specified in content_types_provided/2 is not exported.'}) + 'A callback specified in content_types_provided/2 is not exported.'}, + Stacktrace) end. multiple_choices(Req, State) -> @@ -1578,8 +1577,8 @@ call(Req0, State=#state{handler=Handler, no_call; {Result, Req, HandlerState} -> {Result, Req, State#state{handler_state=HandlerState}} - catch Class:Reason -> - error_terminate(Req0, State, Class, Reason) + catch Class:Reason:Stacktrace -> + error_terminate(Req0, State, Class, Reason, Stacktrace) end; false -> no_call @@ -1620,11 +1619,10 @@ switch_handler({switch_handler, Mod}, Req, #state{handler_state=HandlerState}) - switch_handler({switch_handler, Mod, Opts}, Req, #state{handler_state=HandlerState}) -> {Mod, Req, HandlerState, Opts}. --spec error_terminate(cowboy_req:req(), #state{}, atom(), any()) -> no_return(). -error_terminate(Req, #state{handler=Handler, handler_state=HandlerState}, Class, Reason) -> - StackTrace = erlang:get_stacktrace(), +-spec error_terminate(cowboy_req:req(), #state{}, atom(), any(), any()) -> no_return(). +error_terminate(Req, #state{handler=Handler, handler_state=HandlerState}, Class, Reason, Stacktrace) -> cowboy_handler:terminate({crash, Class, Reason}, Req, HandlerState, Handler), - erlang:raise(Class, Reason, StackTrace). + erlang:raise(Class, Reason, Stacktrace). terminate(Req, #state{handler=Handler, handler_state=HandlerState}) -> Result = cowboy_handler:terminate(normal, Req, HandlerState, Handler), diff --git a/src/cowboy_stream_h.erl b/src/cowboy_stream_h.erl index 71b2948..2a50d6a 100644 --- a/src/cowboy_stream_h.erl +++ b/src/cowboy_stream_h.erl @@ -15,10 +15,6 @@ -module(cowboy_stream_h). -behavior(cowboy_stream). --ifdef(OTP_RELEASE). --compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). --endif. - -export([init/3]). -export([data/4]). -export([info/3]). @@ -285,33 +281,16 @@ send_request_body(Pid, Ref, fin, BodyLen, Data) -> %% Request process. -%% We catch all exceptions in order to add the stacktrace to -%% the exit reason as it is not propagated by proc_lib otherwise -%% and therefore not present in the 'EXIT' message. We want -%% the stacktrace in order to simplify debugging of errors. -%% -%% This + the behavior in proc_lib means that we will get a -%% {Reason, Stacktrace} tuple for every exceptions, instead of -%% just for errors and throws. -%% -%% @todo Better spec. +%% We add the stacktrace to exit exceptions here in order +%% to simplify the debugging of errors. The proc_lib library +%% already adds the stacktrace to other types of exceptions. -spec request_process(cowboy_req:req(), cowboy_middleware:env(), [module()]) -> ok. request_process(Req, Env, Middlewares) -> - OTP = erlang:system_info(otp_release), try execute(Req, Env, Middlewares) catch - exit:Reason -> - Stacktrace = erlang:get_stacktrace(), - erlang:raise(exit, {Reason, Stacktrace}, Stacktrace); - %% OTP 19 does not propagate any exception stacktraces, - %% we therefore add it for every class of exception. - _:Reason when OTP =:= "19" -> - Stacktrace = erlang:get_stacktrace(), - erlang:raise(exit, {Reason, Stacktrace}, Stacktrace); - %% @todo I don't think this clause is necessary. - Class:Reason -> - erlang:raise(Class, Reason, erlang:get_stacktrace()) + exit:Reason:Stacktrace -> + erlang:raise(exit, {Reason, Stacktrace}, Stacktrace) end. execute(_, _, []) -> diff --git a/src/cowboy_websocket.erl b/src/cowboy_websocket.erl index 31103ac..b3600be 100644 --- a/src/cowboy_websocket.erl +++ b/src/cowboy_websocket.erl @@ -17,10 +17,6 @@ -module(cowboy_websocket). -behaviour(cowboy_sub_protocol). --ifdef(OTP_RELEASE). --compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). --endif. - -export([is_upgrade_request/1]). -export([upgrade/4]). -export([upgrade/5]). @@ -513,11 +509,10 @@ handler_call(State=#state{handler=Handler}, HandlerState, end; {stop, HandlerState2} -> websocket_close(State, HandlerState2, stop) - catch Class:Reason -> - StackTrace = erlang:get_stacktrace(), + catch Class:Reason:Stacktrace -> websocket_send_close(State, {crash, Class, Reason}), handler_terminate(State, HandlerState, {crash, Class, Reason}), - erlang:raise(Class, Reason, StackTrace) + erlang:raise(Class, Reason, Stacktrace) end. -spec handler_call_result(#state{}, any(), parse_state(), fun(), commands()) -> no_return(). -- cgit v1.2.3