CloudFront Serving Issues for Brotli-Compressed Files

1

CloudFront inconsistently serves custom Brotli (.br) pre-compressed files stored in S3. While Gzip (.gz) compressed files are served correctly with the expected Content-Type and Content-Encoding, Brotli files are sometimes:

Served with Content-Type: application/octet-stream instead of application/javascript. Served as compressed binary content even though the file extension remains .js. This suggests that CloudFront might incorrectly cache or misinterpret metadata for Brotli files.

Origin: Amazon S3 bucket Files: Pre-compressed <filename>.js.br uploaded to S3 larger than 10MB.

Metadata: Content-Type: application/javascript Content-Encoding: br

CloudFront Configuration: A CloudFront Function rewrites requests to append .br if the Accept-Encoding header includes br. Cache policy configured to forward the Accept-Encoding header. Brotli compression enabled in the distribution settings.

Observed Behavior Gzip files (.gz) behave correctly: browsers correctly decode and render them as JavaScript.

Brotli files (.br) exhibit inconsistent behavior: Sometimes served with application/octet-stream Content-Type. Sometimes served with the .js extension but as raw compressed data.

Behavior changes after 5–10 times serving the correct .js file — after a few successful responses, the file starts being served incorrectly, even without cache invalidation.

Behavior observed across browsers (Chrome, Chromium and Firefox) and using curl for testing.

Cache invalidation temporarily does not fix the issue.

Expected Behavior Brotli-compressed files should always be served with:

Content-Type: application/javascript Content-Encoding: br Browsers should seamlessly decode and run the served JavaScript.

Steps to Reproduce Upload a .js.br file to an S3 bucket with proper metadata. Configure CloudFront to rewrite requests to .br based on Accept-Encoding. Enable Brotli compression and forward the Accept-Encoding header.

Test access through a browser and/or via curl. Observe that after some time, CloudFront may start serving octet-stream or incorrectly unwrapped compressed files.

Notes Switching to Gzip avoids the problem. Brotli compressed files work temporarily but then fail. No issues when accessing files directly from S3 — the problem only occurs when served via CloudFront. Cache Policy TTLs have been adjusted to test variations (no lasting improvement).

asked 22 days ago75 views
3 Answers
0

The issue you're experiencing with CloudFront inconsistently serving Brotli-compressed files is likely due to a combination of factors related to caching behavior, compression settings, and how CloudFront handles pre-compressed files.

CloudFront supports both Gzip and Brotli compression, but there are some important considerations:

  1. Brotli compression in CloudFront is only supported for HTTPS requests. Chrome and Firefox browsers, for example, only support Brotli compression over HTTPS connections. If you're testing with HTTP, this could explain some of the inconsistencies.

  2. CloudFront's behavior with pre-compressed files can be complex. When you enable compression in CloudFront, it's designed to compress files at the edge if they're not already compressed. However, if you're uploading pre-compressed files, this can lead to unexpected behavior.

  3. The issue with Content-Type being set to application/octet-stream instead of application/javascript could be related to how CloudFront is interpreting the file based on its extension or metadata.

  4. The inconsistent behavior you're seeing, where it works correctly for a few requests and then starts failing, suggests there might be caching issues. CloudFront might be caching different versions of the file or its metadata, leading to inconsistent serving.

  5. The fact that Gzip files work correctly while Brotli files don't suggests that there might be specific issues with how CloudFront is handling Brotli compression or pre-compressed Brotli files.

To address these issues, consider the following:

  1. Ensure all requests are made over HTTPS to support Brotli compression.

  2. Instead of pre-compressing files, consider letting CloudFront handle the compression. Upload uncompressed files to S3 and configure CloudFront to compress them at the edge. This approach might be more reliable and consistent.

  3. Review your CloudFront Function that rewrites requests. Ensure it's not interfering with how CloudFront interprets the file type or handles compression.

  4. Check your cache policy settings. Ensure that the cache key includes all necessary elements to differentiate between compressed and uncompressed versions of the files.

  5. Monitor your CloudFront distribution logs to see if there are any patterns in when and how the files are being served incorrectly.

  6. Consider creating a custom cache policy if the managed policy doesn't meet your specific needs for handling Brotli-compressed files.

If the issue persists after implementing these changes, you may need to contact AWS support for further investigation, as there could be underlying issues with how CloudFront is handling your specific Brotli-compressed files.
Sources
Serve compressed files - Amazon CloudFront
Cloudfront caching issue | AWS re:Post
Static JS files served from S3 via CloudFront lead to intermittent CORS issues | AWS re:Post

profile picture
answered 22 days ago
    1. All requests are done via HTTPS
    2. CloudFront compression works only for files 10MB and smaller. This is a case with a larger than 10MB file.
    3. The exact same function works with gzip, not with Brotli.
    4. Debugging was done with custom cache policies.
0

hi,

in your question "pre-compressed files stored in S3."

as CloudFront can take uncompressed files from origin and compressed them automatically at edge location, before sending them to the user browser( Chrome and Firefox web browsers support Brotli compression only when the request is sent using HTTPS. That you are using HTTPS)

So,

in CloudFront console in Behavior edit section:->

"Compress objects automatically"

No [set to No, as your files are already compressed in S3]
Yes

S3 serves the .js.br file with the metadata Content-Type: application/javascript and Content-Encoding: br.

CloudFront, with ***automatic ***compression disabled, forwards these headers and the compressed content directly to the browser.

Best,

profile picture
answered 22 days ago
  • Hi,

    This solution works for this specific file. The problem is that I want all files compressed.

    So far the only working solution is to use gzip. With brotli there seems to be some confusion inside aws that gets messed up when automatic compression is turned on. Funnily enough this does not happen with gzip.

    Is there a case where I can use brotli (the default compression mechanism for files smaller than 10mb) so I keep the consistency across all files (<10mb and customized >10mb for specific files)?

    Best, Rosen

0

hi,

Okay!

so, serving Brotli-compressed files stored in S3 through CloudFront, where CloudFront simply passes through the correct file based on the Accept-Encoding header, without trying to compress it again.

question is how? as CloudFront doesn't support them well

according to doc it says, but it is not consistent as you experience already.

" If your origin returns a compressed object to CloudFront, CloudFront detects that the object is compressed based on the presence of a Content-Encoding header and doesn’t compress the object again." Link:- https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ServingCompressedFiles.html

here i am trying to understand, if you .br file can work with CloudFront:-

so, CloudFront look for .js but not .br so well.

I wonder Lambda@Edge to rewrite the request URI before it reaches to S3:-

let's say

------ Brower send request .jr with accept-encoding: .br

----->CloudFront Get /assets/Script.jr accept-encoding .br

--->it look for exactly /assets/script.js in S3-----> and "S3 will only serve a .br file if the request specifically asks for that exact object path" :--> ------- "GET /assets/script.js.br" ------

AND that's where Lambda@Edge to rewrite request to script.js.br

[ Request URI: /assets/script.js

New URI: /assets/script.js.br

]

now CloudFront has .br (compressed) from S3

Now Brower will see the correct header it requested for.

for Lambda@Edge:- > https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html

I hope it might help!

Best

profile picture
answered 20 days ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions