9 releases (stable)
| 1.0.5 | Nov 11, 2025 |
|---|---|
| 1.0.3 | Nov 10, 2025 |
| 0.1.2 | Nov 8, 2025 |
#2 in #micro-framework
150KB
4K
SLoC
bbwebservice
Rust-native port of the original Python bbwebservice, built on the Rust standard library with rustls providing native TLS support. This guide shows a minimal app, core concepts, and how to exercise the API.
use bbwebservice::{
register, start_blocking, MIME_TYPE, STORE_VARS, response, set_logging, LOGGING_OPTIONS,
};
fn main() {
// Optional: enable request logging
set_logging(LOGGING_OPTIONS::REQUEST, true, None);
// Minimal GET handler
register("::/hello", MIME_TYPE::TEXT, |ctx| {
let who = ctx.query_string.get("name").cloned().unwrap_or_else(|| "World".into());
format!("Hello, {who}!").into()
});
// Start all listeners defined in config/config.json
start_blocking();
}
Overview
bbwebservice mirrors the Python framework:
- Decorator-style routing (
register,post_handler,UrlTemplate, scoped selectors) - HTTP runtime with incremental header/body parsing (chunked, ranged, cookies, queries)
- Response helpers (
Response,Redirect,PartialContent,Dynamic,response()) - Global utilities (
load_file,urlencoded_to_map,set_cookie, etc.) - Configuration via
config/config.jsonwith the same schema as the Python original - Worker pool & backpressure (bounded stdlib threads, keep-alive control, queue limits)
- Logging & CORS with the same scope system, callbacks, and automatic OPTIONS replies
- TLS/HTTPS powered by
rustlswheneverSSLlisteners are enabled (including SNI)
Paths are resolved relative to the executable. On first run the library creates content/ and config/config.json if they are missing (default config matches the Python defaults).
Getting Started
- Clone the repository and change into
rust-bbwebservice/bbwebservice/. - Use Rust 1.66+ (
cargo check/cargo build). - Adjust
config/config.jsonif needed. - Add the crate from crates.io:
[dependencies]
bbwebservice = "<latest version on crates.io>"
Routing & Handlers
| Function | Description |
|---|---|
register(route, mime, handler) |
Registers GET/HEAD routes. |
post_handler, put_handler, patch_handler, delete_handler, options_handler |
Work like the Python decorators; handlers that need request data accept a RequestContext. |
UrlTemplate |
Uses the familiar syntax ip:port::domain:/path/{var:type} with int, float, bool, str, path. |
split_route_scope |
Parses ip:port::domain:/path strings for custom tooling. |
format_ip_port |
Formats scopes like the Python helper. |
error_handler |
Registers custom pages for status codes. |
Routes can be scoped by IP/port/domain; matching priority is the same as in Python (more specific scopes win). Templates populate STORE_VARS.TEMPLATE_VARS automatically.
RequestContext & STORE_VARS
Handlers receive a RequestContext, which mirrors the Python args dict. String constants under STORE_VARS remain available for compatibility. Key fields:
ctx.post: raw body (&[u8])ctx.query_string:HashMap<String, String>ctx.flags: e.g.["urlencoded"],["partial"]ctx.cookies: parsed cookiesctx.response:ResponseMessage(status, headers, body)ctx.is_cancelled(): cooperative watchdog flag that flips when the handler timeout expires
urlencoded_to_map(ctx.post) converts application/x-www-form-urlencoded payloads just like in Python.
Responses & Helpers
| Type / Helper | Behavior |
|---|---|
String / &'static str |
Returned as UTF‑8 with mime_type; charset=utf-8. |
Vec<u8> / bytes |
Raw payload with the supplied MIME type. |
Dynamic |
Wraps arbitrary bytes plus MIME type. |
PartialContent |
Supports range responses (bytes=start-end). |
Redirect |
303/307-style redirects with Location. |
Response / response() |
Full manual control over status, headers, body. |
Logic matches Python: HEAD suppresses bodies, PartialContent sets Content-Range, Redirect drops Content-Type, and registered error_handlers are used when set.
Large payloads (including PartialContent) stream directly from disk in ~64 KiB chunks. Whenever the server knows the total length it sends Content-Length; otherwise it automatically upgrades the response to chunked transfer encoding so handlers never need to buffer whole files.
Logging
use bbwebservice::{set_logging, log_to_file, LOGGING_OPTIONS};
set_logging(LOGGING_OPTIONS::DEBUG, true, None); // global
set_logging(LOGGING_OPTIONS::REQUEST, true, Some("127.0.0.1:5000::/api")); // scoped
log_to_file("/logs/server.log", &[LOGGING_OPTIONS::ERROR], None);
- Scopes use the same
ip:port::domainnotation as routes. - Register additional callbacks via
set_logging_callback(signature(msg, timestamp, level)). LOGGING_OPTIONS::TIMEprepends timestamps to console output.
CORS
use bbwebservice::{enable_cors, disable_cors};
enable_cors(
"*",
&["GET", "POST"],
&["Content-Type"],
&["X-Total-Count"],
false,
600,
);
When enabled the server injects the CORS headers and auto-responds to OPTIONS with 204 No Content (including Allow). disable_cors() fully disables the feature.
Worker Pool, Backpressure & Keep-Alive
- Global thread pool sized by
max_threadsinconfig/config.json(default 100). The queue size is doubled; if full, new connections get503 Service Unavailable. - Each listener can set
max_threadsto limit its own concurrency. - Keep-alive is governed by
keep_alive_timeoutandkeep_alive_max_requests. Callset_keep_alive_limits()to adjust at runtime. - Keep-alive responses include a
Keep-Alive: timeout=.., max=..header so clients know when to re-connect. - Chunked bodies,
Content-Length, timeouts, and range requests are handled per connection, preventing slow clients from stalling the server.
Configuration (config/config.json)
The schema matches Python:
max_threads,max_header_size,max_body_sizekeep_alive_timeout,keep_alive_max_requestsheader_timeout,body_min_rate_bytes_per_sec,handler_timeoutserver: list of listeners (ip,port,queue_size,max_threads,SSL,host,cert_path,https-redirect,https-redirect-escape-paths,update-cert-state)
SSL entries enable in-process TLS termination (via rustls). Provide PEM-encoded cert_path and key_path (absolute or relative to BBWS_MAIN_PATH). Optional host entries let you attach SNI-specific certificates ([{ "host": "app.example.com", "cert_path": "...", "key_path": "..." }]). With https-redirect enabled, HTTP requests are redirected to HTTPS unless they match an escape path.
Timeouts & Metrics
header_timeoutcaps the time between the first byte of a request and the end of the headers. Exceeding it yields a408 Request Timeout.body_min_rate_bytes_per_secenforces a minimum upload rate (Slow Loris defense). When the moving average drops below the threshold the server aborts with408.handler_timeoutarms a watchdog per request. When it expires the server setsctx.is_cancelled()and ultimately responds with504 Gateway Timeout.
Use /_bbws/metrics for a built-in JSON view of timeouts.header, timeouts.body, and timeouts.handler counters so you can hook the runtime into monitoring without extra instrumentation.
TLS / HTTPS
Native TLS is built in via rustls. To serve HTTPS:
- Place your certificate chain and private key in PEM format (e.g.,
config/cert.pem,config/key.pem). - For each listener, set
"SSL": trueand pointcert_path/key_pathat those files:
{
"ip": "0.0.0.0",
"port": 443,
"SSL": true,
"cert_path": "config/cert.pem",
"key_path": "config/key.pem"
}
- (Optional) Add
hostentries to supply additional certificates via SNI. When the client SNI matches one of the hosts, that certificate is served; otherwise, the default certificate is used.
TLS listeners and plain HTTP listeners can coexist. Combine them with https-redirect to bounce cleartext traffic over to TLS automatically.
If you enable "update-cert-state": true on a TLS listener the server watches all referenced PEM files (default cert/key plus SNI entries) and hot-reloads them without a restart as soon as they change on disk.
Utilities & Files
load_file,load_bin_file,load_file_from_directory(with path clamping)set_cookie(ctx, key, value)addsSet-Cookieif the cookie doesn’t already existrender_page&substitute_varssupport simple templating (e.g.{{ ... }})PartialContent::new("/video.mp4", 80_000)andRedirect("/new")behave just like the Python helpers
Project layout:
rust-bbwebservice/
├── bbwebservice/
│ ├── Cargo.toml
│ └── src/
│ ├── config.rs
│ ├── logging.rs
│ ├── router.rs
│ ├── server.rs
│ └── utils/
└── testing/
├── Cargo.toml
└── src/
Status & Next Steps
- The public API remains 1:1 with the Python package, including
STORE_VARS, MIME/status constants, and helper functions. server_task()is currently a placeholder that only logs that scheduling is unimplemented.- Contributions are welcome (middleware, scheduling, tooling, etc.) - the architecture is intentionally modular.
Use this document as a quick reference to build services that behave exactly like the Python bbwebservice, including configuration, logging, and handler semantics.
Dependencies
~8–19MB
~314K SLoC