Design (as agreed in the v0.4 pass): - Dep #3 spent: sha1_smol 1.0.1 (zero transitive deps) instead of a vendored SHA-1 — user call: no hand-rolled crypto. Consequence noted in ROADMAP: the v0.6 wire-format JSON question now costs dep #4. - Base64 stays in-tree but ENCODE-ONLY (RFC 4648 vectors tested): it is an encoding, not crypto, and the decode direction (where parsing bugs live) is deliberately not implemented. - src/ws/{mod,handshake}.rs: validate() implements §4.2.1 (GET, 1.1, Host, upgrade/connection token lists case-insensitively, key shape = base64 of exactly 16 bytes, version 13). Version mismatch -> 426 + sec-websocket-version: 13 (§4.2.2); everything else -> 400. Rejected upgrades stay plain HTTP with keep-alive intact (tested: 400 then 101 on the same connection). - Conn grows pub upgrade: Option<WsUpgrade> (opaque marker; chunk 3 turns it into the duplex/handler handoff payload — shape deliberately uncommitted while the handler API is open). Conn::upgrade(self) is the commit point: 101 + accept key + marker + halt, or the rejection. - conn_actor: upgrade marker + status 101 -> write head, leave the HTTP loop. Until chunk 3 that drops the fd (clients see 101 then EOF); status check is defensive against a post-handler plug clobbering 101. - serialise_response: 1xx no longer get content-length injected (RFC 7230 §3.3.2). 204 left alone on purpose — separate conversation. Accept-key path pinned to the §1.3 worked example end-to-end (unit + wire). Suite: 34 unit + 33 integration + 2 doc.
40 lines
1.2 KiB
Rust
40 lines
1.2 KiB
Rust
//! # urus — a cowboy/bandit-style HTTP library for the smarm actor runtime.
|
|
//!
|
|
//! v1 covers HTTP/1.1, the plug pipeline, and a built-in router. See
|
|
//! `urus-spec.md` for the design.
|
|
//!
|
|
//! ```no_run
|
|
//! use urus::{Pipeline, Router, Conn, Next, serve};
|
|
//!
|
|
//! let pipeline = Pipeline::new().plug(
|
|
//! Router::new()
|
|
//! .get("/", |c: Conn, _n: Next| c.put_status(200).put_body("hello"))
|
|
//! .get("/users/:id", |c: Conn, _n: Next| {
|
|
//! let id = c.params.get("id").unwrap_or("").to_string();
|
|
//! c.put_status(200).put_body(id)
|
|
//! })
|
|
//! );
|
|
//!
|
|
//! serve("0.0.0.0:8080", pipeline).unwrap();
|
|
//! ```
|
|
|
|
pub mod conn;
|
|
pub mod plug;
|
|
pub mod router;
|
|
pub mod parser;
|
|
pub mod net;
|
|
pub mod conn_actor;
|
|
pub mod conn_registry;
|
|
pub mod serve;
|
|
pub mod sse;
|
|
pub mod ws;
|
|
|
|
// Re-exports — what most users want at the crate root.
|
|
pub use conn::{Assigns, Body, Conn, HeaderMap, HttpVersion, Method, Params, RespBody, StreamBody};
|
|
pub use plug::{Next, Pipeline, Plug};
|
|
pub use router::Router;
|
|
pub use sse::{EventSender, SseClosed};
|
|
pub use serve::{
|
|
serve, serve_with, serve_with_shutdown, shutdown_handle, Config, Handle, ShutdownSignal,
|
|
};
|