0.9.0

cloudflare/pingora0.9.0Sep 9, 2026by drcaramelsyrup

Full Release Notes

## [0.9.0](https://github.com/cloudflare/pingora/compare/0.8.0...0.9.0) - 2026-09-04

### ✨ Highlights

- Reworked connection pooling with sharded storage and a true global LRU, addressing stale entries and race windows.
- Added an upstream module system that applies before upstream compression.
- More handling of HTTP parsing and framing edge cases, including non-origin-form request-target preservation, and hop-by-hop header sanitization, obsolete line-fold normalization, stricter request-target validation, and bounded default HTTP/2 limits.
- Split Prometheus integration into the pingora-prometheus crate and made Prometheus optional.
- Improved graceful shutdown and upgrade behavior, including responsive load-balancer shutdown, descriptor lifecycle fixes, and lower shutdown-notification contention.

### ⚠️ Potential Breaking Changes

- Minimum supported Rust version moves to 1.85 for some crates. pingora-foundations declares an MSRV of 1.88.
- RequestHeader and ResponseHeader no longer implement DerefMut because unrestricted mutation could violate internal invariants.
- Removed async_write_vec APIs; consumers should use tokio::io::AsyncWriteExt::write_all_buf.
- Prometheus integration moved from pingora-core to the separate pingora-prometheus crate; Prometheus is optional.
- tracing is now optional in pingora-cache.
- Upgraded to the boring-rs 5.x API.
- PeerOptions::curve now uses Cow.
- Upstream requests strip hop-by-hop and Connection-nominated headers by default; legacy behavior requires explicit compatibility settings.
- Default HTTP/2 server limits are bounded rather than unbounded.
- Removed the unused LruShard Default implementation and lifted Default bounds on sharded cache structures.
- Removed the CacheKey namespace parameter.
- PurgeOutcome enum gains an Expired variant.
- ForcedFreshness and hit-status reporting gain ForceExpiredServeStale variant.

### 🚀 Features — Proxy & Sessions

- Add abort-on-close session configurability.
- Support HTTP/1.1 downstream request pipelining.
- Add cancel-safe body and header writer primitives (proxy tasks) to prevent stalled cache misses from applying backpressure.
- Add an upstream module system and allow modules to adjust after receiving upstream response headers.
- Add proxy warning-log suppression hooks.
- Add keepalive-pool callbacks for tracking connection ages.
- Expose HTTP/1.x request-body bytes accepted by the upstream writer.
- Report point-in-time available HTTP/2 stream capacity.

### 🚀 Features — TLS

- Add ability to configure an offload thread pool for downstream TLS handshakes.
- Add Acceptor::from_server_config for runtime-built rustls ServerConfig values and in-memory key material.
- Export TLS keying material, including from pingora-s2n.
- Add per-peer CA configuration.
- Add a pre-TLS callback for PROXY protocol support.
- Expose the rustls certificate type.
- Add curve and second-keyshare settings to HttpPeer hashing.
- Avoid compiling aws-lc-rs when the ring provider is selected.

### 🚀 Features — Server, Runtime & Load Balancing

- Allow sharing backends across load-balancing selectors.
- Add graceful-upgrade signalling between old and new processes.
- Add per-listener L4 buffer configuration and socket send/receive buffer settings.
- Add Tokio blocking-pool configuration, poll-time histograms, and an alternative timer runtime knob.
- Allow proxy services to override runtime options.
- Add a working-directory option for daemon mode.
- Enable adding user context between sessions on the same connection with HttpPersistentSettings.
- Add socket-cookie access and TCP/TLS establishment timing fields.
- Make HTTP/2 stream and connection windows configurable.

### 🚀 Features — Caching (alpha)

- Add deferred cache-admission policy hooks.
- Implement DCZ dictionary compression and vary on available-dictionary.
- Add CacheMeta freshness updates and expiration-at-time support.
- Support optionally flooring fractional delta-seconds for RFC 9111 handling.
- Preserve Vary provenance across stale refreshes.
- Make cache-lock retries configurable and bounded.
- Add an opt-in purge mode that expires an asset while retaining its body for conditional revalidation and stale serving.
- Use power-of-two selection for eviction balancing.
- Add peek_lru, update_or_admit, and non-promoting set_weight operations in lru.
- Allow adjusting LRU weight limits and reserving capacity.

### 🔒 Security & Hardening

- HTTP ambiguity hardening: centralize raw request-target classification so path and authority validation share one parser; reject ambiguous request authorities on ingress and egress; reject forbidden CR/LF bytes in HTTP/2 :path; and reject delimiter bytes in request lines as defense in depth.
- Sanitize hop-by-hop upstream request headers.
- Preserve non-origin-form request targets without mangling the URI.
- Normalize forwarded responses with obsolete HTTP/1.1 response-header line folding.
- Bound default HTTP/2 server limits to reduce memory-exhaustion exposure.
- Avoid a process abort while appending oversized header maps by returning an InvalidHTTPHeader error.
- Fix some unchecked integer conversions.
- Explicitly prevent reuse of HTTP/1 connections after incomplete responses.
- Update Prometheus for a security advisory.
- Replaced unmaintained daemonize crate with daemonix and updated nix to 0.31.x.

### 🐛 Bug Fixes

- Fix connection-pool and PoolNode race windows and remove empty entries.
- Fixed a potential stall on HTTP/1 response-header reads upon forwarding request bodies via a cancel safety fix.
- Stop waiting on HTTP/2 upstream work after the downstream ends and close timed-out HTTP/2 connections.
- Drain in-flight HTTP/2 streams during shutdown and retry stream creation on a fresh connection when appropriate.
- Prevent HTTP/1 upstream reuse after failed writes or incomplete responses.
- Discard retry buffers after truncation and avoid unnecessary HTTP/2 accept allocations.
- Skip h2c preface detection on TLS streams.
- Do not initialize a body reader for HEAD informational responses.
- Correct HTTP/1 session body-byte accounting.
- Fix listener-fd inheritance and close transfer sockets during graceful upgrade; mark received listener fds close-on-exec.
- Remove the duplicate graceful-shutdown sleep and improve load-balancer shutdown responsiveness.
- Shard proxy shutdown notifications to reduce lock contention and close a lost-wakeup race during graceful shutdown.

### ⚙️ Miscellaneous

- pingora-timeout now uses Tokio timeouts for (configurably) long intervals to avoid memory accumulation.
- Split pingora-prometheus into a separate crate.
- Forward WriteBuf::chunks_vectored to the wrapped buffer.
- Replace custom ASCII-trimming helpers with stabilized standard-library methods.
- Update the MSRV lane and use cargo check for MSRV validation.
- Improve documentation examples for connection tracing and basic setup.
- Preserve bound ports in digests after TLS failures.
- Return an error for divergent multipart cache progress and remove a panic from maybe_cache_meta.
- Various flaky test fixes.