No content-length header when response is compressed

I need the content-length header because I want to show the user a progress bar as they are downloading a resource (I use XMLHttpRequest).

I noticed that Cloudflare doesn’t specify the content-length only when requesting compressed content.

Requesting plain content:

> curl 'https://bombhopper.io/bundle.js' -I
HTTP/2 200 
date: Fri, 06 Dec 2019 12:55:40 GMT
content-type: application/javascript
content-length: 1055924
set-cookie: __cfduid=dbc2e3e013a14713c921f17105b07c25a1575636939; expires=Sun, 05-Jan-20 12:55:39 GMT; path=/; domain=.bombhopper.io; HttpOnly; Secure
x-amz-id-2: MX4p6ULHOWqovXSXXV92LBLKEKTRASIM8bdKXNKGIvh1tz6Q3d1fBRkXkoNGtaESz55jUi7Zi1E=
x-amz-request-id: 42456EC52F9D49A5
cache-control: max-age=0,must-revalidate,public
last-modified: Fri, 06 Dec 2019 01:17:02 GMT
etag: "4dd36d675beda068685226b5b563e05c"
cf-cache-status: REVALIDATED
accept-ranges: bytes
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
alt-svc: h3-23=":443"; ma=86400
server: cloudflare
cf-ray: 540e6a5aafc0edf7-CDG

Requesting compressed content:

> curl 'https://bombhopper.io/bundle.js' -H 'accept-encoding: gzip' -I
HTTP/2 200 
date: Fri, 06 Dec 2019 13:07:35 GMT
content-type: application/javascript
set-cookie: __cfduid=de672103e315b9d5eafcba71a3b5aaedc1575637655; expires=Sun, 05-Jan-20 13:07:35 GMT; path=/; domain=.bombhopper.io; HttpOnly; Secure
x-amz-id-2: MX4p6ULHOWqovXSXXV92LBLKEKTRASIM8bdKXNKGIvh1tz6Q3d1fBRkXkoNGtaESz55jUi7Zi1E=
x-amz-request-id: 42456EC52F9D49A5
cache-control: max-age=0,must-revalidate,public
last-modified: Fri, 06 Dec 2019 01:17:02 GMT
etag: W/"4dd36d675beda068685226b5b563e05c"
cf-cache-status: REVALIDATED
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
vary: Accept-Encoding
alt-svc: h3-23=":443"; ma=86400
server: cloudflare
cf-ray: 540e7bd15cc6ee33-CDG
content-encoding: gzip

I get this for Brotli compression too. I have Cache Level set to Cache everything, nothing too special in my settings otherwise.

I’m having the same problems as well, is there anyway to solve the issue?

We’re compressing it on the fly and don’t know what the length will be for the object when we return the headers. You might try using no-transform in your origin headers and sending the object gzipped with a no-transform header from your origin and see if that works.

2 Likes

Thanks, it worked!

Interestingly, it seems that Cloudflare will decompress on the fly when the request is not made with Accept-Encoding: gzip. It won’t send Content-Length for these users but that’s okay, as far as I know all browsers since IE6 support gzip.

The more relevant downside of your solution is that users won’t be able to benefit from Brotli compression, they’ll fall back to gzip.

I’m curious though, why are you compressing on the fly? I would have assumed storing compressed versions of the files would be less costly than compressing on the fly for each request.

Turns out the XHR progress event reports decompressed size in ev.loaded. Since ev.total corresponds to content-length, which as per RFC 7230 is supposed to be the body, which may be compressed, it can’t be used together with ev.loaded. So now I’m setting a x-decompressed-content-length in my origin server (more on that here), and using that to calculate load progress, which is actually great because it allows users to request any compression algorithm.

By the way for anyone interested, the XHR spec doesn’t specify that the event should report decompressed size in ev.loaded, it’s unspecified. But from my tests that’s what Firefox and Chrome do.

This topic was automatically closed after 14 days. New replies are no longer allowed.