|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2008-02-19 10:48 UTC] mplomer at gmx dot de
Description:
------------
If you have a big project, where "Content-Length" header is set on many places, and then you turn on "zlib.output_compression", you will have a problem, because the original header is still passed through, but it is invalid now, because it contains the length of the uncompressed data instead of the compressed data.
This would confuse some HTTP clients, that rely on the "Content-Length".
I think, "zlib.output_compression" should be completely transparent, so this issue should be handled in php core.
One solution is, to remove the "Content-Length" header (if set) in ob_gzhandler() in ext/zlib/zlib.c:882 (where "Content-Encoding: gzip" header is set). If you see a good way to set the Content-Length to the compressed length, this would be, of course, the best solution, but this is IMHO only possible, if the entire data is buffered before (or is this done by ob_gzhandler anyway?).
This would make the various workarounds irrelevant that have to be done if "zlib.output_compression" is active and is completely backward compatible.
Reproduce code:
---------------
In php.ini:
zlib.output_compression = On
<?php
$output = str_repeat('A', 8192);
header('Content-Length: ' . strlen($output));
?>
Expected result:
----------------
Correct "Content-Length" header or removed "Content-Length" header in response, because the old length is always wrong. Better send no "Content-Length" instead a wrong length.
Actual result:
--------------
The old "Content-Length" header is sent.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 01:00:01 2025 UTC |
> That’s an error. Both scripts set the correct CL (that they know very well), > just the way the specification says they SHOULD. I don’t agree that it would > be the responsibility of the script to counteract the setting (zlib output > compression in this case) of the executing framework (PHP in this case). If > the scripts should take care for every such situation then using the header() > would be completely illegal, because a future output handler might interact > with the output in such a way that invalidates the headers set. This isn’t a > portable phylosophy since it implicitly requires the script being aware of > every aspects of plugins and settings in PHP. > In fact it is the zlib output handler that was setting the wrong CL header (by > not removing the deprecated one). As I see, the handler is constructing a new > response entity instead the one it receives from the script; the consistency of > this response is entirely the responsibility of the handler. As I understand > this has now been patched so that the handler always removes the CL header, and > by that it assures correctness. Note: here’s no refutation of the correctness > of the patched handler. The problem is the zlib.output_compression is not presented as an output handler that rewrites the response and creates a new entity. It is presented as an inoffensive performance option that compresses the output for better performance. And it does so, generally, without the express assent of the programmer. The programmer can always use ob_gzhandler to force compression. Your thesis is that the output handler should not be deactivated; instead it ought to remove the old header and write a new one, whenever possible. This looks good. But consider this script: if (empty($_SERVER["HTTP_RANGE"])) { $offset = 0; } else { //violates rfc2616, which demands ignoring the header if invalid preg_match("/^bytes=(\d+)-/i",$_SERVER["HTTP_RANGE"], $matches); if (empty($matches[1])) $offset = 0; if (is_num_int($matches[1]) && $matches[1] < $filesize && $matches[1]>=0) { $offset = $matches[1]; if (@fseek($fp,$offset,SEEK_SET) != 0) InternalError(); header("HTTP/1.1 206 Partial Content"); header("Content-Range: bytes $offset-".($filesize - 1)."/$filesize"); } elseif ($matches[1] > $filesize) { header("HTTP/1.1 416 Requested Range Not Satisfiable"); die(); } else $offset = 0; } $conlen = $filesize - $offset; header("Content-Length: $conlen"); This is no way this script can work correctly under the zlib handler. 206 responses must have a content-length and the offsets are calculated through the uncompressed size, while under zlib that should be calculated under the compressed size, which is obviously impossible to know without first compressing the file. So actually the only option is to disable the zlib output handler.