8

I'm having some trouble prevent mod_deflate from jumping in on this scenario:

  1. user running CodeIgniter (or any other framework that re-directs to index.php)
  2. mod_deflate is active
  3. zip file is served by a CodeIgniter controller (headers + readfile)

The thing is that Apache always detects the content as being php and therefor something like the lines bellow wont work as the server assumes the ZIP file as being a PHP one.

<FilesMatch "\.(xml|txt|html|php)$">
   SetOutputFilter DEFLATE
</FilesMatch>

Any ideas on how I can have Apache distinguish from an HTML file or a ZIP file both generated by the same index.php framework file.

Edit:
apache log

[Mon Jun 20 02:14:19 2011] [debug] 
mod_deflate.c(602): [client 192.168.0.5] 
Zlib: Compressed 50870209 to 50878224 : URL /index.php, 
referer: http://demo.dev/

Edit:
CI controller that serves the zip

header('Content-Type: application/zip');
header('Content-Transfer-Encoding: binary');
header("Content-Length: " . filesize($file_location)); 
header('Content-Disposition: attachment; filename="' . $file_title . '"'); 
readfile($file_location);
Frankie
  • 24,627
  • 10
  • 79
  • 121

5 Answers5

6

Even tough all answers should have been perfectly valid in a reasonable scenario (and were actually tested prior to making the question) the reason to why I've been unable to instruct Apache to deflate a file by MIME-Type remains unknown.

I was able to have it work as desired by forcing the following instructions into the script

apache_setenv('no-gzip', 1);
ini_set('zlib.output_compression', 0);

I do understand that this is a hot patch and is not addressing the problem's root but so far that will have to suffice. As there are others who may hit the same flag, the above code stays here for reference in what is a dirty fix.

Frankie
  • 24,627
  • 10
  • 79
  • 121
2

You can either:

  • use the deprecated AddOutputFilterByType and specify only the content types you do want to filter; or
  • use the more powerful mod_filter. In FilterProvider you can provide a rule that excludes the filter when the zip content type (application/zip) is found in the response headers.
Artefacto
  • 96,375
  • 17
  • 202
  • 225
  • this single line `AddOutputFilterByType DEFLATE text/html` is good enough to have Apache deflating my fake zip. Doesn't deflate none of the other files though (so it does works more or less as it should). – Frankie Jun 20 '11 at 00:50
  • @Frankie It works here. Make sure you don't have mod_deflate configuration elsewhere. For example, some distros include extra configuration in `/etc/apaches/mods-enabled/deflate.conf` – Artefacto Jun 20 '11 at 01:42
  • thks. Don't have any fancy modules (CentOS) but gonna clean up my httpd.conf tomorrow and see if I can identify the culprit. Thanks. – Frankie Jun 20 '11 at 01:54
  • installed a vanilla version of Fedora 15 only to experience the exact same problem. Tried to reproduce your setup using different alternatives but none worked. Eventually, and building upon your great examples, was able to find the following command: `@apache_setenv('no-gzip', 1);` that was a clear winner. So if you could only update your answer to include the command I'd be more than glad to accept it. Thanks for all the trouble. – Frankie Jun 21 '11 at 23:39
2

You can make use of mod_rewrite to change the mime-type of the request on the Apache level:

# Serve .zip request as zip-files
RewriteRule \.zip$ - [T=application/zip,E=no-gzip:1]

Place it above the rules of the framework, however this needs to make DEFLATE as well depended on mime-type and not file-extension as you do with <FilesMatch>.

Probably it works well together with

AddOutputFilterByType DEFLATE text/html

instead of the <FilesMatch> Directive.

Edit: Added the L flag which should be used in .htaccess context and additionally turned DEFLATE off via the no-gzip environment variable.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • @hakre Apache is still treating the file as a `php` one. The actual path is: `example.com/files/myfile.zip` but somewhat Apache knows and is treating it as a `.php` file. – Frankie Jun 20 '11 at 00:55
  • Because it's a `.php` on disk (resolved file for apache). You need to make DEFLATE dependent on mime-type. I just edited my answer. – hakre Jun 20 '11 at 00:59
  • @hakre, unfortunately no luck. Gonna edit my question to reflect my current `.htaccess` file and `httpd.conf`. – Frankie Jun 20 '11 at 01:06
  • @hakre, if I add the [L] the whole thing stops as it really tries to serve the file and it doesn't exist. Log entry goes as follows: `File does not exist: /home/demo.dev/www/file`. The `www/file` is CI's controller responsible for serving the ZIP file. – Frankie Jun 20 '11 at 01:41
  • Okay, L was a bad idea. But as I read about the `no-gzip` environment variable I thought it's a good idea to set it. – hakre Jun 20 '11 at 01:49
  • The rewrite rule should be unnecessary as PHP is already setting the correct content-type. – Artefacto Jun 20 '11 at 01:51
  • You misunderstood the intention. It's mime-type and it's for the request processing within apache, not (only) for the response HTTP content-type header. – hakre Jun 20 '11 at 01:52
  • @Artefacto @hakre, I must get some sleep so I'm gonna leave this as it is and tomorrow will get back to you guys. Thanks. – Frankie Jun 20 '11 at 01:53
1

Try this (since your urls appear to end in .zip it might work for you):

<FilesMatch "\.(xml|txt|html|php)$">
   SetEnvIf Request_URI "\.zip$" no-gzip
   SetOutputFilter DEFLATE
</FilesMatch>
Femi
  • 64,273
  • 8
  • 118
  • 148
  • thks but unfortunately no luck. If I do a FileMatch only to CSS and JS it will work... as soon as I put `php` into the cradle... stops working. – Frankie Jun 20 '11 at 01:39
0

Instead of using

<FilesMatch "\.(xml|txt|html|php)$">
   SetOutputFilter DEFLATE
</FilesMatch>

Use this configuration for setting compression rules.

AddOutputFilterByType DEFLATE text/html text/plain text/css text/xml application/x-javascript application/javascript

This way, your output will be compressed only if content-type matches with above directives.

CI controller that serves the zip is already sending correct content-type header, so this will not get compressed.

header('Content-Type: application/zip');
Sajid Ali
  • 310
  • 2
  • 10