feat(conn): streaming response bodies — RespBody::Stream + chunked TE (v0.3 chunk 1)
Design decisions (per handoff Q1 user answer + Q3 proposal): - Producer shape is PULL: the handler returns a smarm Receiver<Vec<u8>> (RespBody::Stream / StreamBody, From<Receiver<Vec<u8>>> for ergonomics); the producer is an actor the handler spawned. The conn actor pumps in pump_stream(): it keeps sole ownership of the socket and of write deadlines, and the recv() park between chunks is stoppable by the draining registry's request_stop (stop sentinel unwinds out of park_current; fd + registry guards clean up) — so an infinite stream is force-stoppable at the drain deadline like any in-flight request, with no polling. End of stream = every Sender dropped = terminating 0-chunk. Producer contract: a send() error means the conn died; exit. - Framing: HTTP/1.1 gets transfer-encoding: chunked and the connection stays reusable after the terminator (keep-alive after chunked). HTTP/1.0 has no chunked TE: bytes go raw, keep-alive is forced off, EOF delimits. User-set content-length/transfer-encoding headers are DROPPED for stream bodies — we own the framing, and CL+chunked is a smuggling vector. Empty producer chunks are skipped (a 0-length chunk would terminate the framing early). - request_timeout stays READ-phase only (unchanged). NEW Config/ConnLimits field write_timeout (default 30s) gives every response write a per-write budget: the fixed head+body write, each streamed chunk, and the error paths (413/100-continue/4xx) all go through the now deadline-bounded write_all (wait_writable_timeout, mirroring read_some). Each chunk gets a FRESH budget — streams may outlive any whole-response clock; a single stalled write may not (write-side slowloris). Naming/default were flagged as a user call in the handoff: veto here if write_timeout(30s) isn't it. - RespBody loses derive(Clone) (Receiver isn't Clone; Clone was unused) and gets a manual Debug. Tests: 3 serialiser unit tests (chunked head shape, user-framing-header stripping, 1.0 fallback) + 5 integration (chunked round-trip with decoder, keep-alive after chunked, 1.0 EOF-delimited, shutdown force-stops an infinite stream at drain deadline, stalled reader killed at write_timeout with producer observing the closed channel).
This commit is contained in:
+1
-1
@@ -28,7 +28,7 @@ pub mod conn_registry;
|
||||
pub mod serve;
|
||||
|
||||
// Re-exports — what most users want at the crate root.
|
||||
pub use conn::{Assigns, Body, Conn, HeaderMap, HttpVersion, Method, Params, RespBody};
|
||||
pub use conn::{Assigns, Body, Conn, HeaderMap, HttpVersion, Method, Params, RespBody, StreamBody};
|
||||
pub use plug::{Next, Pipeline, Plug};
|
||||
pub use router::Router;
|
||||
pub use serve::{
|
||||
|
||||
Reference in New Issue
Block a user