5个不稳定版本

0.3.2 2022年6月16日
0.3.1 2022年6月11日
0.3.0 2022年6月9日
0.2.0 2022年4月26日
0.1.0 2022年4月26日

#837 in HTTP服务器

每月 22 次下载

MIT/Apache

145KB
3K SLoC

注意:此库已被重命名为 Servlin

Beatrice

Rust的一个模块化HTTP服务器库。

功能

  • forbid(unsafe_code)
  • 线程化请求处理器
    FnOnce(Request) ->Response+ 'static + Clone + Send + Sync
  • 内部使用异步代码,在负载下表现优异
  • JSON
  • 服务器端事件(SSE)
  • 将大型请求体保存到临时文件
  • 发送100-Continue
  • 限制线程和连接数
  • 模块化:自定义日志记录、编写内部方法的自定义版本等。
  • 没有宏或复杂的类型参数
  • 良好的测试覆盖率(63%)

限制

  • 新项目,尚未在生产环境中证明。
  • 待办事项
    • 请求超时
    • chunked 转发编码的请求体
    • gzip
    • brotli
    • TLS
    • 通过ACME自动获取TLS证书
    • 当接近连接限制时,丢弃空闲连接。
    • 拒绝服务缓解:源节流,最小吞吐量
    • 完整的功能测试套件
    • 缺少负载测试
    • 磁盘空间使用限制

示例

完整示例: examples/

简单示例

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 安全报告


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      🔒  beatrice 0.3.2
0/0        4/4          0/0    0/0     2/2      ☢️  ├── async-fs 1.5.0
0/0        51/51        14/14  0/0     0/0      ☢️  │   ├── async-lock 2.5.0
0/0        106/116      4/8    0/0     0/0      ☢️  │   │   └── event-listener 2.5.2
0/0        28/28        4/4    0/0     0/0      ☢️  │   ├── blocking 1.2.0
0/0        0/0          0/0    0/0     0/0      🔒  │   │   ├── async-channel 1.6.1
0/0        155/155      2/2    0/0     1/1      ☢️  │   │   │   ├── concurrent-queue 1.2.2
0/0        0/0          0/0    0/0     0/0      🔒  │   │   │   │   └── cache-padded 1.2.0
0/0        106/116      4/8    0/0     0/0      ☢️  │   │   │   ├── event-listener 2.5.2
0/0        30/30        2/2    0/0     0/0      ☢️  │   │   │   └── futures-core 0.3.21
1/1        802/802      4/4    0/0     10/10    ☢️  │   │   ├── async-task 4.2.0
0/0        26/26        2/2    0/0     0/0      ☢️  │   │   ├── atomic-waker 1.0.0
0/0        0/0          0/0    0/0     0/0      🔒  │   │   ├── fastrand 1.7.0
0/0        0/0          0/0    0/0     0/0      ❓  │   │   ├── futures-lite 1.12.0
0/0        0/0          0/0    0/0     0/0      🔒  │   │   │   ├── fastrand 1.7.0
0/0        30/30        2/2    0/0     0/0      ☢️  │   │   │   ├── futures-core 0.3.21
0/0        0/0          0/0    0/0     0/0      ❓  │   │   │   ├── futures-io 0.3.21
36/37      2067/2144    0/0    0/0     21/21    ☢️  │   │   │   ├── memchr 2.5.0
1/21       10/368       0/2    0/0     5/40     ☢️  │   │   │   │   └── libc 0.2.126
0/0        0/0          0/0    0/0     0/0      🔒  │   │   │   ├── parking 2.0.0
0/0        11/165       0/0    0/0     2/2      ☢️  │   │   │   ├── pin-project-lite 0.2.9
0/0        21/21        0/0    0/0     4/4      ☢️  │   │   │   └── waker-fn 1.1.0
1/1        75/117       4/6    0/0     2/3      ☢️  │   │   └── once_cell 1.12.0
0/0        0/0          0/0    0/0     0/0      ❓  │   └── futures-lite 1.12.0
0/0        0/0          0/0    0/0     0/0      🔒  ├── async-net 1.6.1
0/0        22/22        0/0    0/0     0/0      ☢️  │   ├── async-io 1.7.0
0/0        155/155      2/2    0/0     1/1      ☢️  │   │   ├── concurrent-queue 1.2.2
0/0        0/0          0/0    0/0     0/0      ❓  │   │   ├── futures-lite 1.12.0
1/21       10/368       0/2    0/0     5/40     ☢️  │   │   ├── libc 0.2.126
1/1        16/18        1/1    0/0     0/0      ☢️  │   │   ├── log 0.4.17
0/0        0/0          0/0    0/0     0/0      ❓  │   │   │   ├── cfg-if 1.0.0
0/0        5/5          0/0    0/0     0/0      ☢️  │   │   │   └── serde 1.0.137
0/0        0/0          0/0    0/0     0/0      ❓  │   │   │       └── serde_derive 1.0.137
0/0        12/12        0/0    0/0     3/3      ☢️  │   │   │           ├── proc-macro2 1.0.39
0/0        4/4          0/0    0/0     0/0      ☢️  │   │   │           │   └── unicode-ident 1.0.0
0/0        0/0          0/0    0/0     0/0      ❓  │   │   │           ├── quote 1.0.18
0/0        12/12        0/0    0/0     3/3      ☢️  │   │   │           │   └── proc-macro2 1.0.39
0/0        50/50        3/3    0/0     2/2      ☢️  │   │   │           └── syn 1.0.96
0/0        12/12        0/0    0/0     3/3      ☢️  │   │   │               ├── proc-macro2 1.0.39
0/0        0/0          0/0    0/0     0/0      ❓  │   │   │               ├── quote 1.0.18
0/0        4/4          0/0    0/0     0/0      ☢️  │   │   │               └── unicode-ident 1.0.0
1/1        75/117       4/6    0/0     2/3      ☢️  │   │   ├── once_cell 1.12.0
0/0        0/0          0/0    0/0     0/0      🔒  │   │   ├── parking 2.0.0
0/0        0/9          1/6    0/0     0/0      ☢️  │   │   ├── polling 2.2.0
0/0        0/0          0/0    0/0     0/0      ❓  │   │   │   ├── cfg-if 1.0.0
1/21       10/368       0/2    0/0     5/40     ☢️  │   │   │   ├── libc 0.2.126
1/1        16/18        1/1    0/0     0/0      ☢️  │   │   │   └── log 0.4.17
0/0        24/24        0/0    0/0     3/3      ☢️  │   │   ├── slab 0.4.6
0/0        5/5          0/0    0/0     0/0      ☢️  │   │   │   └── serde 1.0.137
3/6        528/641      2/4    0/0     3/4      ☢️  │   │   ├── socket2 0.4.4
1/21       10/368       0/2    0/0     5/40     ☢️  │   │   │   └── libc 0.2.126
0/0        21/21        0/0    0/0     4/4      ☢️  │   │   └── waker-fn 1.1.0
0/0        28/28        4/4    0/0     0/0      ☢️  │   ├── blocking 1.2.0
0/0        0/0          0/0    0/0     0/0      ❓  │   └── futures-lite 1.12.0
0/0        0/0          0/0    0/0     0/0      🔒  ├── fixed-buffer 0.5.0
0/0        0/0          0/0    0/0     0/0      ❓  │   └── futures-io 0.3.21
0/0        0/0          0/0    0/0     0/0      ❓  ├── futures-io 0.3.21
0/0        0/0          0/0    0/0     0/0      ❓  ├── futures-lite 1.12.0
0/0        0/0          0/0    0/0     0/0      ❓  ├── include_dir 0.7.2
0/0        0/0          0/0    0/0     0/0      ❓  │   └── include_dir_macros 0.7.2
0/0        12/12        0/0    0/0     3/3      ☢️  │       ├── proc-macro2 1.0.39
0/0        0/0          0/0    0/0     0/0      ❓  │       └── quote 1.0.18
0/0        0/0          0/0    0/0     0/0      🔒  ├── permit 0.1.4
0/0        0/0          0/0    0/0     0/0      🔒  ├── safe-regex 0.2.5
0/0        0/0          0/0    0/0     0/0      🔒  │   └── safe-regex-macro 0.2.5
0/0        0/0          0/0    0/0     0/0      🔒  │       ├── safe-proc-macro2 1.0.36
0/0        0/0          0/0    0/0     0/0      🔒  │       │   └── unicode-xid 0.2.3
0/0        0/0          0/0    0/0     0/0      🔒  │       └── safe-regex-compiler 0.2.5
0/0        0/0          0/0    0/0     0/0      🔒  │           ├── safe-proc-macro2 1.0.36
0/0        0/0          0/0    0/0     0/0      🔒  │           └── safe-quote 1.0.15
0/0        0/0          0/0    0/0     0/0      🔒  │               └── safe-proc-macro2 1.0.36
0/0        0/0          0/0    0/0     0/0      🔒  ├── safina-executor 0.3.3
0/0        0/0          0/0    0/0     0/0      🔒  │   ├── safina-sync 0.2.4
0/0        0/0          0/0    0/0     0/0      🔒  │   └── safina-threadpool 0.2.4
0/0        0/0          0/0    0/0     0/0      🔒  ├── safina-sync 0.2.4
0/0        0/0          0/0    0/0     0/0      🔒  ├── safina-timer 0.1.11
1/1        75/117       4/6    0/0     2/3      ☢️  │   └── once_cell 1.12.0
0/0        5/5          0/0    0/0     0/0      ☢️  ├── serde 1.0.137
0/0        4/7          0/0    0/0     0/0      ☢️  ├── serde_json 1.0.81
0/0        7/7          0/0    0/0     0/0      ☢️  │   ├── itoa 1.0.2
7/9        587/723      0/0    0/0     2/2      ☢️  │   ├── ryu 1.0.10
0/0        5/5          0/0    0/0     0/0      ☢️  │   └── serde 1.0.137
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.0.1
0/0        0/0          0/0    0/0     0/0      ❓  │   │   ├── matches 0.1.9
0/0        3/3          0/0    0/0     0/0      ☢️  │   │   └── percent-encoding 2.1.0
0/0        7/7          0/0    0/0     0/0      ☢️  │   ├── itoa 1.0.2
7/9        587/723      0/0    0/0     2/2      ☢️  │   ├── ryu 1.0.10
0/0        5/5          0/0    0/0     0/0      ☢️  │   └── serde 1.0.137
0/0        0/0          0/0    0/0     0/0      🔒  ├── temp-dir 0.1.11
0/0        0/0          0/0    0/0     0/0      🔒  ├── temp-file 0.1.7
0/0        0/0          0/0    0/0     0/0      ❓  └── url 2.2.2
0/0        2/2          0/0    0/0     0/0      ☢️      ├── form_urlencoded 1.0.1
0/0        0/0          0/0    0/0     0/0      ❓      ├── idna 0.2.3
0/0        0/0          0/0    0/0     0/0      ❓      │   ├── matches 0.1.9
0/0        0/0          0/0    0/0     0/0      🔒      │   ├── unicode-bidi 0.3.8
0/0        5/5          0/0    0/0     0/0      ☢️      │   │   └── serde 1.0.137
0/0        20/20        0/0    0/0     0/0      ☢️      │   └── unicode-normalization 0.1.19
0/0        0/0          0/0    0/0     0/0      🔒      │       └── tinyvec 1.6.0
0/0        5/5          0/0    0/0     0/0      ☢️      │           ├── serde 1.0.137
0/0        0/0          0/0    0/0     0/0      ❓      │           └── tinyvec_macros 0.1.0
0/0        0/0          0/0    0/0     0/0      ❓      ├── matches 0.1.9
0/0        3/3          0/0    0/0     0/0      ☢️      ├── percent-encoding 2.1.0
0/0        5/5          0/0    0/0     0/0      ☢️      └── serde 1.0.137

50/76      4670/5574    43/58  0/0     60/97  

替代方案

请参阅 rust-webserver-comparison.md

变更日志

  • v0.3.2 - 将项目重命名为 'servlin'
  • v0.3.1 - 添加 Response::include_dir
  • v0.3.0
    • 添加 RequestBody::StaticBytes
    • 添加 ResponseBody::StaticBytes
    • RequestBodyResponseBody 中移除 impl From<&[u8]>
  • v0.2.0 - 使 print_log_response 更易于使用。
  • v0.1.0 - 首次发布版本

待办事项

  • 修复上述限制
  • 支持设置了 Content-Length 而没有体(body)的 HEAD 响应。
  • 更新 rust-webserver-comparison.md

许可:MIT OR Apache-2.0

依赖项

~5–18MB
~226K SLoC