- From: Patrick Meenan <patmeenan@gmail.com>
- Date: Thu, 5 Mar 2026 22:10:25 -0500
- To: Michael Toomim <toomim@gmail.com>
- Cc: HTTP Working Group <ietf-http-wg@w3.org>, Braid <braid-http@googlegroups.com>
- Message-ID: <CAJV+MGw2JXTJBkggLqr13mg0XQdk2gWJ+-tpGR+9MHx7tJU9DQ@mail.gmail.com>
Most of what you are describing is outside the scope of HTTP-proper (except
for the actual caching of the responses) and is in the browser's fetch spec
implementation before it hits HTTP.
When you leave the response open as a stream, do you send an initial
response with headers and just never finish it or do you leave the request
hanging until there is data to send?
How are the response headers varied? Specifically, what are the headers
used for the HTML response? The reason I ask is that the client has to make
its decision to fetch or not based 100% on any headers on the cached entry
and has no idea what the second set of headers will be.
Do the requests have the same URLs? How does the server differentiate
between "first" and "second"? How does it handle any prefetch requests the
browser might be sending?
A Chrome netlog will help show what Chrome is doing (I'm happy to look if
you collect one):
https://www.chromium.org/for-testers/providing-network-details/
The 20-second delay could well be the request de-duplication timeout where
Chrome will hold additional requests for identical URLs to make sure they
aren't for the same static resource (instead of wasting bandwidth
downloading the same thing twice). It should be able to make that
determination as soon as the headers are complete though and not have to
wait for the response to end.
You have some level of control over this on the javascript side if you know
what you are fetching shouldn't go through the cache:
https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#cache
i.e. fetch('/foo', cache: 'no-store') will skip checking or writing to the
cache at request time.
On Thu, Mar 5, 2026 at 6:23 PM Michael Toomim <toomim@gmail.com> wrote:
> Hello HTTPers!
>
> We've been experimenting with using fetch() to open a streaming HTTP
> response from the same URL that a page loads from. Specifically, the page
> loads at /foo, then its JavaScript does a fetch() back to /foo with the
> response left open as a stream. We've discovered some strange browser
> quirks that we'd appreciate the WGs input on.
>
> We wrote up a detailed test case with reproduction steps, results
> matrices, and videos here:
>
> https://braid.org/meeting-108/cache-quirks
>
>
> The test server varies Cache-Control headers (no-cache, no-store, none)
> across the initial page load and the streaming fetch, creating 5
> experimental conditions. We tested on Chrome 145, Safari 26.3.1, and
> Firefox 148.0. Here's a summary of what we found:
>
> *Quirk 1: Cached page content returned instead of stream data.* When a
> tab is closed and restored (e.g. Shift-Cmd-T), the second fetch() returns
> the cached HTML of the page itself rather than the streamed response from
> the server. This affects Chrome, Safari, and Firefox on most endpoints.
> Setting Cache-Control: no-store on the initial page load fixes it in
> Chrome and Safari, but not Firefox.
>
> *Quirk 2: 20-second delay before anything renders.* In Chrome, opening a
> second tab to the same URL causes the page itself to hang for precisely 20
> seconds before loading. (Not just the inner fetch. Nothing renders at all.)
> Safari handles this fine. Setting no-store on the streaming fetch (or both
> requests) resolves it for Chrome, but Firefox recognizes no stream data at
> all in this scenario.
>
> The exact 20-second duration suggests this may be Chrome's cache lock
> timing out — perhaps Chrome is blocking a second request to the same URL
> while waiting for the first (streaming) response to become cacheable, and
> gives up after 20 seconds. (In HTTP/2 setups, a similar 20-second delay can
> occur from the SETTINGS frame acknowledgment timeout, but our test case is
> plain HTTP/1.1, so cache locking seems the more likely culprit here.)
>
> *Quirk 3: Streaming fetch hangs indefinitely.* In Firefox 148.0, the
> streaming fetch() now hangs forever on all endpoints, regardless
> of Cache-Control settings. This appears to be a regression — previously
> only some no-store configurations triggered the hang, and it required
> opening a second tab. Now it occurs even on first load. Chrome and Safari
> are unaffected.
>
> We'd appreciate the WG's guidance on what the expected behavior should be
> in these cases. In particular:
>
>
> - Should the cache be allowed to serve the initial page's response
> body for a subsequent fetch() to the same URL when the requests carry
> different headers?
> - Is Chrome's 20-second blocking behavior a cache lock, and does the
> spec allow for this behavior? Should a streaming response that
> hasn't completed block other requests to the same URL?
> - Is there something in the spec that would explain or allow for
> Firefox's hanging behavior with streaming responses?
>
>
> Thanks for any insight!
>
> Michael
>
Received on Friday, 6 March 2026 03:10:40 UTC