Packages
plug
1.15.2
1.20.3
1.20.2
1.20.1
retired
1.20.0
retired
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.15.6
1.15.5
1.15.4
1.15.3
1.15.2
1.15.1
1.15.0
1.14.2
1.14.1
1.14.0
1.13.6
1.13.5
1.13.4
1.13.3
1.13.2
1.13.1
retired
1.13.0
retired
1.12.1
1.12.0
1.11.1
1.11.0
1.10.4
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.2
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.0
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
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.14.0
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.0
0.6.0
0.5.3
0.5.2
0.5.1
0.5.0
0.4.4
0.4.3
0.4.2
0.4.1
Compose web applications with functions
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/plug.ex
defmodule Plug do
@moduledoc """
The plug specification.
## Types of plugs
There are two kind of plugs: function plugs and module plugs.
### Function plugs
A function plug is any function that receives a connection and a set of
options and returns a connection. Its type signature must be:
(Plug.Conn.t, Plug.opts) :: Plug.Conn.t
### Module plugs
A module plug is an extension of the function plug. It is a module that must
export:
* a `c:call/2` function with the signature defined above
* an `c:init/1` function which takes a set of options and initializes it.
The result returned by `c:init/1` is passed as second argument to `c:call/2`. Note
that `c:init/1` may be called during compilation and as such it must not return
pids, ports or values that are specific to the runtime.
The API expected by a module plug is defined as a behaviour by the
`Plug` module (this module).
## Examples
Here's an example of a function plug:
def json_header_plug(conn, _opts) do
Plug.Conn.put_resp_content_type(conn, "application/json")
end
Here's an example of a module plug:
defmodule JSONHeaderPlug do
import Plug.Conn
def init(opts) do
opts
end
def call(conn, _opts) do
put_resp_content_type(conn, "application/json")
end
end
## The Plug pipeline
The `Plug.Builder` module provides conveniences for building plug
pipelines.
"""
@type opts ::
binary
| tuple
| atom
| integer
| float
| [opts]
| %{optional(opts) => opts}
| MapSet.t()
@callback init(opts) :: opts
@callback call(conn :: Plug.Conn.t(), opts) :: Plug.Conn.t()
require Logger
@doc """
Run a series of Plugs at runtime.
The plugs given here can be either a tuple, representing a module plug
and their options, or a simple function that receives a connection and
returns a connection.
If any of the plugs halt, the remaining plugs are not invoked. If the
given connection was already halted, none of the plugs are invoked
either.
While `Plug.Builder` works at compile-time, this is a straight-forward
alternative that works at runtime.
## Examples
Plug.run(conn, [{Plug.Head, []}, &IO.inspect/1])
## Options
* `:log_on_halt` - a log level to be used if a Plug halts
"""
@spec run(Plug.Conn.t(), [{module, opts} | (Plug.Conn.t() -> Plug.Conn.t())], Keyword.t()) ::
Plug.Conn.t()
def run(conn, plugs, opts \\ [])
def run(%Plug.Conn{halted: true} = conn, _plugs, _opts),
do: conn
def run(%Plug.Conn{} = conn, plugs, opts),
do: do_run(conn, plugs, Keyword.get(opts, :log_on_halt))
defp do_run(conn, [{mod, opts} | plugs], level) when is_atom(mod) do
case mod.call(conn, mod.init(opts)) do
%Plug.Conn{halted: true} = conn ->
level && Logger.log(level, "Plug halted in #{inspect(mod)}.call/2")
conn
%Plug.Conn{} = conn ->
do_run(conn, plugs, level)
other ->
raise "expected #{inspect(mod)} to return Plug.Conn, got: #{inspect(other)}"
end
end
defp do_run(conn, [fun | plugs], level) when is_function(fun, 1) do
case fun.(conn) do
%Plug.Conn{halted: true} = conn ->
level && Logger.log(level, "Plug halted in #{inspect(fun)}")
conn
%Plug.Conn{} = conn ->
do_run(conn, plugs, level)
other ->
raise "expected #{inspect(fun)} to return Plug.Conn, got: #{inspect(other)}"
end
end
defp do_run(conn, [], _level), do: conn
@doc """
Forwards requests to another Plug setting the connection to a trailing subpath of the request.
The `path_info` on the forwarded connection will only include the trailing segments
of the request path supplied to forward, while `conn.script_name` will
retain the correct base path for e.g. url generation.
## Example
defmodule Router do
def init(opts), do: opts
def call(conn, opts) do
case conn do
# Match subdomain
%{host: "admin." <> _} ->
AdminRouter.call(conn, opts)
# Match path on localhost
%{host: "localhost", path_info: ["admin" | rest]} ->
Plug.forward(conn, rest, AdminRouter, opts)
_ ->
MainRouter.call(conn, opts)
end
end
end
"""
@spec forward(Plug.Conn.t(), [String.t()], atom, Plug.opts()) :: Plug.Conn.t()
def forward(%Plug.Conn{path_info: path, script_name: script} = conn, new_path, target, opts) do
{base, split_path} = Enum.split(path, length(path) - length(new_path))
conn = do_forward(target, %{conn | path_info: split_path, script_name: script ++ base}, opts)
%{conn | path_info: path, script_name: script}
end
defp do_forward({mod, fun}, conn, opts), do: apply(mod, fun, [conn, opts])
defp do_forward(mod, conn, opts), do: mod.call(conn, opts)
end