Skip to content

3.0.0-beta.4

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 28 Jun 20:02

Added

HTTP caching

  • Cache zones — the cache directive now supports a zone subdirective at host scope, allowing multiple hostnames to share a single in-memory cache store. Named zones can be pre-configured at global scope with custom max_entries capacity. When a global cache { max_entries } block exists without explicit zone blocks, all hosts share a global zone by default. Hosts can opt out with an explicit zone directive.
  • Generation-aware cache capacitymax_entries is now only evaluated on configuration reload instead of on every request, preventing premature LRU eviction when different host blocks specify different capacities for the same zone.
  • Zone attribute in cache metrics — all cache metrics (ferron.cache.requests, ferron.cache.entries, ferron.cache.stores, ferron.cache.evictions, ferron.cache.purges) now include a ferron.cache.zone attribute identifying the zone the request belongs to.

Rate limiting

  • Rate limit zones — the rate_limit directive now supports a zone subdirective at host scope, allowing multiple hostnames to share the same rate limit token bucket registries. Named zones can be defined at global scope. When a global rate_limit block exists without explicit zone blocks, all hosts share a global zone by default. Hosts can opt out with their own rate_limit block.
  • Key extractor in fingerprint — the rate limit fingerprint now includes the key extractor type (ip, uri, header), so rules with different key types no longer share the same registry.
  • Zone attribute in rate limit metrics — rate limit metrics (ferron.ratelimit.rejected, ferron.ratelimit.allowed) and structured log events now include a ferron.ratelimit.zone attribute identifying the zone the request belongs to.

Static file serving

  • If-Range support — The If-Range header is now supported for conditional range requests (RFC 7233 §3.2), allowing clients to receive a partial response when the entity tag or modification date matches, or a full response when the representation has changed.

Fixed

Reverse proxy

  • SRV priority/weight swap fix — SRV upstream resolution was reading the priority and weight fields in the wrong order, causing traffic to be routed to the wrong priority group. Priority and weight are now correctly interpreted per RFC 2782.
  • Upgrade connection pool leak fix — HTTP 101 upgrade connections (WebSocket, etc.) were not decrementing the pool outstanding counter, permanently reducing available pool capacity by one per upgrade. The pool item now drops correctly, releasing the slot.
  • Hop-by-hop header stripping on requests — the outgoing proxy request now strips hop-by-hop headers (Connection, Keep-Alive, Transfer-Encoding, TE, Trailer, Proxy-Authorization, Proxy-Authenticate) per RFC 7230 §6.1, preventing clients from injecting these headers to influence backend behavior.

Static file serving

  • HTTP range requests fix — HTTP range requests now correctly handle out-of-bounds ranges, returning 206 Partial Content with the available range instead of 416 Range Not Satisfiable (per RFC 7233 §2.1).
  • On-the-fly compression allowed while using precompressed files — When serving precompressed files, the content is now compressed on-the-fly if precompressed files are not available, improving performance and reducing disk usage.
  • Multipart byterange fix — Multipart range responses now include the required bytes prefix in Content-Range part headers (per RFC 7233 §4.1) and correctly serve one additional byte per range to match inclusive-to-exclusive bounds (is_end_stream no longer signals end-of-stream while the last range's data is still being streamed).
  • If-None-Match POST fix — POST requests with a matching If-None-Match header now correctly return 412 Precondition Failed instead of 200 OK (per RFC 7232 §4.2).
  • If-Match: * with non-GET/HEAD fixIf-Match: * now correctly passes for POST and other non-GET/HEAD requests when a representation exists, per RFC 7232 §3.1.
  • Invalid Range header handling — Syntactically invalid Range headers are now treated as absent (returning 200 OK) instead of 416 Range Not Satisfiable, per RFC 7233 §3.1.
  • file_cache_control panic fix — Malformed file_cache_control config values can no longer panic the request handler; a validation warning now catches invalid characters.
  • Missing Content-Length for compressed responses — Non-identity (compressed and precompressed) file responses now include the correct Content-Length header.
  • bytes_sent metric fix — The bytes_sent metric now reports the actual compressed file size for precompressed responses instead of the original file size.

HTTP caching

  • Cache revalidation fix - when a cached response is revalidated, the HTTP status code is now preserved from the cached response instead of always using 200 OK.
  • Abuse protection fix - 403 Forbidden responses generated by abuse protection module are no longer cached (as they are served before the cache).
  • Cache scope fix - in the previous version (Ferron 3.0.0-beta.3), caches were per-host instead of global, even when maximum cache items subdirective was global-only. This has been fixed to restore the behavior before 3.0.0-beta.3.
  • Stale-while-revalidate inflight request fix - when a stale response is revalidated, the inflight request handling no longer causes possible hangs.
  • Expires header in past edge case fix - a response with a past Expires header and no Cache-Control directives was incorrectly cached for 5 minutes. This has been fixed to cache the response for 0 seconds (expires immediately) instead.
  • Stale-if-error correctness fix - a stale response is no longer served when must-revalidate is set, per RFC 9111 §4.3.4.
  • Cache key fix - an attacker could craft a cookie value containing &cookie: to collide with another user's cache key. This severe cache collision was fixed by using \0 as the separator instead of & in the cache key.
  • 304 revalidation TTL fix - when a cached response is revalidated via a 304 Not Modified response, the stored response's TTL, stale-while-revalidate, stale-if-error, and must-revalidate directives are now updated from the 304 response's Cache-Control headers per RFC 9111 §4.3.4. Previously only ETag and Last-Modified validators were updated, causing the original TTL to persist even when the upstream sent a different max-age.
  • Cache variant metadata leak fix - the variants_by_base map used for cache lookups previously grew without bound, retaining variant records for all URLs ever cached even after entries were purged. This map is now cleaned up when all entries for a base key are removed via purge.