Thayne
Thayne

Reputation: 6992

S3 CORS, always send Vary: Origin

I am using an S3 bucket behind Cloudfront with CORS enabled. If the client makes a request with the Origin header, then S3 (and cloudfront) respond with a "Vary: Origin" header, however if the request is made without the Origin, header then the response does not contain any Vary Header.

This is problematic because I use a resource from cloudfront/s3 in an img tag, in which case the browser makes the request without the Origin header, and then later make an ajax request for said image. The browser then uses the cached version of the image, without the Access-Control-Allow-Origin header, and therefore denies the request.

Is there any way to get S3 to always return the "Vary: Origin" header?

Upvotes: 28

Views: 11319

Answers (3)

Jan M
Jan M

Reputation: 2225

I stumbled on an easy way to make Cloudfront always add a "Vary: Origin" header, albeit undocumented as far as I can tell: You can force the "Vary" header by including "Origin" in the CloudFront cache key.

On the Cloudfront distribution click "Edit behaviour", find the heading "Cache key and origin requests". If you are using "Legacy cache setting" click select "Origin" under "Add header". If you use the newer Cache policy then you need to click "Create policy" and add the Origin under "Cache key settings", then go back and use the policy you just created.

My use case is HMTL5 video subtitle tracks that don't send an Origin if you use crossorigin="anonymous", and if there is no Origin, there is no Vary: Origin.

Upvotes: 1

Kristian Hanekamp
Kristian Hanekamp

Reputation: 2489

Another solution would be configuring your CloudFront distribution to automatically turn Non-CORS requests into CORS requests. This is possible by adding a CORS header to each request CloudFront sends to S3 using the recently added CloudFront feature "Control Edge-To-Origin Request Headers".

See the feature announcement here: https://aws.amazon.com/blogs/aws/cloudfront-update-https-tls-v1-1v1-2-to-the-origin-addmodify-headers/

And the documentation here: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/forward-custom-headers.html.

Upvotes: 15

drdrek
drdrek

Reputation: 527

I made an account just to answer your question, because there are very few good answers around for this kind of problem (and a few related ones).

The problem you describe happens for some reason primarily in chrome, FF and IE seems to be smart enough not to share cache between AJAX and regular calls in these instances.

The Problem

Lets first describe why the problem happens for future readers:

  • Browser (Chrome) ask the server using a regular <img> or <script> tag. If the server is in the same domain it does not includes an CORS headers.
  • Server (S3) returns the resource. If no Origin header was present in the request it does not attach CORS headers in the reply as they are redundant.
  • Browser (Chrome) try and get the resource again using AJAX, but this time doesn't really go to the server but looks at the cached resource.
  • Browser (Chrome) The cached version does not have CORS headers. It will drop the request as Access-Control-Allow-Origin violation or other related problems.

The solution

In HTML5 there is an attribute called crossorigin that can be added to tags to signify that they need to send origin information. Possible values are crossorigin='anonymous' and crossorigin='use-credentials' these are quite irrelevant to the question asked but as it says in the documentation:

By default (that is, when the attribute is not specified), CORS is not used at all.

https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes

So just create your image tags like this <img src='cloundfront.path' crossorigin='use-credentials'>

Thats it. Its quite obscure so I hope that this answer saves some research time to a bunch of people.

Upvotes: 40

Related Questions