Crates.io | servlin |
lib.rs | servlin |
version | 0.8.0 |
created_at | 2022-06-16 21:00:38.761586+00 |
updated_at | 2025-07-06 20:50:29.203237+00 |
description | Modular HTTP server library, threaded handlers and async performance |
homepage | |
repository | https://github.com/mleonhard/servlin |
max_upload_size | |
id | 607660 |
size | 378,232 |
A modular HTTP server library in Rust.
forbid(unsafe_code)
FnOnce(Request) -> Response + 'static + Clone + Send + Sync
chunked
transfer-encoding for request bodiesComplete 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 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)}))?)
}
fn handle_req(state: Arc<State>, req: Request) -> Result<Response, Error> {
match (req.method(), req.url().path.as_str()) {
("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();
Metric output format: x/y
x = unsafe code used by the build
y = total unsafe code found in the crate
Symbols:
🔒 = No `unsafe` usage found, declares #![forbid(unsafe_code)]
❓ = No `unsafe` usage found, missing #![forbid(unsafe_code)]
☢️ = `unsafe` usage found
Functions Expressions Impls Traits Methods Dependency
0/0 0/0 0/0 0/0 0/0 🔒 servlin 0.8.0
0/0 0/0 0/0 0/0 0/0 🔒 ├── async-fs 2.1.2
4/4 222/222 40/40 0/0 13/13 ☢️ │ ├── async-lock 3.4.0
0/0 2/2 0/0 0/0 0/0 ☢️ │ │ ├── event-listener-strategy 0.5.4
0/0 39/49 8/12 0/0 2/2 ☢️ │ │ │ ├── event-listener 5.4.0
0/0 183/183 2/2 0/0 1/1 ☢️ │ │ │ │ ├── concurrent-queue 2.5.0
4/4 12/75 4/16 0/0 0/3 ☢️ │ │ │ │ │ └── crossbeam-utils 0.8.21
0/0 0/0 0/0 0/0 0/0 🔒 │ │ │ │ ├── parking 2.2.1
0/0 11/191 0/0 0/0 2/2 ☢️ │ │ │ │ └── pin-project-lite 0.2.16
0/0 11/191 0/0 0/0 2/2 ☢️ │ │ │ └── pin-project-lite 0.2.16
0/0 39/49 8/12 0/0 2/2 ☢️ │ │ ├── event-listener 5.4.0
0/0 11/191 0/0 0/0 2/2 ☢️ │ │ └── pin-project-lite 0.2.16
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── blocking 1.6.2
0/0 0/0 0/0 0/0 0/0 🔒 │ │ ├── async-channel 2.5.0
0/0 183/183 2/2 0/0 1/1 ☢️ │ │ │ ├── concurrent-queue 2.5.0
0/0 2/2 0/0 0/0 0/0 ☢️ │ │ │ ├── event-listener-strategy 0.5.4
0/0 36/36 2/2 0/0 0/0 ☢️ │ │ │ ├── futures-core 0.3.31
0/0 11/191 0/0 0/0 2/2 ☢️ │ │ │ └── pin-project-lite 0.2.16
1/1 860/866 4/4 0/0 13/13 ☢️ │ │ ├── async-task 4.7.1
0/0 0/0 0/0 0/0 0/0 ❓ │ │ ├── futures-io 0.3.31
0/0 0/0 0/0 0/0 0/0 ❓ │ │ ├── futures-lite 2.6.0
0/0 0/0 0/0 0/0 0/0 🔒 │ │ │ ├── fastrand 2.3.0
0/0 36/36 2/2 0/0 0/0 ☢️ │ │ │ ├── futures-core 0.3.31
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ ├── futures-io 0.3.31
34/41 1700/2421 2/2 0/0 82/147 ☢️ │ │ │ ├── memchr 2.7.5
0/0 0/0 0/0 0/0 0/0 🔒 │ │ │ ├── parking 2.2.1
0/0 11/191 0/0 0/0 2/2 ☢️ │ │ │ └── pin-project-lite 0.2.16
0/0 28/28 2/2 0/0 0/0 ☢️ │ │ ├── piper 0.2.4
0/0 32/32 2/2 0/0 0/0 ☢️ │ │ │ ├── atomic-waker 1.1.2
0/0 0/0 0/0 0/0 0/0 🔒 │ │ │ ├── fastrand 2.3.0
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ └── futures-io 0.3.31
0/0 14/14 1/1 0/0 0/0 ☢️ │ │ └── tracing 0.1.41
0/0 11/191 0/0 0/0 2/2 ☢️ │ │ ├── pin-project-lite 0.2.16
0/0 98/98 5/5 0/0 2/2 ☢️ │ │ └── tracing-core 0.1.34
0/0 0/0 0/0 0/0 0/0 ❓ │ └── futures-lite 2.6.0
0/0 0/0 0/0 0/0 0/0 🔒 ├── async-net 2.0.0
0/0 72/118 19/22 1/1 5/9 ☢️ │ ├── async-io 2.4.1
4/4 222/222 40/40 0/0 13/13 ☢️ │ │ ├── async-lock 3.4.0
0/0 0/0 0/0 0/0 0/0 ❓ │ │ ├── cfg-if 1.0.1
0/0 183/183 2/2 0/0 1/1 ☢️ │ │ ├── concurrent-queue 2.5.0
0/0 0/0 0/0 0/0 0/0 ❓ │ │ ├── futures-io 0.3.31
0/0 0/0 0/0 0/0 0/0 ❓ │ │ ├── futures-lite 2.6.0
0/0 0/0 0/0 0/0 0/0 🔒 │ │ ├── parking 2.2.1
0/2 39/425 5/20 1/4 5/14 ☢️ │ │ ├── polling 3.8.0
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ ├── cfg-if 1.0.1
61/433 2727/7465 18/22 2/2 41/62 ☢️ │ │ │ ├── rustix 1.0.7
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ │ ├── bitflags 2.9.1
0/0 5/5 0/0 0/0 0/0 ☢️ │ │ │ │ │ └── serde 1.0.219
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ │ │ └── serde_derive 1.0.219
0/0 14/14 0/0 0/0 3/3 ☢️ │ │ │ │ │ ├── proc-macro2 1.0.95
0/0 4/4 0/0 0/0 0/0 ☢️ │ │ │ │ │ │ └── unicode-ident 1.0.18
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ │ │ ├── quote 1.0.40
0/0 14/14 0/0 0/0 3/3 ☢️ │ │ │ │ │ │ └── proc-macro2 1.0.95
0/0 88/88 3/3 0/0 2/2 ☢️ │ │ │ │ │ └── syn 2.0.104
0/0 14/14 0/0 0/0 3/3 ☢️ │ │ │ │ │ ├── proc-macro2 1.0.95
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ │ │ ├── quote 1.0.40
0/0 4/4 0/0 0/0 0/0 ☢️ │ │ │ │ │ └── unicode-ident 1.0.18
0/0 35/103 0/0 0/0 0/0 ☢️ │ │ │ │ ├── errno 0.3.13
1/90 10/679 0/2 0/0 5/92 ☢️ │ │ │ │ │ └── libc 0.2.174
1/90 10/679 0/2 0/0 5/92 ☢️ │ │ │ │ └── libc 0.2.174
0/0 14/14 1/1 0/0 0/0 ☢️ │ │ │ └── tracing 0.1.41
61/433 2727/7465 18/22 2/2 41/62 ☢️ │ │ ├── rustix 1.0.7
0/0 29/29 0/0 0/0 3/3 ☢️ │ │ ├── slab 0.4.10
0/0 5/5 0/0 0/0 0/0 ☢️ │ │ │ └── serde 1.0.219
0/0 14/14 1/1 0/0 0/0 ☢️ │ │ └── tracing 0.1.41
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── blocking 1.6.2
0/0 0/0 0/0 0/0 0/0 ❓ │ └── futures-lite 2.6.0
0/0 0/0 0/0 0/0 0/0 🔒 ├── fixed-buffer 1.0.2
0/0 0/0 0/0 0/0 0/0 ❓ │ └── futures-io 0.3.31
0/0 0/0 0/0 0/0 0/0 ❓ ├── futures-io 0.3.31
0/0 0/0 0/0 0/0 0/0 ❓ ├── futures-lite 2.6.0
0/0 0/0 0/0 0/0 0/0 ❓ ├── include_dir 0.7.4
0/0 0/0 0/0 0/0 0/0 ❓ │ └── include_dir_macros 0.7.4
0/0 14/14 0/0 0/0 3/3 ☢️ │ ├── proc-macro2 1.0.95
0/0 0/0 0/0 0/0 0/0 ❓ │ └── quote 1.0.40
0/0 0/0 0/0 0/0 0/0 🔒 ├── permit 0.2.1
0/0 12/32 0/0 0/0 0/0 ☢️ ├── rand 0.8.5
1/90 10/679 0/2 0/0 5/92 ☢️ │ ├── libc 0.2.174
0/0 2/2 0/0 0/0 0/0 ☢️ │ ├── rand_core 0.6.4
3/6 51/192 0/1 0/0 1/3 ☢️ │ │ ├── getrandom 0.2.16
0/0 0/0 0/0 0/0 0/0 ❓ │ │ │ ├── cfg-if 1.0.1
1/90 10/679 0/2 0/0 5/92 ☢️ │ │ │ └── libc 0.2.174
0/0 5/5 0/0 0/0 0/0 ☢️ │ │ └── serde 1.0.219
0/0 5/5 0/0 0/0 0/0 ☢️ │ └── serde 1.0.219
0/0 0/0 0/0 0/0 0/0 🔒 ├── safe-regex 0.3.0
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-regex-macro 0.3.0
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── safe-proc-macro2 1.0.95
0/0 0/0 0/0 0/0 0/0 🔒 │ │ └── unicode-xid 0.2.6
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-regex-compiler 0.3.0
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── safe-proc-macro2 1.0.95
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-quote 1.0.40
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-proc-macro2 1.0.95
0/0 0/0 0/0 0/0 0/0 🔒 ├── safina 0.7.0
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safina-macros 0.1.3
0/0 0/0 0/0 0/0 0/0 🔒 │ ├── safe-proc-macro2 1.0.95
0/0 0/0 0/0 0/0 0/0 🔒 │ └── safe-quote 1.0.40
0/0 5/5 0/0 0/0 0/0 ☢️ ├── serde 1.0.219
0/0 72/75 0/0 0/0 0/0 ☢️ ├── serde_json 1.0.140
0/0 8/8 0/0 0/0 0/0 ☢️ │ ├── itoa 1.0.15
34/41 1700/2421 2/2 0/0 82/147 ☢️ │ ├── memchr 2.7.5
7/9 572/702 0/0 0/0 2/2 ☢️ │ ├── ryu 1.0.20
0/0 5/5 0/0 0/0 0/0 ☢️ │ └── serde 1.0.219
0/0 0/0 0/0 0/0 0/0 🔒 ├── serde_urlencoded 0.7.1
0/0 2/2 0/0 0/0 0/0 ☢️ │ ├── form_urlencoded 1.2.1
0/0 8/8 0/0 0/0 0/0 ☢️ │ │ └── percent-encoding 2.3.1
0/0 8/8 0/0 0/0 0/0 ☢️ │ ├── itoa 1.0.15
7/9 572/702 0/0 0/0 2/2 ☢️ │ ├── ryu 1.0.20
0/0 5/5 0/0 0/0 0/0 ☢️ │ └── serde 1.0.219
0/0 0/0 0/0 0/0 0/0 🔒 ├── temp-dir 0.1.16
0/0 0/0 0/0 0/0 0/0 🔒 └── temp-file 0.1.9
115/590 6987/14168 117/158 4/7 182/373
See rust-webserver-comparison.md.
log_request_and_response
to log duration_ms
tag.Response::internal_server_errror_500
.Request::parse_url
].Response::too_many_requests_429
].Into<TagList>
for arrays.safina
v0.7.servlin::reexports
module.safina
v0.6.0.once_cell
.LogFileWriterBuilder
.From<Cow<'_, str>>
and From<&Path>
for TagValue
.Seek
for BodyReader
.Request::opt_json
.From<LoggerStoppedError>
for Error
.Response::json
to return Result<Response, Error>
.log_request_and_response
to return Result
.Response::unprocessable_entity_422
.Response::include_dir
redirects.Response::redirect_301
Response::include_dir
to redirect from /somedir
to /somedir/
so relative URLs will work.Response::include_dir
to take &Request
and look for index.html
in dirs.log_request_and_response
and 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()
print_log_response
and RequestBody::length_is_known
RequestBody::len
and is_empty
to return Option
.EventSender::unconnected
.rust-webserver-comparison.md
License: MIT OR Apache-2.0