zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

error_handler.ex (3499B)


      1 defmodule Plug.ErrorHandler do
      2   @moduledoc """
      3   A module to be used in your existing plugs in order to provide
      4   error handling.
      5 
      6       defmodule AppRouter do
      7         use Plug.Router
      8         use Plug.ErrorHandler
      9 
     10         plug :match
     11         plug :dispatch
     12 
     13         get "/hello" do
     14           send_resp(conn, 200, "world")
     15         end
     16 
     17         @impl Plug.ErrorHandler
     18         def handle_errors(conn, %{kind: _kind, reason: _reason, stack: _stack}) do
     19           send_resp(conn, conn.status, "Something went wrong")
     20         end
     21       end
     22 
     23   Once this module is used, a callback named `handle_errors/2` should
     24   be defined in your plug. This callback will receive the connection
     25   already updated with a proper status code for the given exception.
     26   The second argument is a map containing:
     27 
     28     * the exception kind (`:throw`, `:error` or `:exit`),
     29     * the reason (an exception for errors or a term for others)
     30     * the stacktrace
     31 
     32   After the callback is invoked, the error is re-raised.
     33 
     34   It is advised to do as little work as possible when handling errors
     35   and avoid accessing data like parameters and session, as the parsing
     36   of those is what could have led the error to trigger in the first place.
     37 
     38   Also notice that these pages are going to be shown in production. If
     39   you are looking for error handling to help during development, consider
     40   using `Plug.Debugger`.
     41 
     42   **Note:** If this module is used with `Plug.Debugger`, it must be used
     43   after `Plug.Debugger`.
     44   """
     45 
     46   @doc """
     47   Handle errors from plugs.
     48 
     49   Called when an exception is raised during the processing of a plug.
     50   """
     51   @callback handle_errors(Plug.Conn.t(), %{
     52               kind: :error | :throw | :exit,
     53               reason: Exception.t() | term(),
     54               stack: Exception.stacktrace()
     55             }) :: no_return()
     56 
     57   @doc false
     58   defmacro __using__(_) do
     59     quote location: :keep do
     60       @before_compile Plug.ErrorHandler
     61 
     62       @behaviour Plug.ErrorHandler
     63 
     64       @impl Plug.ErrorHandler
     65       def handle_errors(conn, assigns) do
     66         Plug.Conn.send_resp(conn, conn.status, "Something went wrong")
     67       end
     68 
     69       defoverridable handle_errors: 2
     70     end
     71   end
     72 
     73   @doc false
     74   defmacro __before_compile__(_env) do
     75     quote location: :keep do
     76       defoverridable call: 2
     77 
     78       def call(conn, opts) do
     79         try do
     80           super(conn, opts)
     81         rescue
     82           e in Plug.Conn.WrapperError ->
     83             %{conn: conn, kind: kind, reason: reason, stack: stack} = e
     84             Plug.ErrorHandler.__catch__(conn, kind, e, reason, stack, &handle_errors/2)
     85         catch
     86           kind, reason ->
     87             Plug.ErrorHandler.__catch__(
     88               conn,
     89               kind,
     90               reason,
     91               reason,
     92               __STACKTRACE__,
     93               &handle_errors/2
     94             )
     95         end
     96       end
     97     end
     98   end
     99 
    100   @already_sent {:plug_conn, :sent}
    101 
    102   @doc false
    103   def __catch__(conn, kind, reason, wrapped_reason, stack, handle_errors) do
    104     receive do
    105       @already_sent ->
    106         send(self(), @already_sent)
    107     after
    108       0 ->
    109         normalized_reason = Exception.normalize(kind, wrapped_reason, stack)
    110 
    111         conn
    112         |> Plug.Conn.put_status(status(kind, normalized_reason))
    113         |> handle_errors.(%{kind: kind, reason: normalized_reason, stack: stack})
    114     end
    115 
    116     :erlang.raise(kind, reason, stack)
    117   end
    118 
    119   defp status(:error, error), do: Plug.Exception.status(error)
    120   defp status(:throw, _throw), do: 500
    121   defp status(:exit, _exit), do: 500
    122 end