2
votes

I read some articles about setting the content-length of a file that will be served. It has some benefits comparing to chunked downloads. The server serve chunks (don't know what the size of a chunk is anyway) when the content-length is unknown.

In PHP I use the ob_gzhandler to gzip html,js and css files and other text-based content. Setting the raw content-length before gzip output, results in strange side-effects because the length does not match the length of the gzipped output. I notice a delay or the browser reports an encoding error.

I saw a trick (also on stackoverflow) to set the content-length after gzip compression to be sure it reports the correct size. But when I do this, the content is no longer compressed.

The question is, is this behaviour correct? Is gzipped content always send chuncked? Is content-length only needed for files that are not gzipped?

Here some snippets of code:

1 Results in gzipped and chunked file transfer:

ob_start('ob_gzhandler');
echo $sResult;

2 Results in normal file transfer with content-length specified (but expect gzipped and content-length):

ob_start('ob_gzhandler');
echo $sResult;
header('Content-Length: '.ob_get_length()); 

Here some pictures of http header results: 1 Gzipped and Chuncked

2 Expect Gzipped but normal transfer when set content-length

1
It is not a duplicate because he/she is talking about a gzipped FILE. Besides this can be also a file but it is about serving content, not specific a file. Want to know why it is not working the way I described here. Didn't know that it relies on similar method. Still do not know/understand WHY it works. The CSS file I used in this example is a non-existing file because it composed out of several CSS files.Codebeat
It works because it uses two levels of output buffering; at the first ob_end_flush() it flushes the inner output buffering belonging to ob_gzhandler; then the content length is known ... afterwards, the second call flushes the outer buffer.Ja͢ck
Thanks for the clear explanation Jack!Codebeat
Personally I wouldn't bother too much about chunked data transfer; it works fine because chunks aren't typically read one by one, rather the whole responses is read using 8kB buffers and dechunking is done in memory.Ja͢ck

1 Answers

2
votes

Found the solution/trick here: How to determine the Content-Length of a gzipped file?

Made into this:

// clear output buffers
while( ob_get_level() )
 { ob_end_clean(); }

< send http headers here >

ob_start();
ob_start('ob_gzhandler');
echo $sResult;
if( !headers_sent() )
{
   ob_end_flush(); // Flush the output from ob_gzhandler
   header('Content-Length: '.ob_get_length());
   ob_end_flush(); // Flush the outer ob_start()
}

To me is not clear why this works but seems to work perfectly. The content is now gzipped and has a content-length (not chunked).

To prove it, here is a screenshot:

gzipped and content-length

Cheers! ;-)