• Stars
    star
    1,484
  • Rank 30,401 (Top 0.7 %)
  • Language
    Elixir
  • License
    MIT License
  • Created over 4 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Bandit is a pure Elixir HTTP server for Plug & WebSock applications

Bandit Bandit

Build Status Docs Hex.pm

Bandit is an HTTP server for Plug and WebSock apps.

Bandit is written entirely in Elixir and is built atop Thousand Island. It can serve HTTP/1.x, HTTP/2 and WebSocket clients over both HTTP and HTTPS. It is written with correctness, clarity & performance as fundamental goals.

In ongoing automated performance tests, Bandit's HTTP/1.x engine is up to 4x faster than Cowboy depending on the number of concurrent requests. When comparing HTTP/2 performance, Bandit is up to 1.5x faster than Cowboy. This is possible because Bandit has been built from the ground up for use with Plug applications; this focus pays dividends in both performance and also in the approachability of the code base.

Bandit also emphasizes correctness. Its HTTP/2 implementation scores 100% on the h2spec suite in strict mode, and its WebSocket implementation scores 100% on the Autobahn test suite, both of which run as part of Bandit's comprehensive CI suite. Extensive unit test, credo, dialyzer, and performance regression test coverage round out a test suite that ensures that Bandit is and will remain a platform you can count on.

Lastly, Bandit exists to demystify the lower layers of infrastructure code. In a world where The New Thing is nearly always adding abstraction on top of abstraction, it's important to have foundational work that is approachable & understandable by users above it in the stack.

Project Goals

  • Implement comprehensive support for HTTP/1.0 through HTTP/2 & WebSockets (and beyond) backed by obsessive RFC literacy and automated conformance testing
  • Aim for minimal internal policy and HTTP-level configuration. Delegate to Plug & WebSock as much as possible, and only interpret requests to the extent necessary to safely manage a connection & fulfill the requirements of safely supporting protocol correctness
  • Prioritize (in order): correctness, clarity, performance. Seek to remove the mystery of infrastructure code by being approachable and easy to understand
  • Along with our companion library Thousand Island, become the go-to HTTP & low-level networking stack of choice for the Elixir community by being reliable, efficient, and approachable

Project Status

  • Complete support for Phoenix applications (WebSocket support requires Phoenix 1.7+)
  • Complete support of the Plug API
  • Complete support of the WebSock API
  • Complete server support for HTTP/1.x as defined in RFC 9112 & RFC 9110
  • Complete server support for HTTP/2 as defined in RFC 9113 & RFC 9110, comprehensively covered by automated h2spec conformance testing. Though deprecated by later RFCs, Bandit also supports h2c upgrades as specified in RFC7540
  • Support for HTTP content encoding compression on both HTTP/1.x and HTTP/2. gzip and deflate methods are supported per RFC9110ยง8.4.1.{2,3}
  • Complete server support for WebSockets as defined in RFC 6455, comprehensively covered by automated Autobahn conformance testing. Per-message compression as defined in RFC 7692 is also supported
  • Extremely scalable and performant client handling at a rate up to 4x that of Cowboy for the same workload with as-good-or-better memory use

Any Phoenix or Plug app should work with Bandit as a drop-in replacement for Cowboy; exceptions to this are errors (if you find one, please file an issue!).

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-pre"}
  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:

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

  opts = [strategy: :one_for_one, name: MyApp.Supervisor]
  Supervisor.start_link(children, opts)
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:

def start(_type, _args) do
  children = [
    {Bandit,
     plug: 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

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.

Implementation Details

Bandit primarily consists of three protocol-specific implementations, one each for HTTP/1, HTTP/2 and WebSockets. Each of these implementations is largely distinct from one another, and is described in its own README linked above.

If you're just taking a casual look at Bandit or trying to understand how an HTTP server works, the HTTP/1 implementation is likely the best place to start exploring.

Contributing

Contributions to Bandit are very much welcome! Before undertaking any substantial work, please open an issue on the project to discuss ideas and planned approaches so we can ensure we keep progress moving in the same direction.

All contributors must agree and adhere to the project's Code of Conduct.

Security disclosures should be handled per Bandit's published security policy.

Installation

Bandit is available in Hex. The package can be installed by adding bandit to your list of dependencies in mix.exs:

def deps do
  [
    {:bandit, "~> 1.0-pre"}
  ]
end

Documentation can be found at https://hexdocs.pm/bandit.

License

MIT

More Repositories

1

thousand_island

Thousand Island is a pure Elixir socket server
Elixir
703
star
2

hap

A HomeKit Accessory Protocol (HAP) Implementation for Elixir
Elixir
74
star
3

machete

Literate test matchers for ExUnit
Elixir
43
star
4

MTStackableNavigationController

A drop-in replacement for UINavigationController with stacked views ala Path / Facebook.
Objective-C
39
star
5

beats

Beats is a drum machine
Elixir
38
star
6

pragmatic_context

A library to declaratively add JSON-LD support to your ActiveModel objects
Ruby
29
star
7

boiler

11
star
8

MTMultipleViewController

A container view controller that allows the selection of child views based on a UISegmentedControl in the navigation bar
Objective-C
11
star
9

hawk

A simple iOS ad-hoc distribution tool, backed by S3 and good old fashioned email
Ruby
9
star
10

desk_clock

A Nerves-powered, NTP-synchronized, SPI-connected, OLED-outputting desktop clock
Elixir
8
star
11

man_or_machine

A handy-dandy Adhearsion component that detects an answering machine at the far end of a call and facilitates differing behaviours as a result
Ruby
8
star
12

talks

Source for various talks I've given
Elixir
8
star
13

elixir-ci-actions

Shared GitHub Actions workflows for Elixir CI pipelines
7
star
14

doo

Doo - a relentlessly polymorphic approach to deployment scripting
Ruby
6
star
15

MTCollectionOperators

Objective-C
5
star
16

minicap

Minicap replaces the core bits of the stock capistrano recipes with a tiny git-focused implementation
Ruby
5
star
17

Prefer

The simple preference setter for OS X
Objective-C
4
star
18

rainmaker

Rainmaker is a pragmatic UEC (Ubuntu Elastic Cloud) manager
Ruby
4
star
19

benchmark

Benchmarking software for Plug servers
Elixir
3
star
20

MTGenericSemimodalSegue

Objective-C
3
star
21

hap.rs

Rust
3
star
22

Jumpcut

A minimalist clipboard buffer for OS X
Objective-C
3
star
23

MTTextViewController

Objective-C
3
star
24

easel

Easel gets your model cozy with RDF
Ruby
3
star
25

network_benchmark

Elixir
3
star
26

menutree

a simple hierachical command line shell
Ruby
3
star
27

ex_paint

A simple 2D rasterizer for Elixir
Elixir
2
star
28

basicboxen

Basic boxen is a simple starting set of recipes and sensible defaults to build servers using chef-solo
Ruby
2
star
29

filewall

git + capistrano + shorewall = filewall. it's what you want
Ruby
2
star
30

matchat

The simplest chatroom
Ruby
2
star
31

RelayrAce

RelayrAce is a quick and dirty rubygem to talk to the Canakit (and sparkfun) USB controller relay kit
Ruby
2
star
32

ssd1322

Elixir library for controlling SSD1322 based OLED displays
Elixir
1
star
33

doo-extras

A set of base Ubuntu recipes for doo
Ruby
1
star
34

upstairsbox

Elixir
1
star
35

dotfiles

My simple zsh / Neovim / asdf / Elixir / Ruby / macOS focused dotfiles
Shell
1
star
36

mox_demo

A test-driven introduction to the Mox library
Elixir
1
star
37

hap_demo

A demo app for HAP, the Elixir HomeKit Accessory Protocol library
Elixir
1
star
38

rpi-breakout

A simple Raspberry Pi pHAT to break out common interfaces & GPIO
1
star
39

vimfiles

My vim files
Vim Script
1
star
40

pagerduty_user_demo

Elixir
1
star
41

Smart-Keywords

Firefox & Chrome style Smart Keywords for Safari
1
star
42

Former

Former is a wrapper around a minimal web interface meant to provide interstitial web based interfaces to command line driven programs
1
star
43

heretic

Heretic is a file-based semi-structured document library
1
star
44

iolist_test

Elixir
1
star
45

pibox

Docker recipes for the rPi that runs our house
Go
1
star