10 个重大版本
0.10.0 | 2021年6月4日 |
---|---|
0.9.0 | 2021年2月18日 |
0.8.0 | 2021年2月2日 |
0.5.0 | 2020年11月20日 |
#1246 in 解析器实现
在 zc 中使用
255KB
5.5K SLoC
rust-dangerous
Rust 库,用于安全且明确地处理不受信任的(即 dangerous
)数据
文档托管在 docs.rs。
dangerous = "0.10"
目标
- 快速解析。
- 快速编译。
- 无 panic [1]。
- 零成本抽象。
- 最小依赖 [2]。
- 重试/流协议支持。
no-std
/ 适用于嵌入式。- 在成功路径上无堆分配 [3]。
- 支持原始类型。
- 可选详细错误。
- 尽可能使用 SIMD 优化。
[1] 由于 OOM 而导致的 panic 不在范围之内。如果这令人担忧,请禁用堆分配。
[2] 当同时禁用 unicode
和 simd
功能时,零依赖。
[3] 当禁用 full-backtrace
功能时,无堆分配。
此库的目的是提供一个简单的接口,用于安全地显式解析不受信任的数据。dangerous
在解析二进制或简单的文本数据格式和协议方面非常出色。它不是一个像 serde
提供的序列化库,但你可以使用 dangerous
编写一个解析器,该解析器可以在反序列化程序中使用。
panic 和未处理/未确认的数据是此库试图防止的两个常见错误。包括一个可选的、但很可靠的调试接口,具有合理的输入格式和有用的错误信息,以便在生产之前或之后排除问题。
用法
fn decode_message<'i, E>(r: &mut BytesReader<'i, E>) -> Result<Message<'i>, E>
where
E: Error<'i>,
{
r.context("message", |r| {
// Expect version 1
r.context("version", |r| r.consume(0x01))?;
// Read the body length
let body_len = r.context("body len", |r| r.read_u8())?;
// Take the body input
let body = r.context("body", |r| {
let body_input = r.take(body_len as usize)?;
// Decode the body input as a UTF-8 str
body_input.to_dangerous_str()
})?;
// We did it!
Ok(Message { body })
})
}
let input = dangerous::input(/* data */);
let result: Result<_, Invalid> = input.read_all(decode_message);
错误
对于协议的自定义错误通常不会提供关于为什么以及在哪里发生特定问题的上下文。传递像 core::str::Utf8Error
这样简单的错误可能足以在开发时进行调试,然而,如果只是写入日志而没有输入/上下文,通常会成为噪音。在这个阶段,你几乎更好的选择是一个简单的输入错误。
对于任何简单的递归下降解析器,这个问题会加剧,因为子切片的上下文会丢失,这使得将任何错误偏移量传递回根时无用的。通过捕获错误周围和上方的上下文,dangerous
修复了这个问题。
你曾尝试从这个类似的东西反向工作吗?
[ERRO]: ahhh!: Utf8Error { valid_up_to: 2, error_len: Some(1) }
这会更好吗?
[ERRO]: ahhh!: error reading message: error attempting to convert input into string: expected utf-8 code point
> [01 05 68 65 ff 6c 6f]
^^
additional:
error offset: 4, input length: 7
backtrace:
1. `read all input`
2. `<context>` (expected message)
3. `<context>` (expected body)
4. `convert input into string` (expected utf-8 code point)
灵感
此项目最初受到 untrusted 的启发。
依赖
~0–1MB
~16K SLoC