Hello! First off, let me thank you for a great server; we replaced Apache with Litespeed about 6 months ago and it's been rock solid.
I'm running into a problem right now with PHP scripts who output more than around 120MB of data. When I use curl to request the file, it works fine:
> GET dl.php HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3
> Host: localhost
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 29 Jul 2011 17:56:43 GMT
< Connection: close
< Content-Type: application/octet-stream
< Content-Description: File Transfer
< Content-Disposition: attachment; filename="tutorial.mov";
< Content-Transfer-Encoding: binary
< Content-Length: 152466240
< … 150 MB of binary data
However, when hitting the same script from a browser, this results in a zero-byte download. I traced that down to the browser requesting transfer body compression with an "Accept-Encoding: gzip, deflate" header.
When I supply that header via curl, I see the exact same behavior as the browser:
> GET dl.php HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3
> Host: localhost
> Accept: */*
< HTTP/1.1 200 OK
< Date: Fri, 29 Jul 2011 17:56:43 GMT
< Connection: close
< Content-Type: application/octet-stream
< Content-Description: File Transfer
< Content-Disposition: attachment; filename="tutorial.mov";
< Content-Transfer-Encoding: binary
< Content-Length: 152466240
* transfer closed with 152466240 bytes remaining to read
The response is sent using PHP's readfile() mechanism, which writes a complete file directly to PHP's output. I don't know how it buffers the file internally, but it does work with smaller files.
Here's what I've done:
- Make sure that PHP's output compression is disabled. (Not only is it disabled via .htaccess, but it's explicitly disabled in this script using ini_set)
- Try disabling PHP's output buffering before sending the response. Same behavior.
- Disable Litespeed's dynamic output compression. Didn't make a difference (it shouldn't have mattered, anyway, because the mime-types enabled it only for CSS, Javascript, and text/* output).
- Made sure that the lsphp5 external application settings have Response Buffering disabled.
- Change the "Max Dynamic Response Size" setting from 500M to 1000M. Same behavior.
I've checked the Litespeed SAPI source code, and it does not do any kind of output compression, and appears to send the response to Litespeed in 16K packets.
The lsphp5 EA settings mention next to the "response buffering" setting something about enabling Apache's non-parsed headers. I can't find any setting that does this, but that Apache feature does appear to do what we want — send the response directly from the script to the browser without buffering.
Any thoughts? The most telling symptom, to me, is that passing in the Accept-Encoding header immediately triggers the bug with no warnings or errors in the output, or the PHP error log, or the Litespeed error logs. Thanks in advance!
I'm running into a problem right now with PHP scripts who output more than around 120MB of data. When I use curl to request the file, it works fine:
> GET dl.php HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3
> Host: localhost
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 29 Jul 2011 17:56:43 GMT
< Connection: close
< Content-Type: application/octet-stream
< Content-Description: File Transfer
< Content-Disposition: attachment; filename="tutorial.mov";
< Content-Transfer-Encoding: binary
< Content-Length: 152466240
< … 150 MB of binary data
However, when hitting the same script from a browser, this results in a zero-byte download. I traced that down to the browser requesting transfer body compression with an "Accept-Encoding: gzip, deflate" header.
When I supply that header via curl, I see the exact same behavior as the browser:
> GET dl.php HTTP/1.1
> User-Agent: curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8r zlib/1.2.3
> Host: localhost
> Accept: */*
< HTTP/1.1 200 OK
< Date: Fri, 29 Jul 2011 17:56:43 GMT
< Connection: close
< Content-Type: application/octet-stream
< Content-Description: File Transfer
< Content-Disposition: attachment; filename="tutorial.mov";
< Content-Transfer-Encoding: binary
< Content-Length: 152466240
* transfer closed with 152466240 bytes remaining to read
The response is sent using PHP's readfile() mechanism, which writes a complete file directly to PHP's output. I don't know how it buffers the file internally, but it does work with smaller files.
Here's what I've done:
- Make sure that PHP's output compression is disabled. (Not only is it disabled via .htaccess, but it's explicitly disabled in this script using ini_set)
- Try disabling PHP's output buffering before sending the response. Same behavior.
- Disable Litespeed's dynamic output compression. Didn't make a difference (it shouldn't have mattered, anyway, because the mime-types enabled it only for CSS, Javascript, and text/* output).
- Made sure that the lsphp5 external application settings have Response Buffering disabled.
- Change the "Max Dynamic Response Size" setting from 500M to 1000M. Same behavior.
I've checked the Litespeed SAPI source code, and it does not do any kind of output compression, and appears to send the response to Litespeed in 16K packets.
The lsphp5 EA settings mention next to the "response buffering" setting something about enabling Apache's non-parsed headers. I can't find any setting that does this, but that Apache feature does appear to do what we want — send the response directly from the script to the browser without buffering.
Any thoughts? The most telling symptom, to me, is that passing in the Accept-Encoding header immediately triggers the bug with no warnings or errors in the output, or the PHP error log, or the Litespeed error logs. Thanks in advance!
Last edited: