New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 409090 link

Starred by 36 users

Issue metadata

Status: WontFix
Owner: ----
Closed: Sep 2014
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 2
Type: Bug



Sign in to add a comment

Cross-origin request from cache failing after regular request is cached.

Reported by thib...@artillery.com, Aug 29 2014

Issue description

UserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36

Example URL:
http://jsfiddle.net/5g8spmec/7/

Steps to reproduce the problem:
Here a jsFiddle with a 100% repro (open your console): http://jsfiddle.net/5g8spmec/7/

Basically: 
1. Fetch a cross origin image without the crossorigin='anonymous' attribute or via CSS to start a regular fetch without CORS headers
2. Wait for the image to be downloaded and cached.
3. Start the same request but with crossorigin='anonymous'
4. Chrome will fetch from cache, but the CORS headers won't be cached due to the first regular request.
5. This will result in a CORS error on the second fetch. 

What is the expected behavior?
In Firefox and IE, the second request works just fine, and if you load the jsFiddle you'll see two images per row, when firefox will display a `broken image` icon on the second image of each row.

What went wrong?
The second request (with crossorigin='anonymous') will test against the wrong cached headers due to the first request.

Did this work before? No 

Chrome version: 37.0.2062.94  Channel: stable
OS Version: OS X 10.9.4
Flash Version: Shockwave Flash 14.0 r0

I was able to repro on Chrome 36+ on both OSX and Win8.
This works fine in Firefox and IE11.
 
This also works fine in Safari and seems to affect all Chrome versions on every OSes I could try.
Cc: jgraettinger@chromium.org gavinp@chromium.org rvargas@chromium.org
Labels: Cr-Internals-Network-Cache
Status: Untriaged
Thanks for the report and a great repro case.

Labels: -Cr-Internals-Network-Cache Cr-Blink-Loader
Labels: -Cr-Internals-Network

Comment 5 by kbr@chromium.org, Aug 30 2014

Cc: japhet@chromium.org kbr@chromium.org abarth@chromium.org
Labels: -OS-Mac OS-All
Cc: cbiesin...@chromium.org
For the <img> case, I would have expected the fix for  http://crbug.com/341047  to trigger a reload. But perhaps behavior has changed subsequently.
This is due to resource caching external to Blink: the image coming back for the initial non-CORS image fetch has a one year max age. When the next CORS-enabled fetch is made (which is handled correctly wrt CORS, setting up Origin: as reqd), the memory cache is correctly not consulted, issuing another async request instead. That request gets cached data in the response, which is without Origin:, hence CORS access check failure. No image.

A forceful Blink-side fix would be to bust the cache on that second reload (using LOAD_BYPASS_CACHE or LOAD_VALIDATE_CACHE), but it would be a workaround for the http cache not being able to discriminate between a No-CORS resource and a CORS-enabled request for same.
I don't really know how Firefox and IE handle the case, but it seems to work just fine on those browsers.
Cc: davidben@chromium.org
All very reasonable to expect that it should work :)

https://codereview.chromium.org/528283002/ causes the external cache's contents to be disregarded in case there's a "CORS attribute mismatch" wrt memory cache contents. But if the browser-side cache has an entry for the URL without it being in the memory cache, we're not better off, so this would only be a partial solution/workaround.

I can't see the net/http cache keeping track of Origin: on cached resources, and handling that appropriately, but perhaps there are enough hooks to make it do so? If not, is there an existing bug on that already?
I believe that endpoint is actually misbehaving. I'm not sure if IE and Firefox are doing something special here (separate caches? blanket-assuming servers get it wrong and that Origin is always implicitly in Vary?), but there is a different set of response headers depending on whether or not the Origin header is present, which means that Origin needs to be in the Vary header.

And, indeed, the CORS-enabled response does include Origin, among other headers, in Vary. But the non-CORS response does not. And so the cache is responding with the cached response since it's still valid for the new request.

The CORS spec actually explicitly calls this out in a similar case, where the contents of Access-Control-Allow-Origin differ depending on the value of the Origin header:

http://www.w3.org/TR/cors/#resource-implementation

(Dunno if we should do some workaround like blanket-assuming servers are broken and always including Origin in Vary. I'm sure this is not the only such server and this is not an easy bug to diagnose, but it may cause us to cache things much worse; we'd never be able to share cache between origins for any request types which are always CORS-enabled. Worse, because we only ever store one cached response per resource, switching between origins on such a resource would dump the other's cached copy.)
https://bugs.webkit.org/show_bug.cgi?id=63090 is an older bug on the topic.

It'd be useful to know the logic that others use.
According to FF folks, the reason why the 2nd "crossorigin=anonymous" request works out is that the no cookie requirement is effectively included in the cache key, avoiding reuse that way.

If you change the test to use "crossorigin=use-credentials", you'll see the same behavior for both FF and Chromium-based browsers. FF will fare no different if a downstream (proxy?) cache has an entry for this resource without a "Vary:Origin".

Adding that to the endpoint's config seems the best&preferable action here.

Comment 13 by br...@compcc.com, Sep 15 2014

This same issue (I think) impacted us w/ Chrome 37 and the new requirement for CORS headers on web font loads. We have a site that uses web font X and 3rd-party content that references web font X (both refer to the same URL for the web font). The idea is to avoid reloading the web font on 3rd-party content load. Unfortunately, because the "first" load of the web font is by same-origin, the cache is consulted & fails on subsequent reference from 3rd-party content because of missing CORS headers. 3rd-party requests for the font *do* return CORS headers.

Our current workaround is to send CORS headers on the font load, even from same-origin, so that the cached resource has the right headers when Chrome references it in the 3rd-party load. But, this was a custom hack - the platform plugins we use for CORS had to be modified to send CORS headers without an Origin: present in the request (which it isn't for GET on same-origin). It's not ideal and it was a real PITA to debug because Chrome wasn't making it obvious at all that the error / cancelled CORS request was because of missing headers in the cached resource.

If folks think this is different because of the nuances of this bug w/r/t image loads, I can open a new issue.

Thanks!
Yeah, making your page send CORS headers whether or not there is an Origin header is probably correct here. HTTP caches cache headers as well as response body. To interact with caches correctly, you need to either document that you are sensitive to the Origin header in Vary or avoid being sensitive to it. In your case, since you want to avoid reloading the font in the 3rd-party case, you should avoid being sensitive to it.

I agree this should be easier to debug, but I think Chrome's behavior itself is fine.
Status: WontFix
I think there is agreement that the current behavior is correct.
Thanks! 
We'll look into it and keep you updated.
 Issue 421783  has been merged into this issue.
Cc: horo@chromium.org jkarlin@chromium.org
 Issue 422171  has been merged into this issue.
 Issue 421783  has been merged into this issue.
 Issue 421783  has been merged into this issue.
 Issue 558252  has been merged into this issue.

Comment 22 Deleted

This is not correct behavior. You would never expect the browser to function like this. Additionally, Chrome is alone in acting this way.

If you use a canvas to create a screenshot of the current web page, when you flip the visible images to be crossorigin, because of this bug the canvas will be tainted. This can take a day or more to debug.
See comments elsewhere in the thread. HTTP caching requires that servers declare all request headers they are sensitive to in the Vary header. That's just how HTTP works. What is the server doing that one of the options discussed elsewhere in this thread isn't feasible?
It took me hours to figure out that my CORS error was cache related.

Comment 26 by ch...@kalohq.com, Jul 12 2017

Might this issue be related? Seems pretty gnarly without a clear path to avoiding the issue.

https://stackoverflow.com/questions/44800431/caching-effect-on-cors-no-access-control-allow-origin-header-is-present-on-th
That could definitely be related.

If a standard or RFC states that this is correct behavior, perhaps the standard needs to be changed because it's unexpected to say the least.

Sign in to add a comment