Packages
plug
1.19.0
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 by definition any function that receives a connection
and a set of options and returns a connection. Function plugs must have
the following type signature:
(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
@behaviour Plug
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 plug halts, the connection won't invoke the remaining plugs. If the
given connection was already halted, none of the plugs are invoked either.
While `Plug.Builder` is designed to operate at compile-time, the `run` function
serves as a straightforward alternative for runtime executions.
## 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 while setting the connection to a trailing subpath of the request.
The `path_info` on the forwarded connection will only include the request path trailing segments
supplied to the `forward` function. The `conn.script_name` attribute retains the correct base path,
e.g., url generation.
## Example
defmodule Router do
@behaviour Plug
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