Understand the HTTP/1 process model in Bandit
mainkeep-alive feature to send multiple requests over the same connection, all those requests will be serviced by the same process.repository·main·Indexed 23 days ago
https://github.com/mtrudel/banditA high-performance, Elixir-native HTTP server for Plug and WebSock applications. Bandit supports HTTP/1.x, HTTP/2, and WebSockets over both HTTP and HTTPS, and serves as the default server for Phoenix since version 1.7.11. It provides a drop-in replacement for Cowboy in Phoenix applications via the Bandit.PhoenixAdapter.
keep-alive feature to send multiple requests over the same connection, all those requests will be serviced by the same process.Bandit implements HTTP/2 using a two-tier process model to balance connection management and request concurrency:
Bandit.HTTP2.Handler process exists per client connection. It implements the ThousandIsland.Handler behaviour and is supervised by Thousand Island. It manages the overall connection state via a Bandit.HTTP2.Connection struct.Bandit.HTTP2.StreamProcess exists per HTTP request (stream) within a connection. These are started by the connection process via start_link and are not supervised. They manage stream-specific state via a Bandit.HTTP2.Stream struct.Lifecycle & Error Handling:
:init to :closed).Upgrading an HTTP connection to a WebSocket connection in Bandit involves a coordinated process between Bandit, WebSockAdapter, and Plug.
Plug call.WebSockAdapter.upgrade/4.WebSockAdapter.upgrade/4 validates the request and calls Plug.Conn.upgrade_adapter/3 to signal Bandit.Plug.call/2 callback, Bandit.Pipeline performs the upgrade.Bandit.DelegatingHandler switches the connection's handler to Bandit.WebSocket.Handler, handing control to Bandit's WebSocket stack for all future communication.When an HTTP/2 stream is active, Bandit executes the server's configured Plug.
Bandit.HTTP2.Stream struct within a Bandit.HTTP2.StreamProcess.Bandit.Adapter struct.In a Bandit server, every WebSocket connection is modeled as a single process tied to the lifecycle of the underlying connection.
Bandit.DelegatingHandler.Bandit.DelegatingHandler calls handle_connection/2 to allow the WebSocket handler to initialize startup state.Bandit.WebSocket.Connection struct and module.Thousand Island library is passed to Bandit.WebSocket.Handler.handle_data/3. This method parses the data into WebSocket frames, which are then passed to the configured WebSock handler via the Bandit.WebSocket.Connection.Bandit provides full support for WebSockets.
WebSock and WebSockAdapter libraries, which provide a generic abstraction for WebSockets similar to how Plug works for HTTP.The data flow for an HTTP/2 connection follows these steps:
Bandit.HTTP2.Handler.handle_data/3.Bandit.HTTP2.Frame.deserialize/2. Unparsed bytes are buffered to handle fragmented data.Bandit.HTTP2.Connection.handle_frame/3 along with a Bandit.HTTP2.Connection struct.Bandit.HTTP2.StreamProcess.Bandit.HTTP2.Stream). Frames sent to streams that are already closed are discarded.Bandit.HTTP2.Connection module signals a normal or error-driven connection closure.The execution flow for an HTTP/1 request follows these steps:
Thousand Island library calls Bandit.HTTP1.Handler.handle_data/3.handle_data/3 constructs a Bandit.HTTP1.Socket struct that implements the Bandit.HTTPTransport protocol.Bandit.Pipeline.run/3 is called to read the request using the Bandit.HTTPTransport protocol.Plug.Conn structure is constructed to represent the request.Plug.Conn is passed to the configured Plug module.To run Bandit over HTTPS, specify the scheme: :https and provide the paths to your certificate and key files in the options passed to the Bandit child process.
# 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
endYou can host a Plug module using Bandit by starting it within your application's supervision tree or by calling Bandit.start_link/1 directly.
Add {Bandit, plug: YourPlugModule} to your children list in lib/my_app/application.ex.
Bandit.start_link/1For less formal usage, call the function directly:
# Start an http server on the default port 4000, serving MyApp.MyPlug
Bandit.start_link(plug: MyPlug)# 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
endTo use Bandit in your Elixir project, add it to your mix.exs dependencies.
def deps do
[
{:bandit, "~> 1.8"}
]
endBandit can be used as a drop-in replacement for Cowboy in Phoenix applications. For Phoenix applications using WebSockets (like Channels or LiveView), ensure you are using Phoenix 1.7 or later.
{:bandit, "~> 1.8"} to your mix.exs.config/config.exs to use Bandit.PhoenixAdapter.Note: If you have used exotic configuration options in your endpoint, you may need to update them to be compatible with Bandit. Refer to the Bandit.PhoenixAdapter documentation for details.
# config/config.exs
config :your_app, YourAppWeb.Endpoint,
adapter: Bandit.PhoenixAdapter, # <---- ADD THIS LINE
url: [host: "localhost"],
render_errors: ...