Monoio-based HTTP/1.1 and HTTP/2 server for Harrow.
This crate provides a high-performance HTTP server using io_uring. It supports HTTP/1.1 with keep-alive and chunked transfer encoding, and HTTP/2 with multiplexed streams.
Features
- io_uring-based I/O: Zero-copy where possible, minimal syscalls
- Cancellation Safety: Proper handling of io_uring operation cancellation
- Buffer Pooling: Reusable buffers to reduce allocator pressure
- HTTP/2 Support: Multiplexed streams with flow control
Architecture
┌─────────────────────────────────────────────┐
│ Server (lib.rs) │
└─────────────────────┬───────────────────────┘
│ TcpStream
▼
┌─────────────────────────────────────────────┐
│ Connection Handler │
│ (connection.rs) │
└─────────────────────┬───────────────────────┘
│
┌───────────┴───────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────────┐
│ H1 Handler │ │ H2 Handler │
│ (h1.rs) │ │ (h2.rs) │
└─────────────────┘ └─────────────────────┘
Example
fn main() {
let app = App::new().get("/hello", hello);
// High-level thread-per-core bootstrap.
harrow_server_monoio::run(app, "127.0.0.1:3000".parse().unwrap()).unwrap();
}
For advanced cases where you already own a monoio runtime, use the async
serve / serve_with_shutdown / serve_with_config entrypoints instead.
Cancellation Safety
This crate uses io_uring for async I/O. Unlike epoll-based runtimes, io_uring submits actual kernel operations. Dropping a Rust future does NOT automatically cancel the in-flight kernel operation.
This can lead to use-after-free (UAF) vulnerabilities:
- A read operation is submitted with a user buffer
- The future is dropped (e.g., due to timeout)
- The kernel writes to the buffer after it's been freed/reused
Mitigation
All I/O operations with timeout paths use CancelableAsyncReadRent and
explicitly cancel kernel operations before returning:
let canceller = new;
let handle = canceller.handle;
select!
See cancel.rs for the implementation details.