Apache 2.2 mod_filterを使いこなす – AddOutputFilterByType DEFLATE text/htmlを書き換えてみる

ApacheにはコンテンツのMIME-typeに応じてフィルターをかけるAddOutputFilterByTypeディレクティブがありますが、Apache 2.1 以降で非推奨になり、代わりにmod_filterでフィルターをかけることが勧められているようです。

しかしながら、mod_filterの実例があまりにも少ないため、どう使っていいか分からないのが現状です。なので、AddOutputFilterByType DEFLATE text/htmlを書き換えてみることにしました。

mod_deflateのドキュメントには、実例として画像以外をすべて圧縮する方法が以下のように書かれています。

<Location />
# Insert filter
SetOutputFilter DEFLATE

# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html

# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4.0[678] no-gzip

# MSIE masquerades as Netscape, but it is fine
# BrowserMatch bMSIE !no-gzip !gzip-only-text/html

# NOTE: Due to a bug in mod_setenvif up to Apache 2.0.48
# the above regex won't work. You can use the following
# workaround to get the desired effect:
BrowserMatch bMSI[E] !no-gzip !gzip-only-text/html

# Don't compress images
SetEnvIfNoCase Request_URI
.(?:gif|jpe?g|png)$ no-gzip dont-vary

# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
</Location>

これをベースにMIME-typeがtext/*、application/xhtml、application/xmlの場合、deflateするようにしたものが以下になります。

<Location />
# Netscape 4.x has some problems...
BrowserMatch ^Mozilla/4 gzip-only-text/html

# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4.0[678] no-gzip

# MSIE masquerades as Netscape, but it is fine
BrowserMatch bMSIE !no-gzip !gzip-only-text/html

# ここからフィルター設定
FilterDeclare Compression CONTENT_SET
FilterProvider Compression DEFLATE Content-Type $text/plain
FilterProvider Compression DEFLATE Content-Type $text/css
FilterProvider Compression DEFLATE Content-Type $application/xhtml
FilterProvider Compression DEFLATE Content-Type $application/xml
FilterProvider Compression DEFLATE Content-Type $application/xhtml+xml
FilterProvider Compression DEFLATE Content-Type $application/rss+xml
FilterProvider Compression DEFLATE Content-Type $application/atom+xml
FilterProvider Compression DEFLATE Content-Type $application/x-javascript
FilterProvider Compression DEFLATE Content-Type $image/svg+xml
FilterChain Compression
# ここまでフィルター設定

# Don't append Vary heder for specific files
SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png|zip|lzh|exe)$ dont-vary

# Make sure proxies don't deliver the wrong content
Header append Vary User-Agent env=!dont-vary
Header append Vary Accept-Encoding env=!dont-vary
</Location>

まず、FilterDeclareディレクティブでCompressionという名前のフィルター群のタイプがCONTENT_SETであると宣言します(これはなぜそうする必要があるのかよく分からないので教えてください)。

次にFilterProviderディレクティブでCompressionフィルター群にフィルターを追加しています。FilterProviderディレクティブの第一引数はフィルター群に付ける名前(今回はCompression)、第二引数はフィルターのプロバイダー名です。mod_deflateモジュールを読み込むと、ap_register_output_filter関数でDEFLATEというプロバイダー名が自動的に登録されます(そのプロバイダーがdeflateを行います)。第三引数(Content-type $text/plain)はフィルターを実行する条件を指定するもので、今回はHTTPレスポンスヘッダのContent-typeがtext/plainに部分一致した場合のみ、フィルターを実行するという条件をつけています。

最後のFilterChainディレクティブでCompressionフィルター群がApacheのリクエストを通じて呼び出されるようにします(つまりFilterChainディレクティブを使わないと、定義されたフィルター群は実行されません)。

ここで気になるのが、BrowserMatchディレクティブで環境変数に設定したno-gzipやgzip-only-text/htmlがフィルター実行の条件の絞込み(FilterProviderディレクティブの第三引数)に使われていないということです。実はこれらの環境変数はmod_deflateモジュール内で参照され、たとえばno-gzipが設定されていた場合は、自動的にフィルターが外れるようになっています。

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>