34

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".

Racil Hilan
  • 24,690
  • 13
  • 50
  • 55
Wes
  • 351
  • 3
  • 5
  • What browser are you using? Does this behavior occur in all browsers? This sounds like a browser bug. The query parameter solution you propose sounds like a good workaround. – monsur Sep 19 '12 at 16:36
  • added "edit: Fails in both safari 5.1.6 and chrome 21.0.1180.89. Works fine in firefox 14." – Wes Sep 19 '12 at 16:49
  • 1
    Probably a WebKit bug then. This sounds like the same issue: https://bugs.webkit.org/show_bug.cgi?id=63090 The bug suggests that adding the header "Vary: Origin" may address the issue. – monsur Sep 19 '12 at 18:38
  • 3
    The problem has also been reported on the [AWS S3 Forums](https://forums.aws.amazon.com/thread.jspa?messageID=555417򇦙) – Kristian Hanekamp Oct 23 '15 at 13:21

5 Answers5

9

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.

Thayne
  • 6,619
  • 2
  • 42
  • 67
6

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.

Gernot Raudner
  • 814
  • 7
  • 21
3

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.

Community
  • 1
  • 1
Kristian Hanekamp
  • 2,429
  • 1
  • 21
  • 13
2

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.

Talia
  • 1,400
  • 2
  • 10
  • 33
0

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

jcoffland
  • 5,238
  • 38
  • 43