Skip to content

Conversation

@GroophyLifefor
Copy link
Member

Respect the Cache-Control: no-store directive by skipping ETag generation when this header is present.

Changes:

  • Modified res.send() to check for Cache-Control header containing no-store directive (case-insensitive)
  • ETag is no longer generated if no-store is present in Cache-Control
  • Added 5 comprehensive test cases covering:
    • Basic no-store directive
    • no-store with other cache directives
    • Case-insensitive matching
    • Other directives without no-store (still generates ETag)
    • Absence of Cache-Control header (still generates ETag)

This ensures compliance with HTTP caching specifications where no-store prohibits storing the response.

Issue: #2472
Review wanted to @bjohansebas

Copy link
Member

@jonchurch jonchurch left a comment

Choose a reason for hiding this comment

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

This ensures compliance with HTTP caching specifications where no-store prohibits storing the response.

This is not accurate as written. This PR is a perf optimization not a spec alignment. ETAGs can always be sent, Cache-Control: no-store just makes them useless to the client.

Do we have benchmark data showing if this creates a meaningful impact? We pay for a (fast) header check on every response to see if we can save the (also fast) hashing of the body.

@GroophyLifefor
Copy link
Member Author

I don't think it makes meaningful impact but I'll look asap.

@bjohansebas
Copy link
Member

We should also review what Doug had mentioned, i haven’t done my investigation on this yet.

#2473 (comment)

@GroophyLifefor
Copy link
Member Author

This ensures compliance with HTTP caching specifications where no-store prohibits storing the response.

This is not accurate as written. This PR is a perf optimization not a spec alignment. ETAGs can always be sent, Cache-Control: no-store just makes them useless to the client.

Do we have benchmark data showing if this creates a meaningful impact? We pay for a (fast) header check on every response to see if we can save the (also fast) hashing of the body.

Phase First Run (ns) Second Run (ns) Ratio (First / Second)
Total 201,100 161,000 1.25
Determine 1,800 4,300 0.42
Populate 15,900 6,500 2.45
ETag 32,400 300 108

Based on mine measurements, the optimization reduces res.send from ~0.20 ms to ~0.16 ms per request. So it does improve performance, mainly by removing ETag computation, but the overall impact is very small that around 0.04 ms per response.

@krzysdz
Copy link
Contributor

krzysdz commented Jan 19, 2026

We should also review what Doug had mentioned, i haven’t done my investigation on this yet.

#2473 (comment)

Doug's comment is probably based on the no-store description from RFC 7234. RFC 7234 was obsoleted in 2022 by RFC 9111, which introduced changes to this section (text in bold is new):

The no-store response directive indicates that a cache MUST NOT store any part of either the immediate request or the response and MUST NOT use the response to satisfy any other request.

I have looked at Firefox source code and it looks like no-store responses are cached (in memory), but only to enable back-forward navigation, "save as", "print", "view page source", etc. [1, 2, 3, 4, 5]. While, like Doug has said, the BF cache requires validation of no-store cached responses, no requests are made for no-store content. The ETag is checked only if doValidation is false, so it is skipped when no-store is used.

Based on this, I'd say that ETag is not necessary, but RFC 9111 introduced one more change. At the end of no-store section there is a new paragraph:

Note that the must-understand cache directive overrides no-store in certain circumstances; see Section 5.2.2.3.

The Section 5.2.2.3. must-understand says:

The must-understand response directive limits caching of the response to a cache that understands and conforms to the requirements for that response's status code.

A response that contains the must-understand directive SHOULD also contain the no-store directive. When a cache that implements the must-understand directive receives a response that includes it, the cache SHOULD ignore the no-store directive if it understands and implements the status code's caching requirements.

If I understand this correctly, no-store can be ignored when combined with must-understand and then probably ETag might be useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants