Skip to content

Fix HttpServerConnection ETag check to use If-None-Match - #3033

Merged
slaff merged 1 commit into
SmingHub:developfrom
94xhn:fix/httpserver-etag-if-none-match
Jul 20, 2026
Merged

Fix HttpServerConnection ETag check to use If-None-Match#3033
slaff merged 1 commit into
SmingHub:developfrom
94xhn:fix/httpserver-etag-if-none-match

Conversation

@94xhn

@94xhn 94xhn commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

The ETag caching in HttpServerConnection::sendResponseHeaders() returns 304 Not Modified when the If-Match request header matches the response ETag. That's the wrong header for this - If-Match is for optimistic-concurrency checks on writes (RFC 7232 §3.1), not for cache revalidation. The header a normal browser sends when revalidating a cached GET is If-None-Match, and that one isn't handled at all.

It goes a bit deeper than just checking the wrong constant, too: HttpHeaderFieldName/HTTP_HEADER_FIELDNAME_MAP in HttpHeaderFields.h never had an entry for If-None-Match in the first place. Without an entry in the table, an incoming If-None-Match header falls through to the custom-field path in HttpHeaderFields::fromString()/findOrCreate() and gets stored under its own dynamically-allocated field id, completely separate from HTTP_HEADER_IF_MATCH. So request.headers.contains(HTTP_HEADER_IF_MATCH) was always false for a request that only carries If-None-Match, and the 304 path could basically never be reached by a real client - only by something that deliberately sends If-Match on a GET, which isn't standard browser behavior.

Fix: add an IF_NONE_MATCH entry to the header field map, and switch the check in HttpServerConnection.cpp to use it instead of IF_MATCH.

I confirmed the logic by porting the field-table lookup and the 304 condition (unchanged) into a small standalone program and running both the old and new versions: with the current code, a request carrying only If-None-Match never triggers 304; with the fix it does, and a bare If-Match no longer incorrectly triggers 304 on a GET. I didn't spin up the full Sming Host build for this (submodules like FlashString aren't initialized in my checkout), so I can't point to an in-tree test run, but the header-matching code path itself is unchanged from upstream in the repro.

sendResponseHeaders() was checking the If-Match request header to
decide whether to return 304 Not Modified for a cached GET/HEAD, but
If-Match is for optimistic-concurrency writes (RFC 7232 3.1), not
cache revalidation. Real browsers send If-None-Match when revalidating
a cached resource, so this code path never actually returned 304 for
normal traffic - HTTP_HEADER_IF_NONE_MATCH wasn't even defined, so the
header got stored as a custom field and request.headers.contains(HTTP_HEADER_IF_MATCH)
was always false for it.

Added an If-None-Match entry to the header field map and switched the
304 check to use it, matching the conditional GET semantics in RFC 7232.
@what-the-diff

what-the-diff Bot commented Jul 20, 2026

Copy link
Copy Markdown

PR Summary

  • Introduced a New HTTP Header
    A new HTTP header field called If-None-Match has been added. This is typically used by web browsers and servers for effective cache revalidation, ensuring the optimal use of network resources by trying to avoid unnecessary data transfers.

  • Modification in Conditional Check
    The existing control flow in the server connection module has been tweaked. Now, it uses the new If-None-Match header field instead of the If-Match to ascertain if a website resource has been updated. This change can enhance the data accuracy provided to the users and may reduce server load by limiting the transfer of unchanged content.

@slaff slaff added this to the 6.3.0 milestone Jul 20, 2026
@slaff
slaff self-requested a review July 20, 2026 07:53
@slaff
slaff merged commit 98cfa68 into SmingHub:develop Jul 20, 2026
30 checks passed
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