Skip to content

Release v2.0.1: hardening across TLS/H2/proxy/DNS/client + Chrome 153 / Edge 152-153 profiles - #161

Merged
deedy5 merged 15 commits into
mainfrom
dev
Sep 12, 2026
Merged

deedy5 merged 15 commits into
mainfrom
dev

Conversation

@deedy5

@deedy5 deedy5 commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Summary

Patch release focused on fail-closed hardening, fingerprint correctness, and upstream syncs. No new public Rust API; Python client surface gets stricter BuilderError taxonomy.

What's new

Release:

  • chore(release): bump primp and primp-python to 2.0.1 — brotli 8→9, zstd 0.13→0.14, jiter 0.16→0.17, Cargo.lock sync for primp-h2 0.4.19 / primp-rustls 0.23.43

New profiles:

  • feat(imp): add Chrome 153 and Edge 152-153 profiles

Upstream syncs:

  • chore(h2): sync fork to upstream 0.4.19 — GOAWAY stream-id validation, auto DATA framing budget (½ conn window, 25.6k min), empty DATA lifetime flood guard (100), shutdown-race wake fix
  • chore(rustls): sync fork to upstream 0.23.43 — QUIC TLS 1.3-only enforcement, offered-suite tracking / HRR checks, Rfc5077Ticketer truncation fix, saturating binder/ticket-age math

Correctness / security hardening:

  • fix(tls): enforce version limits under impersonation with FIPS-safe handshake — filter offers by min/max, fail-closed on empty range, FIPS scheme/group intersection, TLS 1.2 fallback from advertised list, strict DER/PEM validation
  • fix(impersonation): correct browser fingerprints and H2 pseudo-header order — Chrome sec-ch-ua v151+, versioned header order, non-extending pseudo-order (omit implicit :protocol)
  • fix(h2): harden flow-control accounting and flood guards + fix(h2): validate builder limits, HPACK handling and header ordering — checked arithmetic → FLOW_CONTROL_ERROR, pending-pong GOAWAY guard, warn-and-keep on bad window/frame sizes, last-wins size-update, custom pseudo-order with fallback
  • fix(http): strict URL validation, retry budget and lossless cookie handling — scheme/host check, fallible finite retry budget, hop-by-hop strip preserving proxy-auth, byte-level cookie merge for non-UTF8
  • fix(proxy): fail-closed routing, auth handling and SOCKS hardening — preserve path/query on custom proxies, OWS-tolerant basic-auth, redact matcher debug, pre-dial SOCKS validation, retry all resolved IPs
  • fix(dns): normalize host keys and harden cache and resolvers — lowercase + trailing-dot strip, LRU stale-slot guard, tokio OnceCell hickory resolver
  • fix(client): harden timeouts, pools, ALPN and redirect layering — reject zero read timeout, clamp DNS ≥1ms, None pool timeout = disable eviction, h2 ALPN for prior-knowledge, tower order retry→cookie→decomp→range→redirect
  • fix(client): reset body timeout per chunk and poll cookies without cloning — sleep_until per-chunk deadline, close bodyless on HEADERS+END_STREAM (avoids 0.4.19 empty-DATA flood guard tripping at 101+ GETs)

Python:

  • fix(python): unify body resolution, BuilderError taxonomy and client surface — data+files → multipart (requests-like priority), invalid impersonate/resolver/timeout/CA/body → BuilderError with sources (drops warn-and-fallback), trailing proxy arg, prefix-preserving base URLs, mtime-cached CA bundles, __version__ + full __all__

Deps / runtime:

  • chore(deps): align http to 1.4, prune unused deps and harden panic strategy — http 1.1→1.4, drop fnv/once_cell, workspace panic abort→unwind (panics become Python exceptions)

…rategy

- Bump http 1.1 -> 1.4 across primp and primp-h2, drop fnv and
  once_cell, add tokio sync plus time test-util dev-deps.
- Declare primp-h2 package include list to tighten published files.
- Switch workspace panic from abort to unwind so native panics
  surface as Python exceptions instead of killing the interpreter.
- Replace lossy casts with checked arithmetic in window management;
  return FLOW_CONTROL_ERROR instead of asserting on over-window DATA.
- Queue pending pongs with GOAWAY flood guard instead of dropping them.
- Count all DATA frames including empty EOS toward connection budget.
- Replace unsafe disjoint borrow with safe pattern in stream store.
- Warn and keep previous value on out-of-range window and frame sizes
  instead of panicking in client, server and settings builders.
- Use last-wins HPACK size-update validation and seeded per-table
  hash for header indexing.
- Support custom pseudo-header order with trailing fallback and keep
  duplicate continuations grouped when sorting.
…andshake

- Filter offered TLS versions by configured min/max, fail closed on
  empty range and suppress ECH GREASE when filtered.
- Intersect signature schemes and named groups for FIPS, fall back to
  provider FIPS groups on empty or GREASE-only input; refuse
  fips+ml-dsa feature combo at compile time.
- Select TLS 1.2 cipher fallback from advertised list with JA4-aware
  mapping and warn on fallback; encode empty trust anchors as 00 00.
- Reject empty DER and PEM bundles, trim whitespace per line, share
  PEM-cleaning helper across cert, identity and CRL paths.
- Detect plaintext buffer full case-insensitively without panicking.
… order

- Extend Chrome sec-ch-ua purpose to v151+ and use chrome150 header
  order for v150-v152 while keeping upgrade-first for older versions.
- Use non-extending pseudo-order builder across Chrome, Edge, Firefox,
  Opera and Safari to omit implicit :protocol on custom orders.
- Lowercase host keys and strip trailing dot for cache, hosts file
  and overrides so FQDN variants hit the same entry.
- Guard LRU stale-slot puts without panicking and preserve DoH query
  strings on non-empty paths.
- Use tokio OnceCell for hickory resolver to avoid blocking the runtime.
- Parse proxy URLs without strict client scheme check, preserve path
  and query on custom proxies and fail closed on target parse errors.
- Tolerate OWS whitespace in basic-auth decoding, redact matcher debug
  output and propagate intercept errors instead of swallowing them.
- Validate SOCKS config pre-dial, retry all locally resolved IPs and
  fail fast on deterministic errors; keep proxy TLS ALPN distinct.
- Reattach proxy auth on http-only redirects and thread redirect
  overrides through wrapped request config.
…ndling

- Validate http/https scheme and host on URL conversion, including
  borrowed URL support.
- Add fallible retry budget API with finite range check, saturating
  retry counts and hop-by-hop header stripping that preserves proxy
  auth; match timeouts case-insensitively for h3.
- Tolerate invalid cookie values per-part and merge jar plus one-shot
  cookies at byte level to preserve non-UTF8 with sanitized fallback.
- Reject zero read timeouts via Result API, clamp DNS timeout to at
  least 1ms and poll in-flight responses before timeout checks.
- Respect None pool idle timeout to disable eviction, bound pool size
  by idle-per-host limits and recover from poisoned h3 pool mutexes.
- Validate h2 window and frame sizes with warn-and-ignore, clamp h3
  send window verbatim and force h2 ALPN for prior knowledge.
- Order tower as retry -> cookie -> decompression -> range -> redirect
  so redirects re-enter range handling; surface proxy header errors.
- Strip credentials even on authority decode failure.
- Add deterministic paused-time timeout tests, range-through-redirect
  coverage and fix_coverage regression smokes.
…surface

- Combine data plus files as multipart with requests-like priority
  instead of erroring; share resolve_body and multipart builder
  between sync and async clients.
- Surface invalid impersonate, resolver, timeout, CA and body config
  as BuilderError with source chains; drop warn-and-fallback parsing.
- Move proxy to trailing position on one-shot APIs and thread it
  through client construction; resolve base URLs prefix-preserving
  and skip empty params mappings.
- Cache CA bundles by mtime with bounded size, read through env with
  warnings and fail on missing files; use canonical status reasons
  and newline-joined Set-Cookie handling.
- Export __version__ and complete __all__ in stubs and runtime.
- Validate GOAWAY stream ID is zero and return InvalidStreamId otherwise; thread Head through GoAway::load and framed_read.

- Scale DATA framing budget automatically as half the connection window with 25,600 minimum; keep explicit override via Configured budget.

- Count empty non-final DATA frames against separate lifetime limit (100) without consuming framing budget; large frames no longer replenish empty limit.

- Snapshot stream/reference presence before maybe_close to avoid missing self-wake on shutdown race; add budget and empty-frame unit tests.

- Use BuildHasher::hash_one for header hashing (clippy manual_hash_one).
- Thread Protocol through supports_version and find_cipher_suite so
  QUIC enforces TLS 1.3-only; fix server/client version checks to
  return Tls13RequiredForQuic and require TLS 1.3 for QUIC setup.
- Track offered cipher suites in ClientHello and reject server-selected
  unoffered suites; enforce protocol usability for HRR and QUIC.
- Fix Rfc5077Ticketer truncation panic with checked_sub and add
  truncated-ciphertext rejection test.
- Use saturating arithmetic for binder truncation and ticket age
  overflow; make SupportedCipherSuite::tls13 const.
- Add server_hello and QUIC test encoders plus rejection tests for
  TLS 1.2 on QUIC and non-QUIC suite selection.
- Apply cargo fmt normalization (import order, line width).
…oning

- Use sleep_until with deadline reset on each ready frame so body
  read timeout applies per chunk instead of being cleared.
- Poll cookie middleware via projected future and store references
  instead of cloning Options upfront.
- Close bodyless requests on HEADERS with END_STREAM instead of a
  trailing empty DATA frame; primp-h2 0.4.19 counts empties toward a
  lifetime flood guard (100) and 101+ GETs on one connection would
  trip GOAWAY ENHANCE_YOUR_CALM as BrokenPipe.
- Assign h2 ALPN vector directly instead of useless into_iter/collect
  (clippy useless_conversion); apply cargo fmt normalization.
- Bump primp 2.0.0 -> 2.0.1 and primp-python 2.0.0 -> 2.0.1.
- Bump brotli 8 -> 9, brotli-decompressor 5 -> 6, zstd 0.13 -> 0.14
  and jiter 0.16 -> 0.17; unify zstd on 0.14 in Cargo.lock.
- Sync Cargo.lock for primp 2.0.1, primp-h2 0.4.19, primp-rustls
  0.23.43 and primp-python 2.0.1.
@deedy5
deedy5 merged commit 1887944 into main Sep 12, 2026
20 checks passed
@deedy5
deedy5 deleted the dev branch September 12, 2026 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant