2

I'm using MapBox and I'm looking to add some images to my map that are in an AWS S3 bucket.

The MapBox function that I'm using is loadImage. The loadImage docs state that "External domains must support CORS."

My JS code is similar to:

this.map.on('load', () => {
    ...
    this.map.loadImage("https://my-test-bucket.s3-us-west-1.amazonaws.com/long-uuid-here.png", (error, image) => {
    if (error) {
        console.log(error)
        throw error;
    }
// The rest doesn't matter
...

When my map loads in chrome I get the following error:

Access to fetch at 'https://my-test-bucket.s3-us-west-1.amazonaws.com/long-uuid-here.png' from origin 'https://localhost:7000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

My AWS S3 CORS config is the following:

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]

Using curl -H "origin: localhost" -v "https://my-test-bucket.s3-us-west-1.amazonaws.com/long-uuid-here.png", I get the following output:

* Connected to my-test-bucket.s3-us-west-1.amazonaws.com (<IP HERE>) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: C=US; ST=Washington; L=Seattle; O=Amazon.com, Inc.; CN=*.s3-us-west-1.amazonaws.com
*  start date: Jul 30 00:00:00 2020 GMT
*  expire date: Aug  4 12:00:00 2021 GMT
*  subjectAltName: host "my-test-bucket.s3-us-west-1.amazonaws.com" matched cert's "*.s3-us-west-1.amazonaws.com"
*  issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert Baltimore CA-2 G2
*  SSL certificate verify ok.
> GET /default.jpg HTTP/1.1
> Host: my-test-bucket.s3-us-west-1.amazonaws.com
> User-Agent: curl/7.64.1
> Accept: */*
> origin: localhost
> 
< HTTP/1.1 200 OK
< x-amz-id-2: bLicG+33kfSamR29vMA3BnhmSV27Afooba6yU6hVOPt0mbckO5gefhXN8Ho7hgAEP58s4hKjCf0=
< x-amz-request-id: E760D53EDC5A9804
< Date: Wed, 04 Nov 2020 22:31:38 GMT
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: GET, PUT, POST, DELETE
< Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
< Last-Modified: Tue, 11 Aug 2020 22:37:31 GMT
< ETag: "39eb0bbf2cc33ba02f53f8585004f820"
< Accept-Ranges: bytes
< Content-Type: image/jpeg
< Content-Length: 16579
< Server: AmazonS3

So, it looks like I've got Access-Control-Allow-Origin: * header coming back from the AWS S3 server.

I don't receive any CORS error in Firefox.

Is there a problem with my AWS S3 CORS config? Why am I getting these CORS errors in Chrome v86.0.4240.80 (Official Build) (x86_64)?

Note: my bucket isn't actually named "my-test-bucket". I've changed the URL/bucket name for this question. Also, locally I am using https://localhost (set it up with a certificate since I need to use the W3C geolocation API which only works over HTTPS), if it matters

ChristianF
  • 1,735
  • 4
  • 28
  • 56

1 Answers1

5

It looks like this is a caching issue with Chrome. I found an answer on this question: CORS problems with Amazon S3 on the latest Chomium and Google Canary, from @nassan that suggests adding ?cacheblock=true as a query parameter to the GET request.

So, changing my code to:

this.map.loadImage(`${dealInfo.properties.logo}?cacheblock=true`, (error, image) => {
    ...
})

Resolves the CORS errors that occur in Chrome.

Looks like this is the issue: https://bugs.chromium.org/p/chromium/issues/detail?id=409090.

I also added crossorigin="anonymous" to my script tag.

Seems like this being a Chrome caching issue (header caching?) also explains why I could see the expected headers using curl, but Chrome complained that they weren't there.

ChristianF
  • 1,735
  • 4
  • 28
  • 56
  • I'm with the Chrome guys here - their caching behaviour is perfectly legal, and it is actually S3 at fault for not returning a Vary header on non-CORS requests. See https://forums.aws.amazon.com/thread.jspa?threadID=342401 where I've tried to summarise it. – tangobravo Jul 16 '21 at 15:47
  • It does seem to be an AWS S3 is at-fault on this. However, they have been aware of it for some time, it seems, and it hasn't been fixed. So, the workaround seems to be in order for now. – Rob Sep 25 '21 at 07:37