As far as I am able to tell, the only configuration which should be necessary to get s3 to return the Access-Control-Allow-Origin header is setting a CORS policy and sending the Origin header.
Here is my CORS policy:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
When I send this request:
GET /dots.png HTTP/1.1
Host: dta-test.s3.amazonaws.com
Origin: https://www.test.com
Cache-Control: no-cache
I get a response with these headers:
Accept-Ranges →bytes
Cache-Control →public
Content-Length →893
Content-Type →image/png
Date →Thu, 09 Jan 2014 22:27:20 GMT
ETag →"5345e98a3abcb1057d1a427551d8d702"
Last-Modified →Thu, 09 Jan 2014 19:27:56 GMT
Server →AmazonS3
x-amz-id-2 →2AFNGowXCkLUJa09ZNERXqzxn5IwnygTKCXut0m0gvpapjxXn/kAPYQNvv4pYvVy
x-amz-request-id →71B183AF938A075D
As far as I am aware, the Access-Control-Allow-Origin header should be included in this response. What am I missing?
Edit:
This is what I'm missing: I was using the Postman Chrome extension. Chrome sanitizes the Origin header when making requests, even from extensions. It throws the error Refused to set unsafe header "Origin", which I missed.
We can see with curl that this is actually working:
curl -H "Origin: https://www.test.com" -I "https://dta-test.s3.amazonaws.com/dots.png" -s
HTTP/1.1 200 OK
x-amz-id-2: NnRAOdCOpMCtZ8Jk1bpnuRASb0K/gzM0Vv/6D28C6grcbEZoe2OC0cuu3SMwDaXe
x-amz-request-id: 70110890812CAC58
Date: Thu, 09 Jan 2014 23:03:41 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
Cache-Control: public
Last-Modified: Thu, 09 Jan 2014 19:27:56 GMT
ETag: "5345e98a3abcb1057d1a427551d8d702"
Accept-Ranges: bytes
Content-Type: image/png
Content-Length: 893
Server: AmazonS3
Related
I'm using RestSharp to interface with the Auth0 and Sisense APIs. Everything's working fine except when deleting a user in Auth0. I send the delete request as a DELETE and Auth0 successfully deletes the user.
Here is the response I'm getting from Auth0:
HTTP/1.1 204 No Content
Date: Wed, 19 Feb 2020 16:35:28 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Server: nginx
ot-tracer-spanid: 21cd87957d9bac76
ot-tracer-traceid: 25a636cb6e5fd4ca
ot-tracer-sampled: true
x-ratelimit-limit: 50
x-ratelimit-remaining: 49
x-ratelimit-reset: 1582130129
vary: origin,accept-encoding
cache-control: no-cache
Strict-Transport-Security: max-age=15724800
X-Robots-Tag: noindex, nofollow, nosnippet, noarchive
And here's what I'm getting in the RestSharp response:
System.Runtime.Serialization.SerializationException: Invalid JSON string
at RestSharp.RestClientExtensions.ThrowIfError(IRestResponse response)
at RestSharp.RestClientExtensions.DeleteAsync[T](IRestClient client, IRestRequest request)
I'm making a call to a Sisense web service and RestSharp is handling the 402 just fine. Here's the Sisense response:
HTTP/1.1 204 No Content
Date: Wed, 19 Feb 2020 16:32:14 GMT
Connection: keep-alive
Set-Cookie: sisense-cookieCORS=***************************; Path=/; SameSite=None; Secure
Set-Cookie: sisense-cookie=***************************; Path=/
X-UA-Compatible: IE=Edge
x-xss-protection: 1; mode=block
x-frame-options: ALLOW-FROM https://****************************************************
content-security-policy: frame-ancestors ****************************************************
Cache-Control: private, no-cache, no-store, must-revalidate
Expires: -1
Pragma: no-cache
The main difference between the two is the Content-Type directive present in Auth0. Is that what's causing the problem? Is there a workaround?
For some reason I don't get Accept-Ranges in s3 response parameters. Example curl headers response:
HTTP/1.1 200 OK
x-amz-id-2: ***
x-amz-request-id: ***
Date: Thu, 24 Oct 2019 12:40:51 GMT
Last-Modified: Thu, 24 Oct 2019 10:35:55 GMT
ETag: "770dc36e888906bfc63641cbaf7775ce"
Content-Type: application/octet-stream
Content-Length: 1846218
Server: AmazonS3
Any ideas why? Also I have CORS setuped as that:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<ExposeHeader>Accept-Ranges</ExposeHeader>
<ExposeHeader>Content-Range</ExposeHeader>
<ExposeHeader>Content-Encoding</ExposeHeader>
<ExposeHeader>Content-Length</ExposeHeader>
<ExposeHeader>Access-Control-Expose-Headers</ExposeHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
I can't see the url of the request you are making but ..
AWS S3 does not send the HTTP header Accept-Ranges: bytes if you are using the default endpoint URL. Use the following format as the origin URL instead which serves the required Accept-Ranges header field: .s3.amazonaws.com
From KeyCDN
Hope that helps
Just wanted to know if the GET Bucket op response ever skips the Content-Length header. I tested this and i saw that there was no Content-Length header in the response for GET Bucket op.
How does an application reading the response understand where the body of the response ends if the response doesn't contain Content-Length header?
Request-Response Snippet:
GET /?max-keys=1000&prefix&delimiter=%2F HTTP/1.1
Date: Sat, 09 Apr 2016 18:27:23 GMT
x-amz-request-payer: requester
Authorization: AWS AKIAIP3KAUILC4GG7A2A:UG3bGvIjayrxrkxEX1mfrvETy/M=
Connection: Keep-Alive
User-Agent: Cyberduck/4.9.19632 (Mac OS X/10.10.5) (x86_64)
HTTP/1.1 200 OK
x-amz-id-2: yg76HSq5j0mi0oR6dXF8ZfGq722kHBWiMQmNvXPqiLxr1S4nGj5GVn1RVrPQrOUfNynxxaMSYEY=
x-amz-request-id: B4468E68E10B6AEF
Date: Sat, 09 Apr 2016 18:27:25 GMT
x-amz-bucket-region: us-east-1
Content-Type: application/xml
Server: AmazonS3
Connection: close
<?xml version="1.0" encoding="UTF-8"?>
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">......</ListBucketResult>
Thanks!
The Content-Length header is optional in response. And it may not reflect the real content-length even if it presents. Think about gzipped response. So to answer the question: When no Content-Length is received, the client keeps reading until the server closes the connection.
In Java, keep calling InputStream.read() until it returns -1.
Is the Content-Length header required for a HTTP/1.0 response?
Some of our users are getting this error in the browser consoles:
XMLHttpRequest cannot load https://d2ynz9y5qgba7.cloudfront.net/icons/instagram.svg.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'https://www.weld.io'; is therefore not allowed access.
These are the current headers:
Accept-Ranges: bytes
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: *
Age: 21038
Content-Length: 1086
Content-Type: image/svg+xml
Date: Wed, 23 Mar 2016 10:00:12 GMT
Etag: "5cc3b790e15d7736b95880001521630b"
Last-Modified: Wed, 18 Mar 2015 10:20:32 GMT
Server: AmazonS3
Via: 1.1 8cdc69e06e564b9aef153cf0b52204b0.cloudfront.net (CloudFront)
X-Amz-Cf-Id: 0lD_0czYTm6i5f7RlURkG2dcQx_B252LC2GOu98anzHH1k1eaz2lmg==
X-Cache: Hit from cloudfront
As you can see, Access-Control-Allow-Origin is indeed present.
We are also "whitelisting" Origin on CloudFront.
What could be the cause of this issue?
For some reason I cannot access the response header of "Content-Range" anymore... Therefore it's impossible to determine the file size of a resource using XHR.
I get error Refused to get unsafe header "Content-Range" on Chrome in this line:
var cr = this.getResponseHeader('Content-Range');
Here's the CORS config:
<?xml version="1.0" ?>
<CorsConfig>
<Cors>
<Origins>
<Origin>*</Origin>
</Origins>
<Methods>
<Method>GET</Method>
<Method>HEAD</Method>
<Method>DELETE</Method>
</Methods>
<ResponseHeaders>
<ResponseHeader>x-goog-meta-foo1</ResponseHeader>
<ResponseHeader>origin</ResponseHeader>
<ResponseHeader>range</ResponseHeader>
<ResponseHeader>Content-Range</ResponseHeader>
<ResponseHeader>Content-Length</ResponseHeader>
</ResponseHeaders>
<MaxAgeSec>1800</MaxAgeSec>
</Cors>
CURL output:
$ curl -H "Origin: http://peer5.com" http://commondatastorage.googleapis.com/peer5_vod/wind2_orig.mp4 -s -D - -o /dev/null
HTTP/1.1 200 OK
Server: HTTP Upload Server Built on May 8 2013 16:51:19 (1368057079)
Expires: Mon, 13 May 2013 09:47:40 GMT
Date: Mon, 13 May 2013 08:47:40 GMT
Cache-Control: public, max-age=3600, no-transform
Last-Modified: Fri, 22 Mar 2013 17:09:47 GMT
ETag: "755232ae8fef22bc7b4e9510a68a646e"
x-goog-generation: 1363972188238000
x-goog-metageneration: 2
Content-Type: video/mp4
x-goog-hash: crc32c=pZmS2Q==
x-goog-hash: md5=dVIyro/vIrx7TpUQpopkbg==
Accept-Ranges: bytes
Content-Length: 15535795
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Content-Length, Date, Server, Transfer-Encoding
This appears to be a bug on our side. Only the last header value in the ResponseHeaders list is returned in the Access-Control-Expose-Headers header. We are working on rolling out a fix, but as a workaround, if you only need the Content-Range header (Content-Length is considered a simple header by the CORS spec and is added automatically), please try setting your CORS config to this:
<?xml version="1.0" ?>
<CorsConfig>
<Cors>
<Origins>
<Origin>*</Origin>
</Origins>
<Methods>
<Method>GET</Method>
<Method>HEAD</Method>
<Method>DELETE</Method>
</Methods>
<ResponseHeaders>
<ResponseHeader>Content-Range</ResponseHeader>
</ResponseHeaders>
<MaxAgeSec>1800</MaxAgeSec>
</Cors>
</CorsConfig>
UPDATE: This bug has been fixed.