#web-server #server #async-http #http #async #light-weight

servt

A small, lightweight, and fast optionally asynchronous HTTP server library for Rust

2 unstable releases

0.2.0 Feb 15, 2024
0.1.0 Feb 14, 2024

#1424 in HTTP server

MIT license

23KB
417 lines

servt

a programmatic web server, with very few dependencies.

why

  • many big frameworks are too heavy for small projects, or don't suit yours (or my!) development style
  • so this is small, easy to use, but still powerful

features

async

  • enabled by default, adds smol as a dependency (adds around 35 deps)
  • executes all requests by spawning a new task
  • if not enabled, falls back to std::thread (which spawns a new thread for each request)

time

  • enabled by default, adds chrono as a dependency (adds around 2 deps, as the features enabled are very few, namely alloc and now)
  • adds a Date header to all responses
  • this is technically required by the HTTP/1.1 spec, but the majority of clients will work without it

lib.rs:

A simple, easy to use, and fast web server library for Rust.

Designed to be easy, simple and fast, though powerful enough to handle most use cases.

Features

  • Simple and easy to use
  • Multi-threaded (or async if you enable the async feature
  • Redirects
  • Custom error pages
  • Custom routes (with query string and form parsing)
  • 100-continue support
  • Custom status codes

A few notes

  • The server by default uses multithreading, but you can enable the async feature to use async instead.
  • The Date header is included by default, but you can disable the time feature to exclude it (and save a couple of dependencies). If you don't enable it, bear in mind that is against the HTTP/1.1 spec, but most clients don't care, and thus it is included as an option in order to keep the library as lightweight as possible if configured that way.
  • At the moment, the server does not support keep-alive connections, but it is planned for the future (along with possible HTTP/2 support).
  • Deliberately does not support Last-Modified, If-Modified-Since, etc., because it is not designed to serve static files, but rather functions which are not trackable in the same way.

Ensure your callbacks don't panic

  • If a callback panics, the mutex is poisoned and thus the server will error out with a 500 Internal Server Error on any subsequent requests to the route - therefore, ensure your callbacks don't panic (or handle any errors and return a 500 error).

Supported path formats

  • /path

  • /path/

  • /path?query=string

  • /path/?query=string

  • site.com/path

  • site.com/path/

  • site.com/path?query=string

  • site.com/path/?query=string

  • Note that the Host header is mandated by the HTTP/1.1 spec, but if a request is sent with HTTP 1.0, the server will not enforce it (else it will error out with a 400 Bad Request).

Examples

Basic 'Hello, World!' server

use servt::{Server, ParsedRequest};

let mut server = Server::new(8080, "localhost".to_string());
server.route("/", |req| ("Hello, World!".to_string(), 200));

server.run();

Example good practice form handling

use servt::{Server, ParsedRequest};

let mut server = Server::new(8080, "localhost".to_string());
server.route("/", |req| match req.form {
   Some(form) => (format!("Hello, {}!", form.get("name").unwrap_or(&"World".to_string())), 200),
   None => ("Hello, World!".to_string(), 200),
});

server.run();

Custom error pages

use servt::{Server, ParsedRequest};

let mut server = Server::new(8080, "localhost".to_string());
server.error(404, |_| ("Custom 404 page".to_string(), 404));

server.run();

Dependencies

~0.1–9MB
~89K SLoC