Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / fuzz / seeds / h1-request / uri-escapes.http
Author[]Andy Green <andy@warmcat.com> 2026-10-05 20:22 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-10-06 03:36 UTC
Treec13716bb66d52e3899f944bd81830cb28655d5d8   Raw Patch
 
docs: port plan: phase 1f is done
docs: port plan: phase 1f is done

What permessage-deflate is, how it is tested, where it differs from C,
and what is not done yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019kg5Eemy68ZaqDBcUJQG6J
diff --git a/docs/port-plan.md b/docs/port-plan.md index 9b01da2..7db59e5 100644 --- a/docs/port-plan.md +++ b/docs/port-plan.md @@ -793,6 +793,62 @@ application's message goes as one final frame. - The fuzz target is seeded from `fuzz/fuzz-ws-pmd/seeds`, which includes `bomb-2mb-zeros`. +**Done (2026-10-05)**, behind npro-ws's `pmd` feature, with `miniz_oxide` +and `adler2` admitted as [dependencies.md](dependencies.md) has them. +`npro_ws::pmd` negotiates: a server takes the first `permessage-deflate` +offer it can keep to (`server_accept`), with `server_no_context_takeover` +and `client_no_context_takeover` as C takes them, and says so in its 101; +a client offers `permessage-deflate` and takes the server's answer if its +parameters are RFC 7692's, each once, in C's ranges (`client_accept`). +`Ws::with_pmd` then inflates a message whose first frame has RSV1, RSV1 +being refused anywhere else as C refuses it: its payload is held, unmasked, +at most 1KiB at a time, inflated into at most 1KiB a call, the drain +budget, with `rx_pending` saying when there is more to give without input; +the trailer is put back at its end; data after a BFINAL that is not +padding, data that does not inflate, and a message past its limit (C's +256MiB, `Params::with_max_message`) drop the connection, as C marks its +socket unusable, what inflated before the failure given first. What the +application sends is deflated into frames of at most 1KiB, RSV1 on the +first, the flush's trailer removed, an empty message after a flush C's +one octet. Context is dropped per message as each side agreed: the +deflater for our own `*_no_context_takeover`, the inflater for the peer's, +or when its stream ended. + +The tests: all four pmd transcripts replay (`ws-client-pmd-rsv2`, +`-rsv1-continuation`, `-rsv1-ping`, and `ws-server-pmd-rsv1-continuation`, +through the `sansio-pmd` vhost); RFC 7692 7.2.3's example frames inflate, +one piece at a time and in larger ones; messages of every size around the +1KiB bounds, compressible and not, go client to server and back, written +four bytes at a time and read a byte at a time, with and without context +takeover; and the fuzz target `ws-pmd`, seeded from C's +`fuzz/fuzz-ws-pmd/seeds`. Fuzzing it found that a caller must be told to +come back for what inflates without more input (`rx_pending`), and that +what inflated before a failure must be given first, so the check of text +sees the stream in order. What npro deflates was also inflated by zlib +(Python's), as C's peers would, by hand: that is how the window below was +found, and is not yet a test. + +Differences from C, each where C does something RFC 7692 does not have: + +- `miniz_oxide`'s smaller windows refer further back than they say (zlib + finds distances too far back from a 9 bit window, and from any under + 14), so npro's deflater always uses 32KiB. A server declines an offer + asking for a smaller `server_max_window_bits`, and tries the next, as + RFC 7692 7.1.2.1 has it; C takes the offer and leaves the parameter + out, still deflating with 32KiB. A client refuses a + `client_max_window_bits` under 15, which it did not offer; C takes it. +- A client refuses the lws-private options C takes from a server + (`rx_buf_size` and the like), and a parameter given twice. +- A server takes the first offer it can keep to; C takes the first + `permessage-deflate`, and drops the connection if it is offered twice + before an offer with parameters. + +Not yet: the deflater's compression level and the 1KiB chunks are C's +defaults, not configurable; a client offers only `permessage-deflate`, with +no parameters; no permanent test inflates npro's output with zlib (the C +oracle's `sync-c-h1.sh` is where one would go); the `x-webkit-deflate-frame` +and other extensions are not ported. + ### Phase 1g: minimal `npro-io` - std TCP, plain poll-style loop, no tls yet. Enough to run:
Page fetched 0s ago, creation time: 3ms (vhost etag hits: 0%, cache hits: 0%)