Expand description

NOTE: This library was renamed to Servlin.

Beatrice

A modular HTTP server library in Rust.

Features

  • forbid(unsafe_code)
  • Threaded request handlers:
    FnOnce(Request) -> Response + 'static + Clone + Send + Sync
  • Uses async code internally for excellent performance under load
  • JSON
  • Server-Sent Events (SSE)
  • Saves large request bodies to temp files
  • Sends 100-Continue
  • Limits number of threads and connections
  • Modular: roll your own logging, write custom versions of internal methods, etc.
  • No macros or complicated type params
  • Good test coverage (63%)

Limitations

  • New, not proven in production.
  • To do:
    • Request timeouts
    • chunked transfer-encoding for request bodies
    • gzip
    • brotli
    • TLS
    • automatically getting TLS certs via ACME
    • Drop idle connections when approaching connection limit.
    • Denial-of-Service mitigation: source throttling, minimum throughput
    • Complete functional test suite
    • Missing load tests
    • Disk space usage limits

Examples

Complete examples: examples/.

Simple example:

use beatrice::{
    print_log_response,
    socket_addr_127_0_0_1,
    HttpServerBuilder,
    Request,
    Response
};
use beatrice::reexport::{safina_executor, safina_timer};
use serde::Deserialize;
use serde_json::json;
use std::sync::Arc;
use temp_dir::TempDir;

struct State {}

fn hello(_state: Arc<State>, req: &Request) -> Result<Response, Response> {
    #[derive(Deserialize)]
    struct Input {
        name: String,
    }
    let input: Input = req.json()?;
    Ok(Response::json(200, json!({"message": format!("Hello, {}!", input.name)}))
    .unwrap())
}

fn handle_req(state: Arc<State>, req: &Request) -> Result<Response, Response> {
    match (req.method(), req.url().path()) {
        ("GET", "/ping") => Ok(Response::text(200, "ok")),
        ("POST", "/hello") => hello(state, req),
        _ => Ok(Response::text(404, "Not found")),
    }
}

let state = Arc::new(State {});
let request_handler = move |req: Request| {
    print_log_response(&req, handle_req(state, &req))
};
let cache_dir = TempDir::new().unwrap();
safina_timer::start_timer_thread();
let executor = safina_executor::Executor::new(1, 9).unwrap();
executor.block_on(
    HttpServerBuilder::new()
        .listen_addr(socket_addr_127_0_0_1(8000))
        .max_conns(1000)
        .small_body_len(64 * 1024)
        .receive_large_bodies(cache_dir.path())
        .spawn_and_join(request_handler)
).unwrap();

Cargo Geiger Safety Report

Alternatives

See rust-webserver-comparison.md.

Changelog

  • v0.3.2 - Renaming project to ‘servlin’.
  • v0.3.1 - Add Response::include_dir.
  • v0.3.0
    • Add RequestBody::StaticBytes.
    • Add ResponseBody::StaticBytes.
    • Remove impl From<&[u8]> for RequestBody and ResponseBody.
  • v0.2.0 - Make print_log_response easier to use.
  • v0.1.0 - First published version

TO DO

  • Fix limitations above
  • Support HEAD responses that have Content-Length set and no body.
  • Update rust-webserver-comparison.md

Modules

This part of the library is not covered by the semver guarantees. If you use these in your program, a minor version upgrade could break your build.

Structs

Wraps a String that contains only US-ASCII chars.

Builds an HTTP server.

Enums

Struct returned by RequestBody::async_reader and ResponseBody::async_reader.

Struct returned by RequestBody::reader and ResponseBody::reader.

Functions