Expand description
HTTP/1 framing over independently owned scheduler I/O lanes. No runtime, tasks or transport ownership are hidden inside this crate.
§Base HTTP/1
An unpublished native HTTP/1 codec over published Base scheduler stream capabilities. This crate owns head and trailer syntax, framing, read-ahead, persistence and body lifecycle.
RequestReader<R>::read_request returns a Request<IncomingBody<'_, R>> and an Exchange. The body borrows the input lane. ResponseWriter<W> owns an independent output lane, sends interim responses and writes a generic Response<B> where B: ReadableBody. Returning the incoming body gives streaming echo without an extra task or dynamic dispatch.
Exchange retains immutable framing decisions: version, HEAD/CONNECT classification, persistence, Expect/Continue and, for server requests, any upgrade offers. The application owns RequestMetadata and its ordinary fields; protocol control fields have already been extracted. Its mutations cannot change the captured decisions. Use exchange.version() when constructing the interim writer; the earlier prototype’s Exchange::head() snapshot accessor has been removed.
The initial implementation supports HTTP/1.0 and HTTP/1.1 requests, fixed and chunked input, request trailers, fixed/chunked/close-delimited output, response trailers, HEAD/bodyless responses, interim heads, persistence, and managed 101/CONNECT duplex bodies. It rejects conflicting framing and enforces configurable head/field/chunk-line limits. An early final response permits reuse when the active upload subsequently completes; abandoned input disables reuse. Only chunked transfer coding is implemented; upgrade selection currently supports one unversioned token.
RequestWriter<W> and ResponseReader<R> provide independent client directions. Drive request output and response input concurrently, delivering interim heads through InterimResponses. The reader uses the matching request head for HEAD/CONNECT semantics and shares the native input body decoder. Request output supports fixed/chunked framing and trailers; response input also supports close-delimited bodies. HTTP/1.0 request bodies require a length. These primitives hide no dialing, pooling, task creation or Expect/Continue wait policy. Switch responses expose raw input and disable HTTP reuse; managed bidirectional client switch coordination remains future work.
A writer’s successful persistence result applies to its output lane only. Finish both directions, check input reuse, and join all exchange work before admitting another request. A complete early response must not automatically cancel a still-active upload. An error can cancel its sibling direction, but both must still be awaited. See the duplex experiment.
Bodies use base-http semantics. Request/response/body reads return owned BodyFrame events: Data { data, end }, Headers { fields, end }, or End. Stop after frame.is_end(). Incoming fixed-length data carries final completion; chunked trailers arrive in an owned final header frame. Initial message fields remain untouched; callers can forward frames directly or explicitly collect fields with HttpHeaders::append_trailers. Outgoing writers consume the end flag without another read and serialize header frames directly as trailers. ReadableBody::may_have_trailers() defaults to true and selects HTTP/1.1 chunked framing before reads, even with a known data length. Static bodies return false. Known lengths are validated with either fixed or chunked output. HTTP/1.0 cannot represent actual trailer frames.
The caller owns the socket: flush successful output, await both lane closures, drop the handles, then close the socket exclusively. A failed or dropped started operation prevents reuse. Cancellation is distinct from backend retirement. base-http-server implements this ownership sequence and bounded listener orchestration.
The codecs consume transport-neutral base_endpoint::stream::{ReadableStream, WritableStream} capabilities. Scheduler socket handles forward directly into these contracts. TLS handshakes and ALPN selection belong to endpoint and application orchestration; this crate processes plaintext only. The shared base-http-protocol layer constructs matching codec pairs after selection.
Run cargo test --locked and cargo clippy --locked --all-targets -- -D warnings. Deterministic tests cover fragmentation, partial writes and framing failures. Real HTTP and HTTPS integration tests live in the sibling base-http-server and base-http-client packages. Rust 1.87 is the declared minimum. Managed client tunnels, fuzzing and other runtime-backend validation remain follow-up work.
Content-Length is available as metadata.content_length, including on HEAD/304 responses. Host becomes request authority. Transfer-Encoding, Connection, standard connection controls, Connection-nominated fields and Upgrade are consumed by framing/exchange processing and excluded from application Fields. Single-token upgrade intent is represented by protocol; richer upgrade offers remain private exchange state. Outgoing metadata.persistent can request closure or HTTP/1.0 keep-alive. Raw outgoing control fields remain validated, including conflicts with typed values; generated wire controls do not mutate metadata.
Structs§
- Exchange
- Captured framing facts and, when input can still change, shared state. A successful switch changes incoming body reads to raw data without releasing transport.
- Incoming
Body - A pull body borrowing the connection’s input lane. Returning it as the response body provides streaming echo and managed duplex tunnels without boxing, queueing, spawning, or transferring socket ownership.
- Interim
Writer - Statically dispatched interim-response hook borrowing the output lane.
- Options
- Bounds apply before allocating or accepting an entire wire section.
- Request
Reader - Sequential request admission. Input read-ahead survives body completion and protocol switches. Dropped/failed partial reads prohibit further admission.
- Request
Writer - Sequential client output. Drive this lane concurrently with
ResponseReaderso an upstream response can arrive before request production completes. No dialing, pooling, detached task or Expect/Continue wait policy is hidden. - Response
Reader - Sequential client input sharing the native request body’s chunk decoder. The matching request head supplies HEAD/CONNECT semantics. This reader does not queue outstanding requests; the owner pairs each response in wire order. Switch responses expose raw input only; coordinating the outgoing switch and managed bidirectional client bodies is not implemented here.
- Response
Writer - The response lane. A partially sent or abandoned response permanently
poisons admission. The owner must still await
closeto retire the backend.
Enums§
- Error
- An HTTP/1 failure. Variants wrapping a cause describe this layer and report the cause as their source.