diff --git a/lib/bandit/pipeline.ex b/lib/bandit/pipeline.ex index 6ee219ae..61384ae5 100644 --- a/lib/bandit/pipeline.ex +++ b/lib/bandit/pipeline.ex @@ -46,10 +46,14 @@ defmodule Bandit.Pipeline do {:upgrade, adapter.transport, protocol, opts} end rescue - exception -> handle_error(:error, exception, __STACKTRACE__, transport, span, opts, conn) + exception -> + handle_error(:error, exception, __STACKTRACE__, transport, span, opts, conn) catch :throw, value -> handle_error(:throw, value, __STACKTRACE__, transport, span, opts, conn) + + :exit, value -> + handle_error(:exit, value, __STACKTRACE__, transport, span, opts, conn) end rescue exception -> @@ -197,7 +201,7 @@ defmodule Bandit.Pipeline do end @spec handle_error( - :error | :throw, + :error | :throw | :exit, Exception.t() | term(), Exception.stacktrace(), Bandit.HTTPTransport.t(), diff --git a/test/bandit/http1/request_test.exs b/test/bandit/http1/request_test.exs index 190088b5..dfe06caa 100644 --- a/test/bandit/http1/request_test.exs +++ b/test/bandit/http1/request_test.exs @@ -1958,6 +1958,21 @@ defmodule HTTP1RequestTest do throw("something") end + test "returns a 500 if the plug exits", context do + output = + capture_log(fn -> + response = Req.get!(context.req, url: "/exits") + assert response.status == 500 + Process.sleep(100) + end) + + assert output =~ "(exit) \"something\"" + end + + def exits(_conn) do + exit("something") + end + test "does not send an error response if the plug has already sent one before raising", context do output = @@ -2387,6 +2402,26 @@ defmodule HTTP1RequestTest do def uncaught_throw(_conn) do throw("thrown") end + + test "it should not send `exception` events for exiting requests", context do + output = + capture_log(fn -> + {:ok, collector_pid} = + start_supervised({Bandit.TelemetryCollector, [[:bandit, :request, :exception]]}) + + Req.get!(context.req, url: "/uncaught_exit") + + Process.sleep(100) + + assert [] = Bandit.TelemetryCollector.get_events(collector_pid) + end) + + assert output =~ "(exit) \"exited\"" + end + + def uncaught_exit(_conn) do + exit("exited") + end end describe "connection closure / error handling" do diff --git a/test/bandit/http2/plug_test.exs b/test/bandit/http2/plug_test.exs index 421a7a2a..42c25fdc 100644 --- a/test/bandit/http2/plug_test.exs +++ b/test/bandit/http2/plug_test.exs @@ -1046,5 +1046,25 @@ defmodule HTTP2PlugTest do def uncaught_throw(_conn) do throw("thrown") end + + test "it should not send `exception` events for exiting requests", context do + output = + capture_log(fn -> + {:ok, collector_pid} = + start_supervised({Bandit.TelemetryCollector, [[:bandit, :request, :exception]]}) + + Req.get!(context.req, url: "/uncaught_exit") + + Process.sleep(100) + + assert [] = Bandit.TelemetryCollector.get_events(collector_pid) + end) + + assert output =~ "(exit) \"exited\"" + end + + def uncaught_exit(_conn) do + exit("exited") + end end end