Skip to main content

Crate base_http1

Crate base_http1 

Source
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.
IncomingBody
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.
InterimWriter
Statically dispatched interim-response hook borrowing the output lane.
Options
Bounds apply before allocating or accepting an entire wire section.
RequestReader
Sequential request admission. Input read-ahead survives body completion and protocol switches. Dropped/failed partial reads prohibit further admission.
RequestWriter
Sequential client output. Drive this lane concurrently with ResponseReader so an upstream response can arrive before request production completes. No dialing, pooling, detached task or Expect/Continue wait policy is hidden.
ResponseReader
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.
ResponseWriter
The response lane. A partially sent or abandoned response permanently poisons admission. The owner must still await close to retire the backend.

Enums§

Error
An HTTP/1 failure. Variants wrapping a cause describe this layer and report the cause as their source.