http-net 0.10.0

Sans-IO HTTP/1.1 server and client: strict RFC 9112 parsing, smuggling defences, bounded buffers, keep-alive, chunked bodies, upgrades, a blocking std adapter, no third-party dependencies.
Documentation
# http-net v0.10.0 - Beta

**Date:** 2026-11-12
**Compare:** `v0.9.2...v0.10.0`

**The simplicity audit and the third review, before 1.0.** The public
API was checked once more for one-line common uses with plain `?`, names a
newcomer can read, and one way to do each thing; five places fell short and
are fixed with four signature changes, each a compile error at the line to
change. An independent review of 0.9.2 found no defect in the parser or
framing core; what it found at the proxy and adapter edges is fixed here
too. `docs/MIGRATION.md` shows every change.

## What is http-net?

An HTTP/1.1 engine that does no I/O. Feed it the bytes a socket delivered;
it hands back requests or responses as borrowed views of those bytes,
decodes their bodies, and serializes what you send back. Parsing is strict:
a message two implementations could frame differently is refused with a
specific error, never repaired. Every buffer is bounded by configuration,
and each limit is checked before the bytes it governs are buffered.

## Changed

- **`parse_response_head` takes the request's `Method`.** The `Asked`
  struct is gone: pass `Method::Head`, `Method::Connect`, or the method
  the request had (`Asked::default()` becomes `Method::Get`).
- **`RequestHead::copy_into` returns `HeadFacts`.** It returned a
  `Result` that was never an error; drop the `?`.
- **`blocking::Connection::new(stream)`** takes only the socket. Set
  limits with the new `with_limits`, as on every other constructor.
- **The blocking time setters take a `Duration`** or `None`:
  `ServerConfig::with_read_timeout(Duration::from_secs(5))`, with no
  `Some`. `Some(..)` still compiles. The setters are no longer `const fn`.

- **`Request::forward_from` writes `host`** from the authority the proxy
  read (the absolute-form target's, else the `Host` field's) and never
  copies the received one (RFC 9112 section 3.2.2), so the next hop sees
  the authority that was checked. It drops `proxy-authorization`, which is
  the proxy's own credential.
- **Incoming trailers drop `content-length`, `transfer-encoding`, and
  `host`** (RFC 9110 section 6.5.1), so nothing downstream merges or
  relays them.
- **`Debug` redacts more:** fields whose names mark a credential
  (`x-api-key`, `x-auth-token`, `x-session-id`, and the like) and a request
  target's query.
- **`parse-net` is pinned** to `=0.7.0`: its grammar decides what is
  accepted on the wire, so it changes only with an http-net release.

## Fixed

- **`forward_from` is linear.** It read every `Connection` option for
  every field, so one request the default limits accept could cost
  milliseconds of CPU to forward. The options are read once now.
- **Wiping covers buffer growth.** With `set_wipe(true)`, a growing input
  buffer freed its old block without zeroing it.

## Added

- **`?` from `HttpError` into `std::io::Error`** (feature `std`), so a
  driver that returns `io::Result` needs no `map_err`. Running out of input
  is `UnexpectedEof`, a caller mistake is `InvalidInput`, anything the peer
  sent is `InvalidData`; the `HttpError` stays readable inside.
- **`end_to_end_headers`** on `RequestHead` and `ResponseHead`: the fields
  a proxy forwards, in linear time.
- **`ClientConn::set_wipe`**, as on `ServerConn`.
- **`OwnedRequestHead::wipe`**: an owned head kept past the connection is
  dropped with its bytes zeroed, spare capacity included (a vector reused
  through `copy_into` can hold an earlier, longer head there).

## Documentation

- The blocking server is for local, development, and trusted-network use;
  internet-facing servers drive `ServerConn` from an event loop with
  per-peer limits.
- `ServerConn` lists which call writes what.

## Testing

All tests and doctests pass (`cargo test --all-features`). Each fix has a
regression test that failed before it: the forwarding cost against
thousands of `Connection` options and against eight times the fields
(`tests/linearity.rs`), `host` and `proxy-authorization` on the forwarded
request and a conformance row for RFC 9112 section 3.2.2, an allocator
that inspects every freed block for the credential (`tests/wipe_growth.rs`),
trailer filtering on both sides, and the wider redaction. Every fuzz
target ran 15 minutes on this code with no finding.

## Performance

No hot path changed. Interleaved against 0.9.2, nine rounds a run, five
runs: the median change of every benchmark across the runs is under the 5%
gate (between -4% and +5%). The machine was heavily loaded, so single runs
moved up to 15% either way, in both directions on the same benchmark.

## Stability

The API stays the 1.0 candidate, now in this simpler form. 1.0.0 needs two
weeks with no API change, counted from this release, so it ships at the
earliest on 2026-11-26, on James's decision. The MSRV is Rust 1.85.

## Installation

```toml
[dependencies]
http-net = "0.10"
```

MSRV: Rust 1.85.

**Full Changelog:** https://github.com/jamesgober/http-net/compare/v0.9.2...v0.10.0