diff --git a/.travis.yml b/.travis.yml index adca6b6c..3df2a610 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ language: erlang sudo: false install: "true" # don't let travis run get-deps otp_release: + - 21.0 + - 20.0 - 19.1 - 18.3 - 17.5 diff --git a/include/wm_compat.hrl b/include/wm_compat.hrl new file mode 100644 index 00000000..672f2619 --- /dev/null +++ b/include/wm_compat.hrl @@ -0,0 +1,7 @@ +-ifndef(deprecate_stacktrace). +-define(STPATTERN(Pattern), Pattern). +-define(STACKTRACE, erlang:get_stacktrace()). +-else. +-define(STPATTERN(Pattern), Pattern:__STACKTRACE). +-define(STACKTRACE, __STACKTRACE). +-endif. diff --git a/include/wm_resource.hrl b/include/wm_resource.hrl index 588405df..3381669c 100644 --- a/include/wm_resource.hrl +++ b/include/wm_resource.hrl @@ -1 +1 @@ --record(wm_resource, {module, modstate, modexports, trace}). +-record(wm_resource, {module, modstate, trace}). diff --git a/rebar.config b/rebar.config index ea770995..9b04df9e 100644 --- a/rebar.config +++ b/rebar.config @@ -5,7 +5,7 @@ {xref_checks, [undefined_function_calls]}. -{deps, [{mochiweb, "2.12.2"}]}. +{deps, [{mochiweb, "2.18.0"}]}. {eunit_opts, [ no_tty, @@ -15,8 +15,7 @@ {profiles, [{test, [{deps, [meck, - {ibrowse, {git, "git://github.com/cmullaparthi/ibrowse.git", {tag, "v4.0.2"}}}, - {eunit_formatters, {git, "git://github.com/seancribbs/eunit_formatters", {branch, "master"}}} + {ibrowse, "4.4.0"} ]}, {erl_opts, [debug_info]} ]} diff --git a/rebar.config.script b/rebar.config.script index 2dba9a9f..9679562d 100644 --- a/rebar.config.script +++ b/rebar.config.script @@ -11,4 +11,15 @@ Config1 = case hd(OtpVersion) =:= $R andalso OtpVersion < "R15B02" of CONFIG ++ [{erl_opts, HashDefine}] end; false -> CONFIG - end. + end, +if + OtpVersion >= "21" -> + case lists:keysearch(erl_opts, 1, Config1) of + {value, {erl_opts, Opts2}} -> + lists:keyreplace(erl_opts, 1, Config1, {erl_opts, [{d, deprecate_stacktrace}|Opts2]}); + false -> + [{erl_opts, [{d, deprecate_stacktrace}]}|Config1] + end; + true -> + Config1 +end. diff --git a/rebar.lock b/rebar.lock index 57d5070b..4bc80524 100644 --- a/rebar.lock +++ b/rebar.lock @@ -1,6 +1,6 @@ {"1.1.0", -[{<<"mochiweb">>,{pkg,<<"mochiweb">>,<<"2.12.2">>},0}]}. +[{<<"mochiweb">>,{pkg,<<"mochiweb">>,<<"2.18.0">>},0}]}. [ {pkg_hash,[ - {<<"mochiweb">>, <<"80804AD342AFA3D7F3524040D4EED66CE74B17A555DE454AC85B07C479928E46">>}]} + {<<"mochiweb">>, <<"EB55F1DB3E6E960FAC4E6DB4E2DB9EC3602CC9F30B86CD1481D56545C3145D2E">>}]} ]. diff --git a/src/webmachine.app.src b/src/webmachine.app.src index ad14f7b1..363e92d0 100644 --- a/src/webmachine.app.src +++ b/src/webmachine.app.src @@ -23,7 +23,7 @@ %% string() for the "Server" response header ]}, - {contributors,["Sean Cribbs", "Joe DeVivo" "Bryan Fink", + {maintainers,["Sean Cribbs", "Joe DeVivo", "Bryan Fink", "Kelly McLaughlin", "Jared Morrow", "Andy Gross", "Steve Vinoski"]}, {licenses,["Apache"]}, diff --git a/src/webmachine_app.erl b/src/webmachine_app.erl index 35fa74a3..0c15a08c 100644 --- a/src/webmachine_app.erl +++ b/src/webmachine_app.erl @@ -27,7 +27,7 @@ -include("webmachine_logger.hrl"). --define(QUIP, "cafe not found"). +-define(QUIP, "greased slide to failure"). %% @spec start(_Type, _StartArgs) -> ServerRet %% @doc application start callback for webmachine. diff --git a/src/webmachine_decision_core.erl b/src/webmachine_decision_core.erl index 4a50d09a..34263895 100644 --- a/src/webmachine_decision_core.erl +++ b/src/webmachine_decision_core.erl @@ -23,6 +23,13 @@ -author('Bryan Fink '). -export([handle_request/2]). -include("webmachine_logger.hrl"). +-include("wm_compat.hrl"). + +%% Suppress Erlang/OTP 21 warnings about the new method to retrieve +%% stacktraces. +-ifdef(OTP_RELEASE). +-compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). +-endif. handle_request(Resource, ReqState) -> _ = [erase(X) || X <- [decision, code, req_body, bytes_written, tmp_reqstate]], @@ -31,8 +38,8 @@ handle_request(Resource, ReqState) -> try d(v3b13) catch - error:_ -> - error_response(erlang:get_stacktrace()) + ?STPATTERN(error:_Reason) -> + error_response(?STACKTRACE) end. wrcall(X) -> diff --git a/src/webmachine_dispatcher.erl b/src/webmachine_dispatcher.erl index dffa9aa7..280fdbab 100644 --- a/src/webmachine_dispatcher.erl +++ b/src/webmachine_dispatcher.erl @@ -628,7 +628,7 @@ make_reqdata(Path) -> MochiReq = mochiweb_request:new(testing, 'GET', Path, {1, 1}, mochiweb_headers:make([])), Req = webmachine:new_request(mochiweb, MochiReq), - {RD, _} = Req:get_reqdata(), + {RD, _} = webmachine_request:get_reqdata(Req), RD. -endif. diff --git a/src/webmachine_mochiweb.erl b/src/webmachine_mochiweb.erl index 6b59daee..32d3b1d5 100644 --- a/src/webmachine_mochiweb.erl +++ b/src/webmachine_mochiweb.erl @@ -63,7 +63,7 @@ start(Options) -> webmachine_router:init_routes(DGroup, DispatchList), _ = [application_set_unless_env_or_undef(K, V) || {K, V} <- WMOptions], MochiName = list_to_atom(to_list(PName) ++ "_mochiweb"), - LoopFun = fun(X) -> loop(DGroup, X) end, + LoopFun = fun(X) -> ?MODULE:loop(DGroup, X) end, mochiweb_http:start([{name, MochiName}, {loop, LoopFun} | OtherOptions]). stop() -> diff --git a/src/webmachine_resource.erl b/src/webmachine_resource.erl index ada1ac1c..e9a072cb 100644 --- a/src/webmachine_resource.erl +++ b/src/webmachine_resource.erl @@ -17,9 +17,10 @@ -module(webmachine_resource). -author('Justin Sheehy '). -author('Andy Gross '). --export([new/4, wrap/2]). +-export([new/3, wrap/2]). -export([do/3,log_d/2,stop/1]). +-include("wm_compat.hrl"). -include("wm_resource.hrl"). -include("wm_reqdata.hrl"). -include("wm_reqstate.hrl"). @@ -27,11 +28,22 @@ -type t() :: #wm_resource{}. -export_type([t/0]). -new(R_Mod, R_ModState, R_ModExports, R_Trace) -> +-define(CALLBACK_ARITY, 2). + +%% Suppress Erlang/OTP 21 warnings about the new method to retrieve +%% stacktraces. +-ifdef(OTP_RELEASE). +-compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). +-endif. + +new(R_Mod, R_ModState, R_Trace) -> + case erlang:module_loaded(R_Mod) of + false -> code:ensure_loaded(R_Mod); + true -> ok + end, #wm_resource{ module = R_Mod, modstate = R_ModState, - modexports = R_ModExports, trace = R_Trace }. @@ -118,15 +130,13 @@ default(_) -> wrap(Mod, Args) -> case Mod:init(Args) of {ok, ModState} -> - {ok, webmachine_resource:new(Mod, ModState, - orddict:from_list(Mod:module_info(exports)), false)}; + {ok, webmachine_resource:new(Mod, ModState, false)}; {{trace, Dir}, ModState} -> {ok, File} = open_log_file(Dir, Mod), log_decision(File, v3b14), log_call(File, attempt, Mod, init, Args), log_call(File, result, Mod, init, {{trace, Dir}, ModState}), - {ok, webmachine_resource:new(Mod, ModState, - orddict:from_list(Mod:module_info(exports)), File)}; + {ok, webmachine_resource:new(Mod, ModState, File)}; _ -> {stop, bad_init_arg} end. @@ -136,7 +146,6 @@ do(#wm_resource{}=Res, Fun, ReqProps) -> do(Fun, ReqProps, #wm_resource{ module=R_Mod, - modexports=R_ModExports, trace=R_Trace }=Req) when is_atom(Fun) andalso is_list(ReqProps) -> @@ -155,21 +164,20 @@ do(Fun, ReqProps, %% Do not need the embedded state anymore TrimData = ReqData#wm_reqdata{wm_state=undefined}, {Reply, - webmachine_resource:new(R_Mod, NewModState, R_ModExports, R_Trace), + webmachine_resource:new(R_Mod, NewModState, R_Trace), ReqState#wm_reqstate{reqdata=TrimData}}. handle_wm_call(Fun, ReqData, #wm_resource{ module=R_Mod, modstate=R_ModState, - modexports=R_ModExports, trace=R_Trace }=Req) -> case default(Fun) of no_default -> resource_call(Fun, ReqData, Req); Default -> - case orddict:is_key(Fun, R_ModExports) of + case erlang:function_exported(R_Mod, Fun, ?CALLBACK_ARITY) of true -> resource_call(Fun, ReqData, Req); false -> @@ -200,12 +208,13 @@ resource_call(F, ReqData, _ -> log_call(R_Trace, attempt, R_Mod, F, [ReqData, R_ModState]) end, Result = try + %% Note: the argument list must match the definition of CALLBACK_ARITY apply(R_Mod, F, [ReqData, R_ModState]) - catch C:R -> - Reason = {C, R, trim_trace(erlang:get_stacktrace())}, + catch ?STPATTERN(C:R) -> + Reason = {C, R, trim_trace(?STACKTRACE)}, {{error, Reason}, ReqData, R_ModState} end, - case R_Trace of + case R_Trace of false -> nop; _ -> log_call(R_Trace, result, R_Mod, F, Result) end, diff --git a/test/decision_core_test.erl b/test/decision_core_test.erl index 5b3f8eca..39a2b9ae 100644 --- a/test/decision_core_test.erl +++ b/test/decision_core_test.erl @@ -17,10 +17,20 @@ -ifdef(TEST). +-include("wm_compat.hrl"). -include("wm_reqdata.hrl"). -include_lib("eunit/include/eunit.hrl"). --compile(export_all). +-export([size_stream_raises_error/2, process_post_for_created_p11/3, get_streamed_body/2, send_streamed_body/2, + accept_text/2, writer_response/2, known_length_body/2, range_response/2, stream_content_md5/0, + validate_checksum_for_md5stream/3, process_post_for_md5_stream/3, init/1, service_available/2, + validate_content_checksum/2, is_authorized/2, allowed_methods/2, known_methods/2, uri_too_long/2, + known_content_type/2, valid_entity_length/2, malformed_request/2, forbidden/2, valid_content_headers/2, + content_types_provided/2, content_types_accepted/2, language_available/2, charsets_provided/2, + encodings_provided/2, resource_exists/2, generate_etag/2, last_modified/2, moved_permanently/2, + moved_temporarily/2, previously_existed/2, allow_missing_post/2, post_is_create/2, process_post/2, + create_path/2, is_conflict/2, multiple_choices/2, base_uri/2, base_uri_add_slash/1, expires/2, + delete_resource/2, delete_completed/2, to_html/2]). -define(RESOURCE, atom_to_list(?MODULE)). -define(RESOURCE_PATH, "/" ++ ?RESOURCE). @@ -35,6 +45,12 @@ md5(Bin) -> crypto:md5(Bin). -endif. +%% Suppress Erlang/OTP 21 warnings about the new method to retrieve +%% stacktraces. +-ifdef(OTP_RELEASE). +-compile({nowarn_deprecated_function, [{erlang, get_stacktrace, 0}]}). +-endif. + -define(HTTP_1_0_METHODS, ['GET', 'POST', 'HEAD']). -define(HTTP_1_1_METHODS, ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'CONNECT', 'OPTIONS']). @@ -320,8 +336,8 @@ setup() -> meck:new(webmachine_resource, MeckOpts), Ctx catch - T:E -> - io:format(user, "~n~p : ~p : ~p", [T, E, erlang:get_stacktrace()]), + ?STPATTERN(T:E) -> + io:format(user, "~n~p : ~p : ~p", [T, E, ?STACKTRACE]), error(setup_failed) end. diff --git a/test/wm_integration_test.erl b/test/wm_integration_test.erl index 9aac6413..63b83521 100644 --- a/test/wm_integration_test.erl +++ b/test/wm_integration_test.erl @@ -17,8 +17,6 @@ -include_lib("eunit/include/eunit.hrl"). -include("webmachine.hrl"). --compile([export_all]). - integration_test_() -> {foreach, %% Setup