Expand description
Servlin
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
chunkedtransfer-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 serde::Deserialize;
use serde_json::json;
use servlin::{
socket_addr_127_0_0_1,
Error,
HttpServerBuilder,
Request,
Response
};
use servlin::log::log_request_and_response;
use servlin::reexport::{safina_executor, safina_timer};
use std::sync::Arc;
use temp_dir::TempDir;
struct State {}
fn hello(_state: Arc<State>, req: Request) -> Result<Response, Error> {
#[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, Error> {
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| {
log_request_and_response(req, |req| handle_req(state, req)).unwrap()
};
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(8271))
.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.4.0
- Changed
Response::jsonto returnResult<Response, Error>. - Changed
log_request_and_responseto returnResult. - Added
Response::unprocessable_entity_422.
- Changed
- v0.3.2 - Fix bug in
Response::include_dirredirects. - v0.3.1
- Add
Response::redirect_301 Response::include_dirto redirect from/somedirto/somedir/so relative URLs will work.
- Add
- v0.3.0 - Changed
Response::include_dirto take&Requestand look forindex.htmlin dirs. - v0.2.0
- Added:
log_request_and_responseand other logging toolingResponse::ok_200()Response::unauthorized_401()Response::forbidden_403()Response::internal_server_errror_500()Response::not_implemented_501()Response::service_unavailable_503()EventSender::is_connected()PORT_env()
- Removed
print_log_responseandRequestBody::length_is_known - Changed
RequestBody::lenandis_emptyto returnOption. - Bugfixes
- Added:
- v0.1.1 - Add
EventSender::unconnected. - v0.1.0 - Rename library to Servlin.
TO DO
- Fix limitations above
- Support HEAD responses that have Content-Length set and no body.
- Update
rust-webserver-comparison.md- Add missing data
- Add other servers from https://www.arewewebyet.org/topics/frameworks/
- Rearrange
- Generate geiger reports for each web server
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
Stringthat contains only US-ASCII chars. - Builds an HTTP server.
Enums
- Struct returned by
RequestBody::async_readerandResponseBody::async_reader. - Struct returned by
RequestBody::readerandResponseBody::reader.
Functions
- Reads and parses the
PORTenvironment variable.