Stefan
Stefan

Reputation: 28541

Get Apache to auto-decompress a file, but only if needed

I'd like to keep all the static files of my web-server locally compressed, and to serve them either compressed or not, depending on the request.

The answers in How can I pre-compress files with mod_deflate in Apache 2.x? , are close, since indeed by enabling MultiViews and using the right AddEncoding, I can get Apache to return me the compressed foo.tar.gz file from my web-server when I request foo.tar, and it comes with the proper Content-Encoding: header.

But this only works if the client includes Accept-Encoding: gzip in the headers it sends to the server. OTOH if the client does not support the gzip encoding, my server just tells me there's no "acceptable" foo.tar for me.

I can get Apache to decompress that tarball before sending it if I use AddOutputFilter INFLATE tar. But if I do that, then the server also decompresses the content when I request foo.tar.gz (or when I specify that I accept the gzip encoding), which I clearly don't want.

So how do I get Apache to decompress the files when the client doesn't support the gzip content-encoding, but to serve the pre-compressed file in the other cases?

EDIT: Based on @covener's suggestion I tried the following:

AddEncoding x-gzip .gz .tgz
RemoveType application/x-gzip .gz .tgz
AddType application/x-tar .tgz

<Location /packages>
  FilterDeclare smgunzip CONTENT_SET
  FilterProvider smgunzip INFLATE req=Accept-Encoding !$gzip
  FilterChain smgunzip
</Location>

[ Using Apache-2.2.22 here. ] But the result is actually worse than with just the first three lines: when I request the .tar.gz file, it now gets returned without the "Content-Encoding:", and when I request the .tar file, I receive the content of the tar.gz (i.e. still compressed) regardless of the "Accept-Encoding:" header and still without the "Content-Encoding:".

Upvotes: 4

Views: 2984

Answers (2)

uckelman
uckelman

Reputation: 26234

Try this:

DirectoryIndex "index.html.gz" "index.html"

# Don't list the compressed files in directory indexes - you probably don't want to expose
# the .gz URLs to the outside. They're also misleading, since requesting them will give the
# original files rather than compressed ones.
IndexIgnore "*.html.gz" "*.css.gz"

RewriteEngine On

# Rewrite requests for .html/.css files to their .gz counterparts, if they exist.
RewriteCond "%{DOCUMENT_ROOT}%{REQUEST_FILENAME}.gz" -s
RewriteRule "^(.*)\.(html|css)$" "$1\.$2\.gz" [QSA]

# Serve compressed HTML/CSS with the correct Content-Type header.
RewriteRule "\.html\.gz$" "-" [T=text/html,E=no-gzip:1]
RewriteRule "\.css\.gz$"  "-" [T=text/css,E=no-gzip:1]

# Define a filter which decompresses the content using zcat.
# CAVEAT: This will fork a new process for every request made by a client that doesn't
# support gzip compression (most browsers do), so may not be suitable if you're running a
# very busy site.
ExtFilterDefine zcat cmd="/bin/zcat -"

<FilesMatch "\.(html|css)\.gz$">
  <If "%{HTTP:Accept-Encoding} =~ /gzip/">
    # Client supports gzip compression - pass it through.
    Header append Content-Encoding gzip
  </If>
  <Else>
    # Client doesn't support gzip compression - decompress it.
    SetOutputFilter zcat
  </Else>

  # Force proxies to cache gzipped & non-gzipped css/js files separately.
  Header append Vary Accept-Encoding
</FilesMatch>

Cribbed from Daniel Collins, Serving static gzip-compressed content with Apache.

Upvotes: 0

covener
covener

Reputation: 17886

(make sure you have AddEncoding gzip or x-gzip gz or it will break)

2.4:

<Directory /home/covener/SRC/2.4.x/built/htdocs>
  Options +MultiViews
  MultiviewsMatch Any
  FilterDeclare gzip CONTENT_SET
  FilterProvider gzip INFLATE "! req('Accept-Encoding') =~ /gzip/"
  FilterChain gzip
</Directory>

2.2:

<Directory /home/covener/SRC/2.2.x/built/htdocs>
  Options +MultiViews
  MultiviewsMatch Any
  FilterDeclare gzip CONTENT_SET
  FilterProvider gzip INFLATE req=Accept-Encoding !$gzip
  FilterChain gzip
</Directory>

Upvotes: 6

Related Questions