Subiendo api v2
This commit is contained in:
179
deps/plug/lib/plug.ex
vendored
Normal file
179
deps/plug/lib/plug.ex
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
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
|
||||
Reference in New Issue
Block a user