Skip to content

Honor origin agent cache headers and edge TTL - #86

Open
Orkuncakilkaya wants to merge 5 commits into
mainfrom
inter-2548-fix-agent-cache-headers
Open

Orkuncakilkaya wants to merge 5 commits into
mainfrom
inter-2548-fix-agent-cache-headers

Conversation

@Orkuncakilkaya

@Orkuncakilkaya Orkuncakilkaya commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Agent cache headers: before and after

Services to test (staging, procdn.fpjs.sh):

Test results

Step Expected Before After
1. First request 200, no s-maxage, no age, cache-tag ❌ age: 1 ✅ no age, cache-tag kept*
2. Second request (hit) 200, no s-maxage, age: 0, no cache-tag ❌ age: 1 ✅ HIT, age: 0, no cache-tag
3. After max-age** 200, no s-maxage, age: 0, no cache-tag ❌ HIT, age: 1 ✅ HIT (revalidated), age: 0
4. If-None-Match 304, no s-maxage, age: 0, no cache-tag ❌ 304 HIT, no age ✅ 304 HIT, age: 0
  • Staging sends no s-maxage.
  • * Upstream sends cache-tag only on its own cache misses. The proxy keeps it on misses.
  • ** The edge TTL is 60s in both builds, so a 70s pause covers it.

What changed

Area Before After
Edge TTL 60s Unchanged
Build HTTP cache API off --enable-http-cache
age on miss Upstream value Removed
age on hit Upstream value 0
cache-tag on hit Replayed Removed
If-None-Match on hit 304 (native) 304 for GET/HEAD, 412 for other methods
If-None-Match on upstream error — Error kept
If-None-Match lists, *, commas in tags — Handled

Why

  • Upstream age would reach browsers. Hits need age: 0 so browsers keep the agent for the full max-age.
  • cache-tag is the upstream CDN's purge tag. It isn't exposed on hits.
  • Detecting hits needs the HTTP cache API. With it on, Fastly Compute no longer answers If-None-Match on hits.

@Orkuncakilkaya
Orkuncakilkaya requested a balanced review from Copilot September 24, 2026 11:38
@Orkuncakilkaya Orkuncakilkaya changed the title fix: add applyAgentCacheHeaders to handle edge TTL and cache headers Honor origin agent cache headers and edge TTL Sep 24, 2026
@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Coverage report

St.❔
Category Percentage Covered / Total
🟢 Statements
97.71% (+0.17% 🔼)
256/262
🟢 Branches
98.9% (+0.2% 🔼)
90/91
🟢 Functions
98.36% (+0.15% 🔼)
60/61
🟢 Lines
97.67% (+0.15% 🔼)
252/258
Show new covered files 🐣
St.❔
File Statements Branches Functions Lines
🟢
... / agentCacheHeaders.ts
100% 100% 100% 100%

Test suite run success

107 tests passing in 7 suites.

Report generated by 🧪jest coverage report action from a756cda

Show full coverage report
St File % Stmts % Branch % Funcs % Lines Uncovered Line #s
🟢 All files 97.7 98.9 98.36 97.67
🟢  src 90.38 100 93.33 90.38
🟢   env.ts 92.59 100 100 92.59 67,74
🟢   handler.ts 100 100 100 100
🟡   index.ts 66.66 100 50 66.66 9,19-20
🟢  src/handlers 99.11 97.22 100 99.1
🟢   handleApiRequest.ts 100 100 100 100
🟢   handleDownloadScript.ts 100 100 100 100
🟢   handleIngressAPI.ts 100 100 100 100
🟢   handleStatusPage.ts 98.61 96.15 100 98.61 73
🔴   index.ts 0 0 0 0
🟢  src/utils 100 100 100 100
🟢   addProxyIntegrationHeaders.ts 100 100 100 100
🟢   addTrafficMonitoring.ts 100 100 100 100
🟢   agentCacheHeaders.ts 100 100 100 100
🟢   clientIp.ts 100 100 100 100
🟢   cookie.ts 100 100 100 100
🟢   createErrorResponse.ts 100 100 100 100
🟢   createRoute.ts 100 100 100 100
🟢   getIngressBackendByRegion.ts 100 100 100 100
🟢   getStore.ts 100 100 100 100
🔴   index.ts 0 0 0 0
🟢   proxyEndpoint.ts 100 100 100 100
🟢   returnHttpResponse.ts 100 100 100 100

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Conditional ETag handling does not support tag lists or *, causing incorrect 200 responses.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity · 1 Low severity

Open (2)
What changed in this PR

Updates agent script downloads to honor origin cache headers and edge TTLs.

Changes:

  • Uses origin-controlled caching and Fastly’s HTTP cache API.
  • Normalizes cache headers and adds conditional ETag responses.
  • Adds cache behavior tests and a patch changeset.
File Review
test/​handlers/​downloadScript.test.ts Adds cache and conditional-request tests.
src/​utils/​agentCacheHeaders.ts Requires correct parsing of multi-value and wildcard If-None-Match headers (moderate). Documentation should clarify cache-tag miss/hit behavior (nit).
src/​handlers/​handleDownloadScript.ts Applies origin-driven caching and header normalization.
package.json Enables the Fastly HTTP cache API.
.changeset/​tame-rice-eat.md Records the patch release.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/utils/agentCacheHeaders.ts
Comment thread src/utils/agentCacheHeaders.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Conditional request and cache-header handling contain unresolved critical and moderate correctness issues.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 High severity · 2 Medium severity

Open (3)
Resolved since last review (2)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Honor If-None-Match wildcard without an ETag

src/​utils/​agentCacheHeaders.ts:45

The etag !== null guard prevents the wildcard form from being honored when the selected representation has no ETag. If-None-Match: * matches any existing representation for a conditional GET/HEAD, so a cache hit without an ETag incorrectly returns 200 instead of 304; handle * independently of the ETag comparison.

Comment thread src/utils/agentCacheHeaders.ts
Comment thread src/utils/agentCacheHeaders.ts Outdated
Comment thread src/utils/agentCacheHeaders.ts
Orkuncakilkaya and others added 2 commits September 24, 2026 14:54
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The three moderate cache-header and conditional-response issues must be resolved before approval.

Review effort: Balanced
Findings: None

Resolved since last review (3)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Parse quoted Cache-Control values before filtering directives

src/​utils/​agentCacheHeaders.ts:33

Splitting Cache-Control on every comma does not respect quoted extension values. For example, the valid header foo="a,s-maxage=10", max-age=60 is split so that part of the quoted value is mistaken for the real s-maxage directive and removed, leaving a corrupted header. Parse commas only when they are outside quoted strings before filtering directives.

Medium severity Handle If-None-Match wildcard without requiring an ETag

src/​utils/​agentCacheHeaders.ts:46

If-None-Match: * matches any existing representation even when that representation has no ETag. Requiring etag !== null here makes a cached 2xx response without an ETag return 200 instead of 304. Handle the wildcard before applying the ETag-presence requirement.

@Orkuncakilkaya
Orkuncakilkaya marked this pull request as ready for review September 24, 2026 12:05
…atch

Remove s-maxage handling and restore the 60s edge TTL, since the staging origin doesn't send s-maxage.
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Following releases will be created using changesets from this PR:

fastly-compute-proxy@0.4.2

Patch Changes

  • Updated agent endpoint response to reset age and drop cache-tag on cache hits, and to answer If-None-Match with 304 (c186ae8)

This branch has not been deployed

No deployments
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.

2 participants