Cloudflare's Weird Age Header.
Tags: http, cloudflare
Published: 2022-03-01 20:06:12

---
title: Cloudflare's Weird Age Header.
published: true
date: 2022-02-18 22:00:00 UTC
tags: HTTP,Cloudflare
canonical_url: https://kevincox.ca/2022/02/18/cloudflare-age-header/
---

<main><p>I noticed something weird today:</p>
<div><pre><code><font color="#8B8A88">%</font><b> curl -I https://blog.benjojo.co.uk/rss.xml</b>
HTTP/2 200
<b>age</b>: 99788
<b>cache-control</b>: public, max-age=1800
<b>cf-cache-status</b>: HIT
<b>date</b>: Fri, 18 Feb 2022 17:41:40 GMT
<b>server</b>: cloudflare
...
</code></pre></div>
<p>Do you see the oddity? <code>Age</code> is greater than <code>Cache-Control</code>’s <code>max-age</code>. According to <a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.2.3">RFC2616</a> that means that this resource is already expired. Let’s look at the “Summary of age calculation algorithm”.</p>
<div><pre><code><span>apparent_age</span> <span>=</span> <span>max</span><span>(</span><span>0</span><span>,</span> <span>response_time</span> <span>-</span> <span>date_value</span><span>)</span>
<span>corrected_received_age</span> <span>=</span> <span>max</span><span>(</span><span>apparent_age</span><span>,</span> <span>age_value</span><span>)</span>
<span>response_delay</span> <span>=</span> <span>response_time</span> <span>-</span> <span>request_time</span>
<span>corrected_initial_age</span> <span>=</span> <span>corrected_received_age</span> <span>+</span> <span>response_delay</span>
<span>resident_time</span> <span>=</span> <span>now</span> <span>-</span> <span>response_time</span>
<span>current_age</span> <span>=</span> <span>corrected_initial_age</span> <span>+</span> <span>resident_time</span>
</code></pre></div>
<p>Let’s fill in some variables and evaluate…</p>
<div><pre><code><span>age_value</span> <span>=</span> <span>101626</span>
<span>date_value</span> <span>=</span> <span>"2022-02-18 17:41:40"</span>
<span>now</span> <span>=</span> <span>"2022-02-18 17:41:41"</span>
<span>request_time</span> <span>=</span> <span>"2022-02-18 17:41:39"</span>
<span>response_time</span> <span>=</span> <span>"2022-02-18 17:41:41"</span>

<span>apparent_age</span> <span>=</span> <span>max</span><span>(</span><span>0</span><span>,</span> <span>"2022-02-18 17:41:41"</span> <span>-</span> <span>"2022-02-18 17:41:40"</span><span>)</span> <span># 1</span>
<span>corrected_received_age</span> <span>=</span> <span>max</span><span>(</span><span>1</span><span>,</span> <span>101626</span><span>)</span> <span># 101626</span>
<span>response_delay</span> <span>=</span> <span>"2022-02-18 17:41:41"</span> <span>-</span> <span>"2022-02-18 17:41:39"</span> <span># 2</span>
<span>corrected_initial_age</span> <span>=</span> <span>101626</span> <span>+</span> <span>2</span> <span># 101628</span>
<span>resident_time</span> <span>=</span> <span>"2022-02-18 17:41:41"</span> <span>-</span> <span>"2022-02-18 17:41:41"</span> <span># 0</span>
<span>current_age</span> <span>=</span> <span>101628</span> <span>+</span> <span>0</span> <span># 101628</span>
</code></pre></div>
<p>I’ll save you the math for calculating freshness but it boils down to <code><span>current_age</span> <span>&lt;=</span> <span>max_age</span></code> AKA <code><span>101628</span> <span>&lt;=</span> <span>1800</span> <span>==</span> <span>false</span> <span># STALE</span></code>.</p>
<p>This means that Cloudflare is serving resources that are already stale! Now this isn’t much of a problem, the customer may have configured Cloudflare to cache for an extended period of time, ignoring the original headers. However in that case Cloudflare should probably “spoof” the headers to reflect reality. In this case this the best option is likely updating the <code>Cache-Control</code> header to suggest that the response still has a little life left in it. Or just set <code>max-age=0</code> to indicate that it needs to be revalidated, I think this option would preserve the current behaviour while being less confusing.</p>
<p>One explanation is that the origin is down. The <code>Age</code> header is over 28h old, so it does seem unlikely that this was an intentional cache period. In this case they may be using something like a <code>s-stale-if-error</code> extension to indicate that the cache may use expired entries if the origin is down.</p>
<p>Another possible explanation is that Cloudflare revalidated the cache entry, however in this case the <code>Age</code> header should be reset to the time of validation.</p>
<p>I don’t think this is a major problem, the only downside I can think of is that it will lead to clients constantly contacting Cloudflare to revalidate, which may not have been the original intention. However it certainly did pique my curiosity.</p></main>