Packages
phoenix
1.4.6
1.8.9
1.8.8
1.8.7
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.1
1.8.0
1.8.0-rc.4
1.8.0-rc.3
1.8.0-rc.2
1.8.0-rc.1
1.8.0-rc.0
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.7.0-rc.3
1.7.0-rc.2
1.7.0-rc.1
1.7.0-rc.0
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.15
1.5.14
1.5.13
1.5.12
1.5.11
1.5.10
1.5.9
1.5.8
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.0
1.4.18
1.4.17
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.3
1.4.0-rc.2
1.4.0-rc.1
1.4.0-rc.0
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.3.0-rc.3
1.3.0-rc.2
1.3.0-rc.1
1.3.0-rc.0
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.1
1.2.0-rc.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.17.1
0.17.0
0.16.1
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.0
0.4.1
0.4.0
0.3.1
0.3.0
0.2.11
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Productive. Reliable. Fast. A productive web framework that does not compromise speed or maintainability.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/phoenix/controller/pipeline.ex
defmodule Phoenix.Controller.Pipeline do
@moduledoc false
@doc false
defmacro __using__(opts) do
quote bind_quoted: [opts: opts] do
@behaviour Plug
require Phoenix.Endpoint
import Phoenix.Controller.Pipeline
Module.register_attribute(__MODULE__, :plugs, accumulate: true)
@before_compile Phoenix.Controller.Pipeline
@phoenix_log_level Keyword.get(opts, :log, :debug)
@phoenix_fallback :unregistered
@doc false
def init(opts), do: opts
@doc false
def call(conn, action) when is_atom(action) do
conn = update_in conn.private,
&(&1 |> Map.put(:phoenix_controller, __MODULE__)
|> Map.put(:phoenix_action, action))
Phoenix.Endpoint.instrument conn, :phoenix_controller_call,
%{conn: conn, log_level: @phoenix_log_level}, fn ->
phoenix_controller_pipeline(conn, action)
end
end
@doc false
def action(%Plug.Conn{private: %{phoenix_action: action}} = conn, _options) do
apply(__MODULE__, action, [conn, conn.params])
end
defoverridable [init: 1, call: 2, action: 2]
end
end
@doc false
def __action_fallback__(plug) do
quote bind_quoted: [plug: plug] do
@phoenix_fallback Phoenix.Controller.Pipeline.validate_fallback(
plug,
__MODULE__,
Module.get_attribute(__MODULE__, :phoenix_fallback))
end
end
@doc false
def validate_fallback(plug, module, fallback) do
cond do
fallback == nil ->
raise """
action_fallback can only be called when using Phoenix.Controller.
Add `use Phoenix.Controller` to #{inspect module}
"""
fallback != :unregistered ->
raise "action_fallback can only be called a single time per controller."
not is_atom(plug) ->
raise ArgumentError, "expected action_fallback to be a module or function plug, got #{inspect plug}"
fallback == :unregistered ->
case Atom.to_charlist(plug) do
~c"Elixir." ++ _ -> {:module, plug}
_ -> {:function, plug}
end
end
end
@doc false
defmacro __before_compile__(env) do
action = {:action, [], true}
plugs = [action|Module.get_attribute(env.module, :plugs)]
{conn, body} = Plug.Builder.compile(env, plugs,
log_on_halt: :debug,
init_mode: Phoenix.plug_init_mode())
fallback_ast =
env.module
|> Module.get_attribute(:phoenix_fallback)
|> build_fallback()
quote do
defoverridable [action: 2]
def action(var!(conn_before), opts) do
try do
var!(conn_after) = super(var!(conn_before), opts)
unquote(fallback_ast)
catch
:error, reason ->
Phoenix.Controller.Pipeline.__catch__(
var!(conn_before), reason, __MODULE__,
var!(conn_before).private.phoenix_action, System.stacktrace()
)
end
end
defp phoenix_controller_pipeline(unquote(conn), var!(action)) do
var!(conn) = unquote(conn)
var!(controller) = __MODULE__
_ = var!(conn)
_ = var!(controller)
_ = var!(action)
unquote(body)
end
end
end
defp build_fallback(:unregistered) do
quote do: var!(conn_after)
end
defp build_fallback({:module, plug}) do
quote bind_quoted: binding() do
case var!(conn_after) do
%Plug.Conn{} = conn_after -> conn_after
val -> plug.call(var!(conn_before), plug.init(val))
end
end
end
defp build_fallback({:function, plug}) do
quote do
case var!(conn_after) do
%Plug.Conn{} = conn_after -> conn_after
val -> unquote(plug)(var!(conn_before), val)
end
end
end
@doc false
def __catch__(%Plug.Conn{}, :function_clause, controller, action,
[{controller, action, [%Plug.Conn{} | _] = action_args, _loc} | _] = stack) do
args = [module: controller, function: action, arity: length(action_args), args: action_args]
reraise Phoenix.ActionClauseError, args, stack
end
def __catch__(%Plug.Conn{} = conn, reason, _controller, _action, stack) do
Plug.Conn.WrapperError.reraise(conn, :error, reason, stack)
end
@doc """
Stores a plug to be executed as part of the plug pipeline.
"""
defmacro plug(plug)
defmacro plug({:when, _, [plug, guards]}), do:
plug(plug, [], guards)
defmacro plug(plug), do:
plug(plug, [], true)
@doc """
Stores a plug with the given options to be executed as part of
the plug pipeline.
"""
defmacro plug(plug, opts)
defmacro plug(plug, {:when, _, [opts, guards]}), do:
plug(plug, opts, guards)
defmacro plug(plug, opts), do:
plug(plug, opts, true)
defp plug(plug, opts, guards) do
quote do
@plugs {unquote(plug), unquote(opts), unquote(Macro.escape(guards))}
end
end
end