Wes
Wes

Reputation: 361

Cached non CORS response conflicts with new CORS request

Gist:

I have a page that uses tag loading of an image from s3 (HTML img tag) and I have a page that uses xmlhttprequest. The tag loading gets cached without the CORS headers and so the xmlhttprequest sees the cached version, checks it's headers and fails with a cross origin error.

Details:

edit: Fails in both safari 5.1.6 and chrome 21.0.1180.89. Works fine in Firefox 14.

Using S3's new CORS, I setup a CORSRule as so:

<CORSRule>
  <AllowedOrigin>*</AllowedOrigin>
  <AllowedMethod>GET</AllowedMethod>
  <AllowedMethod>HEAD</AllowedMethod>
  <MaxAgeSeconds>0</MaxAgeSeconds>
  <AllowedHeader>*</AllowedHeader>
</CORSRule>

If I request an image from S3 without setting the origin in the request headers I get back the image without any CORS headers in the response.

This get's cached and subsequent CORS requests (one's that do set the origin in the request header) get rejected as the browser uses the non CORS version form the cache.

What's the best way to solve this? Can I set something so the non CORS version never gets cached? Should I differentiate the CORS requests by appending a ?some_flag to the url of the request?

Ideally I'd have S3 ALWAYS send back the needed CORS headers even if the request doesn't contain "origin".

Upvotes: 34

Views: 6598

Answers (5)

Talia Stocks
Talia Stocks

Reputation: 1410

I ran into this problem, too. I ended up setting up a cloudfront distribution in front of my S3 bucket, and set the Origin Custom Headers options in the Origin Settings section in cloudfront to send Origin: https://example.com to my S3 origin. This causes S3 to always serve the CORS headers, since it always sees the Origin request header. In order to do this, you have to make sure that the Origin header is not whitelisted by any of your cloudfront behaviors.

tl;dr: I told cloudfront to send Origin: https://example.com with every request to my S3 origin, and served my content via cloudfront.

Upvotes: 2

Kristian Hanekamp
Kristian Hanekamp

Reputation: 2489

One solution would be to set the crossorigin='use-credentials' attribute on the img-tag to force the browser to always perform a CORS request, see here: https://stackoverflow.com/a/34496683/725542

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: 3

jcoffland
jcoffland

Reputation: 5430

You could append the img tag using Javascript after making your CORS request.

Upvotes: 0

Gernot Raudner
Gernot Raudner

Reputation: 824

it's definitely not the best way, but you could disable caching of the image request by adding some url parameter to the request. usually, this is done via javascript, e.g.:

var img = document.createElement('img');
img.setAttribute('src', yourRequestUrl + '?d=' + Date.now());
tagToAppendImg.appendChild(img);

this will always force an uncached response, because the date in milliseconds always produces a different URL that the browser doesn't know yet, but i'm uncertain if this solves your problem.

Upvotes: 6

Thayne
Thayne

Reputation: 7012

I ran into the same problem. As @monsur said, the problem is that S3 doesn't set teh "Vary: Origin" header, even though it should. Unfortunately, as far as I know there is no way to get S3 to send that header. However, you can work around this by adding a query string paramater to the request such as ?origin=example.com when you need CORS. The query string forces the browser not to use the cached resource.

Ideally, cloudfront and S3 would send the Vary:Origin header when CORS is enabled and/or Webkit would implicitly vary on the Origin header, which I assume Firefox does since it doesn't have this problem.

Upvotes: 9

Related Questions