Current section

Files

Jump to
bandit lib bandit.ex
Raw

lib/bandit.ex

defmodule Bandit do
@moduledoc """
Defines a Bandit server as part of a supervision tree. A typical child spec
to start a Bandit server hosting a plug looks like:
```
{Bandit, plug: {MyApp.Plug, :arg_passed_to_plug_init}, options: [port: 4000]}
```
Three options are supported:
* `scheme`: One of `:http` or `:https`. If `:https` is supported, you will need
to specify `certfile` and `keyfile` in the `transport_options` subsection of `options`.
* `plug`: The plug to handle connections. Can be specified as `MyPlug` or `{MyPlug, plug_opts}`
* `read_timeout`: How long to wait for data from the client before timing out and closing the
connection, specified in milliseconds. Defaults to 60_000
* `options`: Options to pass to `ThousandIsland`. For an exhaustive list of options see the
`ThousandIsland` documentation, however some common options are:
* `port`: The port to bind to. Defaults to 4000
* `num_acceptors`: The number of acceptor processes to run. This is mostly a performance
tuning knob and can usually be left at the default value of 10
* `transport_module`: The name of the module which provides basic socket functions.
This overrides any value set for `scheme` and is intended for cases where control
over the socket at a fundamental level is needed.
* `transport_options`: A keyword list of options to be passed into the transport socket's listen function
"""
@typedoc "A Plug definition"
@type plug :: {module(), keyword()}
@spec child_spec([]) :: Supervisor.child_spec()
def child_spec(arg) do
{options, illegal_options} =
arg
|> Keyword.get(:options, [])
|> Keyword.split(~w(port num_acceptors transport_module transport_options)a)
if illegal_options != [] do
raise "Unsupported option(s) in Bandit config: #{inspect(illegal_options)}"
end
{transport_module, extra_transport_options} =
case Keyword.get(arg, :scheme, :http) do
:http -> {ThousandIsland.Transports.TCP, []}
:https -> {ThousandIsland.Transports.SSL, alpn_preferred_protocols: ["h2", "http/1.1"]}
end
read_timeout = Keyword.get(arg, :read_timeout, 60_000)
options =
options
|> Keyword.put_new(:transport_module, transport_module)
|> Keyword.update(
:transport_options,
extra_transport_options,
&Keyword.merge(&1, extra_transport_options)
)
|> Keyword.put(:handler_module, Bandit.DelegatingHandler)
|> Keyword.put(:handler_options, %{
plug: plug(arg),
handler_module: Bandit.InitialHandler,
read_timeout: read_timeout
})
%{id: Bandit, start: {ThousandIsland, :start_link, [options]}}
end
defp plug(arg) do
arg
|> Keyword.fetch!(:plug)
|> case do
{plug, plug_options} -> {plug, plug.init(plug_options)}
plug -> {plug, plug.init([])}
end
end
end