You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Heuristic freshness computed from Last-Modified #3
A response stating no explicit expiration is revalidated on every exchange, even where it carries a Last-Modified
field that says how volatile the content actually is. An origin whose content has not changed in a year is re-fetched
as eagerly as one edited a minute ago.
proposal
Derive a freshness lifetime from the response header fields where the origin states no explicit expiration, as
permitted by RFC 9111 § 4.2.2: take the interval since Last-Modified and treat a fraction of it as the lifetime,
around 10% as the RFC encourages.
Guards:
apply only where no Cache-Control freshness directive and no Expires is stated; no-cache and max-age=0 are
stated expirations and must keep winning, so the test is whether a directive is present, not whether the computed
lifetime is 0
apply only for the heuristically cacheable status codes of RFC 9110 § 15.1
bound the result, so a distant Last-Modified does not yield an unbounded lifetime
let ttl cap the result as it caps any computed lifetime
alternatives
Leaving it to the consumer to state a flat lifetime. That covers an origin stating nothing at all, but ignores the
volatility an origin does state, so a stable and a churning resource are reused for the same span.
notes
Ranks between the two cases already settled: a stated expiration wins over this, and this wins over a flat lifetime
the consumer states for an origin whose responses carry no Last-Modified either.
changed the title [-]Heuristic freshness for responses stating no explicit expiration[/-][+]Heuristic freshness computed from Last-Modified[/+]on Sep 3, 2026
A response stating no expiration but reporting a usable Last-Modified is now reused for a tenth of the interval its content had already gone unchanged when the response was generated, measured up to the instant the origin server states in Date and falling back to the reception time where it states none, matching how the lifetime Expires states is measured.
Guards
a Cache-Controlno-cache, max-age, must-revalidate or proxy-revalidate directive or an Expires field keeps winning, tested by presence rather than by the lifetime it computes
the assumption applies to the heuristically cacheable status codes of RFC 9110 § 15.1 alone
ttl caps the assumed share as it caps a stated expiration, and supplies the freshness where no usable Last-Modified is reported
content stated as changed after generation yields no freshness
Open point
The bound is ttl alone, so the default ttl of 0 leaves the assumed share uncapped: a Last-Modified ten years back yields a one-year lifetime. Filed separately if a built-in ceiling is wanted.
Activity
[-]Heuristic freshness for responses stating no explicit expiration[/-][+]Heuristic freshness computed from Last-Modified[/+]feat!: assume a freshness lifetime from the last modification time
knoan commentedon Sep 3, 2026
Implemented in
4dc394donrelease/0.1.Approach
A response stating no expiration but reporting a usable
Last-Modifiedis now reused for a tenth of the interval its content had already gone unchanged when the response was generated, measured up to the instant the origin server states inDateand falling back to the reception time where it states none, matching how the lifetimeExpiresstates is measured.Guards
Cache-Controlno-cache,max-age,must-revalidateorproxy-revalidatedirective or anExpiresfield keeps winning, tested by presence rather than by the lifetime it computesttlcaps the assumed share as it caps a stated expiration, and supplies the freshness where no usableLast-Modifiedis reportedOpen point
The bound is
ttlalone, so the defaultttlof0leaves the assumed share uncapped: aLast-Modifiedten years back yields a one-year lifetime. Filed separately if a built-in ceiling is wanted.