Closed Bug 1302119 Opened 8 years ago Closed 8 years ago

fetch() does not respect cache-control headers

Categories

(Core :: Networking: Cache, defect)

48 Branch
defect
Not set
normal

Tracking

()

RESOLVED DUPLICATE of bug 428916

People

(Reporter: mjs, Unassigned, NeedInfo)

Details

Attachments

(1 file)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:48.0) Gecko/20100101 Firefox/48.0
Build ID: 20160817112116

Steps to reproduce:

Firefox seems to ignore cache-control headers passed to fetch(). As an example:

1. Load https://www.mozilla.org/en-US/.
2. Attempt to retrieve "/en-US/" over the network (avoiding cache) via:

fetch(new Request("/en-US/", { headers: { "cache-control": "no-cache" }})).then(r => console.log(r));


Actual results:

The path /en-US/ is retrieved from the cache.


Expected results:

A new network request is issued for "/en-US/". (Which is how Chrome behaves.)

(I am aware that Firefox supports the cache: no-cache option, which in this case accomplishes the same thing, however I think it should respect the cache-control header as well.)
reproducible
Version 	48.0.1
Build ID 	20160817112116
User Agent 	Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:48.0) Gecko/20100101 Firefox/48.0
Status: UNCONFIRMED → NEW
Component: Untriaged → Networking: Cache
Ever confirmed: true
Product: Firefox → Core
The server for `https://www.mozilla.org/en-US/` does not provide either of these headers:

  Last-Modified:
  Etag:

Because of this the browser cannot send either the If-Modified-Since or If-None-Match none matched headers.  As a result the server cannot revalidate the resource.  (The 'no-cache' header value means to revalidate.)  So the server just returns the complete file.

If you do the same thing on a site that does support revalidation then it works correctly.  For example, go open `http://example.com` in a new tab.  Then execute these statements:

fetch(new Request("/", { headers: { "cache-control": "default" }})).then(r => console.log(r));
fetch(new Request("/", { headers: { "cache-control": "no-cache" }})).then(r => console.log(r));
fetch(new Request("/", { headers: { "cache-control": "no-store" }})).then(r => console.log(r));

In the network monitor you should see:

* A cached 200 load (since you just navigated to the site)
* A 304 because the no-cache requests revalidation and nothing changed
* A full network 200 load because no-store says to bypass the cache

Does this work for you?
Flags: needinfo?(mjs)
feel free to reopen if this isn't resolved in firefox 49 but I'm pretty sure its a dup of a fixed issue
Status: NEW → RESOLVED
Closed: 8 years ago
Resolution: --- → DUPLICATE
bkelly:

Sorry, I didn't quite follow your comment.

I was not expecting requests with "cache-control: no-cache" to ever be fulfilled by the cache, as per

https://tools.ietf.org/html/rfc7234#section-5.2.1.4

Chrome and Safari Preview seem to revalidate in this situation however Firefox does not. (Also verified by running a server on localhost.)

> A 304 because the no-cache requests revalidation and nothing changed

I was expecting a 200 in this situation.

> A full network 200 load because no-store says to bypass the cache

This is separate to this bug, but my reading of https://tools.ietf.org/html/rfc7234#section-5.2.1.5 is that a cached response could actually be used in this situation (see the final paragraph) and both Chrome and Safari do appear to use a cached response in this situation.

(Keeping this bug resolved as a dupe of bug 428916 seems fine, though.)
> I was not expecting requests with "cache-control: no-cache" to ever be
> fulfilled by the cache, as per
> 
> https://tools.ietf.org/html/rfc7234#section-5.2.1.4

That states:

" The "no-cache" request directive indicates that a cache MUST NOT use a stored response to satisfy the request without successful validation on the origin server."

The part about "without successful validation on the origin server" is satisfied by a 304 response.  In that case the browser can use the cached version.

> Chrome and Safari Preview seem to revalidate in this situation however
> Firefox does not. (Also verified by running a server on localhost.)

Do these browsers send a If-Modified-Since or If-None-Match header?  If so, where are they getting the value?

It's possible they are setting If-Modified-Since based on when they cached it, but this is dangerous since the client clock may not match the server clock 

> > A 304 because the no-cache requests revalidation and nothing changed
> 
> I was expecting a 200 in this situation.

No, sine we have a Last-Modified header on the cached resource we can send an If-Modified-Since to revalidate.  This results in a 304 indicating no change.

> > A full network 200 load because no-store says to bypass the cache
> 
> This is separate to this bug, but my reading of
> https://tools.ietf.org/html/rfc7234#section-5.2.1.5 is that a cached
> response could actually be used in this situation (see the final paragraph)
> and both Chrome and Safari do appear to use a cached response in this
> situation.

I agree the RFC allows it, but it doesn't appear to require it.  Our implementation more closely matches the fetch spec's definition of no-show:

https://fetch.spec.whatwg.org/#concept-request-cache-mode
> > > A 304 because the no-cache requests revalidation and nothing changed
> > I was expecting a 200 in this situation.
> No, sine we have a Last-Modified header on the cached resource we can send an If-Modified-Since to revalidate.  This results in a 304 indicating no change.

By "send an If-Modified-Since to revalidate" do you mean a network request? Provided the cached response satisfies max-age and other constraints, Firefox doesn't appear to send anything to the server in the "cache-control: no-cache" situation, conditional or not--it just used the cached response.

I also don't see any 304s in the Network panel, only cached and uncached 200s. (See attachment. The "/" resource had a max-age of 60s, and the third request was issued after 60s, so it went through to the origin, resulting in an uncached 200.)

I understood the "successful validation on the origin server" condition of 5.2.1.5 to mean that the client could only use a cached response if it issued a network request to the origin, and the origin returned a 304. Otherwise is there even any difference between no-cache and no cache-control directive?
Attached image Three Fetches
Try in FF49+ where bug 428916 is fixed.
bkelly: it works as I was expecting it to in Firefox Nightly, thanks!
Great!  FF49 should be released next week, so not long to wait.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: