1

I am trying to get CloudFront to serve a gzipped text file along with Content-Length: <bytes> and Access-Control-Expose-Headers: Content-Length headers so I can display the download progress when using fetch().

The setup I have is:

  1. Pre-compress the files with gzip before uploading to S3 and set Content-Encoding: gzip. (Using CloudFront's automatic compression will mean that it is compressed on-the-fly and the Content-Length header will not be set.)
  2. CORS settings for S3 setting Allow-Control-Expose-Headers: Content-Length as follows:
<?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>
    <ExposeHeader>Content-Length</ExposeHeader>
</CORSRule>
</CORSConfiguration>
  1. CloudFront setup with the corresponding S3 Origin and:
    • GET, HEAD, OPTIONS allowed
    • Origin header whitelisted
    • "Compress Objects Automatically" disabled

Using this configuration I get:

  • Requesting from S3:

    curl <s3 URL> -H "Accept-Encoding: gzip" -H "Origin: example.com" -I

HTTP/1.1 200 OK
x-amz-id-2: ...
x-amz-request-id: ...
Date: Sat, 03 Aug 2019 06:28:41 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD
Access-Control-Expose-Headers: Content-Length
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
Last-Modified: Sat, 03 Aug 2019 05:32:02 GMT
ETag: "6483b10f491dc607412899efad695a04"
Content-Encoding: gzip
x-amz-version-id: ...
Accept-Ranges: bytes
Content-Type: text/plain; charset=utf-8
Content-Length: 559354
Server: AmazonS3
  • Requesting from CloudFront without specifying Accept-Encoding: gzip (or simply deliberately mis-spelling it as gzp):

    curl <cloudfront URL> -H "Origin: example.com" -I

HTTP/2 200
content-type: text/plain; charset=utf-8
content-length: 559354
date: Sat, 03 Aug 2019 06:05:26 GMT
access-control-allow-origin: *
access-control-allow-methods: GET, HEAD
access-control-expose-headers: Content-Length
last-modified: Sat, 03 Aug 2019 05:32:02 GMT
etag: "6483b10f491dc607412899efad695a04"
content-encoding: gzip
x-amz-version-id: ...
accept-ranges: bytes
server: AmazonS3
vary: Origin
age: 1572
x-cache: Hit from cloudfront
via: 1.1 xxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: ...
x-amz-cf-id: ...
  • Requesting from CloudFront specifying Accept-Encoding: gzip:

    curl <cloudfront URL> -H "Accept-Encoding: gzip" -H "Origin: example.com" -I

HTTP/2 200
content-type: text/plain; charset=utf-8
content-length: 559354
date: Sat, 03 Aug 2019 05:39:50 GMT
access-control-allow-origin: *
access-control-allow-methods: GET, HEAD
last-modified: Sat, 03 Aug 2019 05:32:02 GMT
etag: "6483b10f491dc607412899efad695a04"
content-encoding: gzip
x-amz-version-id: ...
accept-ranges: bytes
server: AmazonS3
vary: Origin
age: 3239
x-cache: Hit from cloudfront
via: 1.1 xxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: ...
x-amz-cf-id: ...

Notice that the access-control-expose-headers: Content-Length header gets dropped from the CloudFront response headers simply because we set Accept-Encoding: gzip.

(Also note that S3 is happy to return it even when Accept-Encoding: gzip is set.)

Is there any way to get CloudFront to keep the Access-Control-Expose-Headers header when the request has Accept-Encoding: gzip?

brianskold
  • 121
  • 6
  • Note that https://stackoverflow.com/questions/48530160/cors-headers-missing-when-request-header-has-accept-encoding-for-website-of-cl describes a similar but different situation. I do not have any custom origin headers and CORS headers are not being dropped, only the `Access-Control-Expose-Headers` header. – brianskold Aug 03 '19 at 06:43

1 Answers1

1

I believe I may have found the answer. It's necessary to add Accept-Encoding to the set of whitelisted headers in the CloudFront cache behavior. Doing that and then running an invalidation appears to fix it.

brianskold
  • 121
  • 6
  • It may have only been the invalidation that was needed. The `age` header in the responses tells you how long ago CloudFront fetched the object that it is currently returning. Changing parameters in the Cache Behavior settings doesn't necessarily change behavior when objects are already cached, until they are later invalidated or expire -- but changing the whitelisted headers is an exception to this, since that changes the cache key. – Michael - sqlbot Aug 03 '19 at 14:46
  • Oh interesting, I didn't know that. However, it still seems the `Accept-Encoding` is needed in the set of whitelisted headers. Without it, I can't get the `Access-Control-Expose-Headers` header to be returned when `Accept-Encoding` is set to `gzip`. – brianskold Aug 04 '19 at 23:50