5 个版本

0.2.0 2022年7月24日
0.2.0-alpha12022年7月17日
0.1.1 2022年7月15日
0.1.0 2022年7月15日

#4 in #request-handler

Apache-2.0

52KB
834 代码行,不包括注释

Crates.io docs.rs Crates.io

unit-rs

unit-rs 是围绕来自 NGINX Unit 的 C 库 libunit.a 的安全包装,允许在 Rust 中创建 Unit 应用程序。

示例

unit-rs 添加为依赖项

[dependencies]
unit-rs = "0.2"

并将以下内容添加到 src/main.rs

use unit_rs::{Unit, Request};

fn main() {
    let mut unit = Unit::new().unwrap();

    unit.set_request_handler(|req: Request<'_>| {
        let headers = &[("Content-Type", "text/plain")];
        let body = "Hello world!\n";
        req.send_response(200, headers, body)?;

        Ok(())
    });

    unit.run();
}

一旦编译完成,运行中的 NGINX Unit 服务器可以配置为使用它,通过指向二进制文件的路径的外部应用程序

{
  "listeners": {
      "*:8080": {
          "pass": "applications/rustapp"
      }
  },
  "applications": {
      "rustapp": {
          "type": "external",
          "working_directory": "/path/to/package",
          "executable": "/path/to/package/hello_world",
          "processes": 4
      }
  }
}

有关更详细的示例,请参阅 examples/request_info.rs,以及 deploy.sh 脚本中的示例 curl 命令。

功能

目前并非所有功能都受支持,但已有足够的功能来检查请求的所有方面并创建响应。

此库还可以通过创建额外的 Unit 对象实例来实现多线程。

当启用 http 功能时,可以使用来自 http 包的类型来编写处理程序,使用 http::HttpHandler 适配器。

缺失的功能

尚未实现 WebSocket 支持。

在 Unit 缓存整个请求体之前检查请求头(并可能关闭请求)的回调尚未提供。

目前没有执行请求异步处理的方法。具有昂贵计算或阻塞 I/O 的处理程序将阻塞整个线程上下文。

具有非 UTF8 路径或其头字段中包含非 UTF8 的请求将导致请求处理程序崩溃。

当单个线程崩溃时,无法优雅地取消其他 Unit 线程。这可以通过使用多个进程而不是线程来缓解。

构建

为了构建,库需要 libclang(由 bindgen 需要)和 unit-dev(提供 libunit.a 及其头文件)。

大多数发行版都将有 libclang-dev 软件包(或类似),而 unit-dev 必须从 Unit 的自身仓库安装,这些仓库链接在他们的 安装指南 中。

请注意,NGINX Unit要求服务器和应用程序使用相同版本;使用旧版或新版本的NGINX Unit编译的libunit的应用程序将无法工作。

安全性

unit-rs试图通过使所有无效的libunit API使用变得不可能,并防止所有未定义的行为,来成为一个安全的包装器。

为此,有些性能是牺牲的,使用了Rust对所有数组进行的强制边界检查。

例如,使用unit-rs的应用程序在以下情况下将遇到运行时崩溃:

  • 从请求中读取的字节数多于可用的字节数
  • 向响应写入的字节数多于分配的字节数

但是,Rust的类型系统也允许许多编译时保证。在使用unit-rs时,以下情况将成为编译时错误或无法表达:

  • 移动Unit上下文或在线程之间共享请求数据
  • 访问比可用的字段/头更多的字段
  • 将请求数据指针存储在超过请求处理函数生命周期的变量中
  • 将指向或进入共享内存缓冲区的指针存储在超过缓冲区生命周期的变量中
  • 发送已经发送过的共享内存缓冲区
  • 发送未初始化的共享内存区域
  • 忘记释放共享内存缓冲区

通过使用全局互斥锁,unit-rs还将确保所有额外的多线程Unit上下文都是从主上下文中派生的,并且主上下文的生命周期比所有次要上下文长。

基准测试

使用wrk基准测试工具在Ryzen 7 CPU上进行的一次测试表明,Unit达到每秒约250000个请求,主要是由于Unit服务器和wrk工具本身达到最大。

相比之下,一个经典的Nginx服务器在服务静态文件时达到每秒约200000个请求(尽管请注意,经典Nginx具有许多更多功能)。

依赖关系

~0.5–2.5MB
~46K SLoC