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.
27 lines
1.0 KiB
Rust
27 lines
1.0 KiB
Rust
//! WebSocket support (RFC 6455).
|
|
//!
|
|
//! v0.4 chunk 1: the upgrade handshake. A handler that wants to speak
|
|
//! WebSocket calls [`Conn::upgrade`](crate::Conn::upgrade); on a valid
|
|
//! handshake the connection actor writes the `101 Switching Protocols`
|
|
//! response and leaves the HTTP request loop. (Until the duplex wiring
|
|
//! lands — chunk 3 — leaving the loop closes the socket; the 101 itself
|
|
//! is correct and tested.)
|
|
//!
|
|
//! Dependency note: SHA-1 comes from `sha1_smol` (zero transitive deps),
|
|
//! spending urus dependency slot #3 — agreed in the v0.4 design pass over
|
|
//! vendoring. Base64 here is the 20-byte *encode* direction only and is
|
|
//! not cryptographic, so that stays in-tree (`handshake::b64`).
|
|
|
|
pub mod handshake;
|
|
|
|
pub use handshake::Rejection;
|
|
|
|
/// Marker carried on a [`Conn`](crate::Conn) whose handler accepted a
|
|
/// WebSocket upgrade. Opaque: chunk 3 grows this into the handler/duplex
|
|
/// handoff payload, so nothing outside the crate should depend on its
|
|
/// shape.
|
|
#[derive(Debug)]
|
|
pub struct WsUpgrade {
|
|
pub(crate) _priv: (),
|
|
}
|