Fix full-page cache handling for HTTP HEAD requests
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 5
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
Problem
The full-page cache treats HEAD as cacheable, but a cache hit emits the cached HTML body and exits. HTTP HEAD responses must have the same headers as GET without a message body. Sending the body wastes bandwidth and can confuse monitors, crawlers, and reverse proxies that use HEAD for freshness checks.
Evidence
src/Modules/Cache/PageCache.php:962-966allows bothGETandHEADrequests through the cacheability gate.src/Modules/Cache/PageCache.php:161-176emits$htmlfor both a fresh hit and a stale hit without checking the request method.- The existing page-cache tests do not cover fresh, stale, or lock-stale
HEADresponses.
Scope
Correct HEAD behavior in the local page-cache path while preserving cache keys, HIT/STALE headers, invalidation, and GET behavior.
Implementation plan
- Introduce one request-method helper and use it consistently in cacheability and cache-response delivery.
- On fresh, stale, and stale-lock hits, send the same cache state headers as
GETbut return no body forHEAD; include a correctContent-Lengthonly when it is safe to provide it. - Decide and document the miss behavior so a
HEADrequest never writes or emits a body unexpectedly. - Keep internal regeneration and preload requests on their existing
GETpath. - Add focused PHPUnit coverage for fresh HIT, STALE, and STALE-LOCK
HEADrequests and for an unaffectedGETHIT.
Acceptance criteria
- A cached
HEADrequest returns the expectedX-Perform-Cachestate and an empty body. - A
GETrequest for the same cache key still returns the cached body unchanged. HEADnever creates a cache entry or changes cache freshness state as an unintended side effect.- Fresh, stale, and lock-contention paths are all covered by regression tests.
Validation
composer testcomposer phpstan- PHPCS on changed PHP files
- Isolated WordPress runtime proof: warm a page with
GET, then compareGETandHEADstatus, headers, and response byte count.
Non-goals and risk
- Do not broaden page-cache invalidation; issue #197 and PR #199 own lifecycle invalidation.
- Do not alter cache keys, TTLs, Cloudflare behavior, or public settings.
- Preserve HTTP compatibility for proxies that issue
HEADrequests.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/Modules/Cache/PageCache.php, especially lines 161-176 for cache-hit delivery and 962-966 for the cacheability gate. Trace fresh, stale, stale-lock, miss, and internal regeneration paths, then add focused PHPUnit coverage for HEAD and unaffected GET behavior. Done means HEAD preserves cache-state headers with no body while GET, invalidation, and cache freshness behavior remain unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- backend, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100