View Source Bandit (Bandit v1.6.0)

Bandit is an HTTP server for Plug and WebSock apps.

As an HTTP server, Bandit's primary goal is to act as 'glue' between client connections managed by Thousand Island and application code defined via the Plug and/or WebSock APIs. As such there really isn't a whole lot of user-visible surface area to Bandit, and as a consequence the API documentation presented here is somewhat sparse. This is by design! Bandit is intended to 'just work' in almost all cases; the only thought users typically have to put into Bandit comes in the choice of which options (if any) they would like to change when starting a Bandit server. The sparseness of the Bandit API should not be taken as an indicator of the comprehensiveness or robustness of the project.

Using Bandit With Phoenix

Bandit fully supports Phoenix. Phoenix applications which use WebSockets for features such as Channels or LiveView require Phoenix 1.7 or later.

Using Bandit to host your Phoenix application couldn't be simpler:

  1. Add Bandit as a dependency in your Phoenix application's mix.exs:

     {:bandit, "~> 1.0"}
  2. Add the following adapter: line to your endpoint configuration in config/config.exs, as in the following example:

      # config/config.exs
    
      config :your_app, YourAppWeb.Endpoint,
        adapter: Bandit.PhoenixAdapter, # <---- ADD THIS LINE
        url: [host: "localhost"],
        render_errors: ...
  3. That's it! You should now see messages at startup indicating that Phoenix is using Bandit to serve your endpoint, and everything should 'just work'. Note that if you have set any exotic configuration options within your endpoint, you may need to update that configuration to work with Bandit; see the Bandit.PhoenixAdapter documentation for more information.

Using Bandit With Plug Applications

Using Bandit to host your own Plug is very straightforward. Assuming you have a Plug module implemented already, you can host it within Bandit by adding something similar to the following to your application's Application.start/2 function:

# lib/my_app/application.ex

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      {Bandit, plug: MyApp.MyPlug}
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

For less formal usage, you can also start Bandit using the same configuration options via the Bandit.start_link/1 function:

# Start an http server on the default port 4000, serving MyApp.MyPlug
Bandit.start_link(plug: MyPlug)

Configuration

A number of options are defined when starting a server. The complete list is defined by the t:Bandit.options/0 type.

Setting up an HTTPS Server

By far the most common stumbling block encountered when setting up an HTTPS server involves configuring key and certificate data. Bandit is comparatively easy to set up in this regard, with a working example looking similar to the following:

# lib/my_app/application.ex

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      {Bandit,
       plug: MyApp.MyPlug,
       scheme: :https,
       certfile: "/absolute/path/to/cert.pem",
       keyfile: "/absolute/path/to/key.pem"}
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

WebSocket Support

If you're using Bandit to run a Phoenix application as suggested above, there is nothing more for you to do; WebSocket support will 'just work'.

If you wish to interact with WebSockets at a more fundamental level, the WebSock and WebSockAdapter libraries provides a generic abstraction for WebSockets (very similar to how Plug is a generic abstraction on top of HTTP). Bandit fully supports all aspects of these libraries.

Summary

Types

Options to configure the deflate library used for HTTP compression

Options to configure the HTTP/1 stack in Bandit

Options to configure the HTTP/2 stack in Bandit

Options to configure shared aspects of the HTTP stack in Bandit

Possible top-level options to configure a Bandit server

Options to configure the WebSocket stack in Bandit

Functions

Starts a Bandit server using the provided arguments. See options/0 for specific options to pass to this function.

Types

@type deflate_options() :: [
  level: :zlib.zlevel(),
  window_bits: :zlib.zwindowbits(),
  memory_level: :zlib.zmemlevel(),
  strategy: :zlib.zstrategy()
]

Options to configure the deflate library used for HTTP compression

@type http_1_options() :: [
  enabled: boolean(),
  max_request_line_length: pos_integer(),
  max_header_length: pos_integer(),
  max_header_count: pos_integer(),
  max_requests: pos_integer(),
  clear_process_dict: boolean(),
  gc_every_n_keepalive_requests: pos_integer(),
  log_unknown_messages: boolean()
]

Options to configure the HTTP/1 stack in Bandit

  • enabled: Whether or not to serve HTTP/1 requests. Defaults to true
  • max_request_line_length: The maximum permitted length of the request line (expressed as the number of bytes on the wire) in an HTTP/1.1 request. Defaults to 10_000 bytes
  • max_header_length: The maximum permitted length of any single header (combined key & value, expressed as the number of bytes on the wire) in an HTTP/1.1 request. Defaults to 10_000 bytes
  • max_header_count: The maximum permitted number of headers in an HTTP/1.1 request. Defaults to 50 headers
  • max_requests: The maximum number of requests to serve in a single HTTP/1.1 connection before closing the connection. Defaults to 0 (no limit)
  • clear_process_dict: Whether to clear the process dictionary of all non-internal entries between subsequent keepalive requests. If set, all keys not starting with $ are removed from the process dictionary between requests. Defaults to true
  • gc_every_n_keepalive_requests: How often to run a full garbage collection pass between subsequent keepalive requests on the same HTTP/1.1 connection. Defaults to 5 (garbage collect between every 5 requests). This option is currently experimental, and may change at any time
  • log_unknown_messages: Whether or not to log unknown messages sent to the handler process. Defaults to false
@type http_2_options() :: [
  enabled: boolean(),
  max_header_block_size: pos_integer(),
  max_requests: pos_integer(),
  default_local_settings: keyword()
]

Options to configure the HTTP/2 stack in Bandit

  • enabled: Whether or not to serve HTTP/2 requests. Defaults to true
  • max_header_block_size: The maximum permitted length of a field block of an HTTP/2 request (expressed as the number of compressed bytes). Includes any concatenated block fragments from continuation frames. Defaults to 50_000 bytes
  • max_requests: The maximum number of requests to serve in a single HTTP/2 connection before closing the connection. Defaults to 0 (no limit)
  • default_local_settings: Options to override the default values for local HTTP/2 settings. Values provided here will override the defaults specified in RFC9113§6.5.2
@type http_options() :: [
  compress: boolean(),
  deflate_options: deflate_options(),
  log_exceptions_with_status_codes: list() | Range.t(),
  log_protocol_errors: :short | :verbose | false,
  log_client_closures: :short | :verbose | false
]

Options to configure shared aspects of the HTTP stack in Bandit

  • compress: Whether or not to attempt compression of responses via content-encoding negotiation as described in RFC9110§8.4. Defaults to true
  • deflate_options: A keyword list of options to set on the deflate library. A complete list can be found at deflate_options/0. Note that these options only affect the behaviour of the 'deflate' content encoding; 'gzip' does not have any configurable options (this is a limitation of the underlying :zlib library)
  • log_exceptions_with_status_codes: Which exceptions to log. Bandit will log only those exceptions whose status codes (as determined by Plug.Exception.status/1) match the specified list or range. Defaults to 500..599
  • log_protocol_errors: How to log protocol errors such as malformed requests. :short will log a single-line summary, while :verbose will log full stack traces. The value of false will disable protocol error logging entirely. Defaults to :short
  • log_client_closures: How to log cases where the client closes the connection. These happen routinely in the real world and so the handling of them is configured separately since they can be quite noisy. Takes the same options as log_protocol_errors, but defaults to false
@type options() :: [
  {:plug, module() | {module(), Plug.opts()}}
  | {:scheme, :http | :https}
  | {:port, :inet.port_number()}
  | {:ip, :inet.socket_address()}
  | :inet
  | :inet6
  | {:keyfile, binary()}
  | {:certfile, binary()}
  | {:otp_app, Application.app()}
  | {:cipher_suite, :strong | :compatible}
  | {:display_plug, module()}
  | {:startup_log, Logger.level() | false}
  | {:thousand_island_options, ThousandIsland.options()}
  | {:http_options, http_options()}
  | {:http_1_options, http_1_options()}
  | {:http_2_options, http_2_options()}
  | {:websocket_options, websocket_options()}
]

Possible top-level options to configure a Bandit server

  • plug: The Plug to use to handle connections. Can be specified as MyPlug or {MyPlug, plug_opts}
  • scheme: One of :http or :https. If :https is specified, you will also need to specify valid certfile and keyfile values (or an equivalent value within thousand_island_options.transport_options). Defaults to :http
  • port: The TCP port to listen on. This option is offered as a convenience and actually sets the option of the same name within thousand_island_options. If a string value is passed, it will be parsed as an integer. Defaults to 4000 if scheme is :http, and 4040 if scheme is :https
  • ip: The interface(s) to listen on. This option is offered as a convenience and actually sets the option of the same name within thousand_island_options.transport_options. Can be specified as:
    • {1, 2, 3, 4} for IPv4 addresses
    • {1, 2, 3, 4, 5, 6, 7, 8} for IPv6 addresses
    • :loopback for local loopback (ie: 127.0.0.1)
    • :any for all interfaces (ie: 0.0.0.0)
    • {:local, "/path/to/socket"} for a Unix domain socket. If this option is used, the port option must be set to 0
  • inet: Only bind to IPv4 interfaces. This option is offered as a convenience and actually sets the option of the same name within thousand_island_options.transport_options. Must be specified as a bare atom :inet
  • inet6: Only bind to IPv6 interfaces. This option is offered as a convenience and actually sets the option of the same name within thousand_island_options.transport_options. Must be specified as a bare atom :inet6
  • keyfile: The path to a file containing the SSL key to use for this server. This option is offered as a convenience and actually sets the option of the same name within thousand_island_options.transport_options. If a relative path is used here, you will also need to set the otp_app parameter and ensure that the named file is part of your application build
  • certfile: The path to a file containing the SSL certificate to use for this server. This option is offered as a convenience and actually sets the option of the same name within thousand_island_options.transport_options. If a relative path is used here, you will also need to set the otp_app parameter and ensure that the named file is part of your application build
  • otp_app: Provided as a convenience when using relative paths for keyfile and certfile
  • cipher_suite: Used to define a pre-selected set of ciphers, as described by Plug.SSL.configure/1. Optional, can be either :strong or :compatible
  • display_plug: The plug to use when describing the connection in logs. Useful for situations such as Phoenix code reloading where you have a 'wrapper' plug but wish to refer to the connection by the endpoint name
  • startup_log: The log level at which Bandit should log startup info. Defaults to :info log level, can be set to false to disable it
  • thousand_island_options: A list of options to pass to Thousand Island. Bandit sets some default values in this list based on your top-level configuration; these values will be overridden by values appearing here. A complete list can be found at ThousandIsland.options/0
  • http_options: A list of options to configure the shared aspects of Bandit's HTTP stack. A complete list can be found at http_options/0
  • http_1_options: A list of options to configure Bandit's HTTP/1 stack. A complete list can be found at http_1_options/0
  • http_2_options: A list of options to configure Bandit's HTTP/2 stack. A complete list can be found at http_2_options/0
  • websocket_options: A list of options to configure Bandit's WebSocket stack. A complete list can be found at websocket_options/0
@type websocket_options() :: [
  enabled: boolean(),
  max_frame_size: pos_integer(),
  validate_text_frames: boolean(),
  compress: boolean()
]

Options to configure the WebSocket stack in Bandit

  • enabled: Whether or not to serve WebSocket upgrade requests. Defaults to true
  • max_frame_size: The maximum size of a single WebSocket frame (expressed as a number of bytes on the wire). Defaults to 0 (no limit)
  • validate_text_frames: Whether or not to validate text frames as being UTF-8. Strictly speaking this is required per RFC6455§5.6, however it can be an expensive operation and one that may be safely skipped in some situations. Defaults to true
  • compress: Whether or not to allow per-message deflate compression globally. Note that upgrade requests still need to set the compress: true option in connection_opts on a per-upgrade basis for compression to be negotiated (see 'WebSocket Support' section below for details). Defaults to true

Functions

@spec start_link(options()) :: Supervisor.on_start()

Starts a Bandit server using the provided arguments. See options/0 for specific options to pass to this function.