Skip to content

Drop If-None-Match tokens the server could never have issued - #204

Merged
koriym merged 1 commit into
bearsunday:1.xfrom
koriym:unpoolable-validators
Aug 29, 2026
Merged

Drop If-None-Match tokens the server could never have issued#204
koriym merged 1 commit into
bearsunday:1.xfrom
koriym:unpoolable-validators

Conversation

@koriym

@koriym koriym commented Aug 29, 2026

Copy link
Copy Markdown
Member

Closes #202 (#202).

EntityTags::of() handed every parsed opaque-tag to the ETag pool as a cache key. PSR-6 reserves {}()/\@: in keys, so If-None-Match: "x:y" threw InvalidArgumentException from inside isNotModified() / isNotModifiedFor(): one request header became a 500, and the scoped path logged a cache_error that reads as a pool outage.

No ETag setter can issue such a token (EtagSetter/MobileEtagSetter: crc32 decimal; DevEtagSetter: sanitized URI tag), so it can never match. EntityTags drops it and the request is answered in full. Dropping is per-token: "good", "x:y" still revalidates on "good".

* is dropped for the same reason on top of not being an opaque tag at all - RFC 9110 §13.1.2 gives it existence semantics, tracked separately in #203 (#203). Its observable answer is unchanged (always a full response); the pool just is not asked.

Tests

  • EntityTagsTest: the drop contract per grammar (reserved chars, *, per-token dropping, both server-issued grammars pass).
  • HttpCacheTest::testAClientChosenUnpoolableTokenIsAMissNotAnError: the 500 reproduction through both transfer boundaries now answers false, closes as an ordinary miss, and records no cache_error.

A client-chosen token with a PSR-6 reserved character ({}()/\@:) reached
the ETag pool as a cache key and Symfony threw: one request header turned
into a 500, logged as if the pool were down. No ETag setter can emit such
a token - EtagSetter/MobileEtagSetter issue crc32 decimals, DevEtagSetter
the sanitized URI tag - so it can never match, and the honest answer is
an ordinary miss.

EntityTags now drops unpoolable tokens per-token, so a list with one
valid validator still revalidates. `*` is dropped too: it is not an
opaque tag but RFC 9110 §13.1.2 existence semantics, tracked in bearsunday#203.
The observable answer for `*` is unchanged (always a full response); the
pool just is not asked.

Closes bearsunday#202
@koriym

koriym commented Aug 29, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8270ab1e-d4d0-4b78-b031-bbce4da4a757

📥 Commits

Reviewing files that changed from the base of the PR and between 5b11768 and e13c757.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • src/EntityTags.php
  • tests/EntityTagsTest.php
  • tests/HttpCacheTest.php

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change filters client-supplied If-None-Match tokens that cannot be used as PSR-6 cache keys. Tests verify valid-token handling and ordinary cache misses without cache errors. The changelog documents the behavior.

Changes

ETag token filtering

Layer / File(s) Summary
Filter unpoolable ETag tokens
src/EntityTags.php
EntityTags::of() drops * and opaque tags containing PSR-6 reserved characters. It also documents rejection of malformed token syntax.
Validate cache-miss behavior
tests/EntityTagsTest.php, tests/HttpCacheTest.php, CHANGELOG.md
Tests cover token filtering, valid tokens beside invalid tokens, and ordinary misses for both HTTP cache boundaries. The changelog records the behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to e13c7

Invalid client validators now produce a normal full response instead of a server error, while valid validators continue to revalidate normally. No actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 3 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the filtering of invalid If-None-Match tokens, the resulting cache behavior, and the test coverage. It directly relates to the changeset.
Title check ✅ Passed The title clearly and concisely summarizes the main change: removing If-None-Match tokens that the server could not have issued.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 7 functions across 3 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@codecov

codecov Bot commented Aug 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (5b11768) to head (e13c757).

Additional details and impacted files
@@             Coverage Diff             @@
##                 1.x      #204   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
- Complexity       511       513    +2     
===========================================
  Files             97        97           
  Lines           1365      1365           
===========================================
  Hits            1365      1365           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@koriym
koriym merged commit 548ff80 into bearsunday:1.x Aug 29, 2026
20 checks passed
@koriym
koriym deleted the unpoolable-validators branch August 29, 2026 09:52
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.

A client-chosen If-None-Match token with a PSR-6 reserved character turns the request into a 500

1 participant