ApacheのDirectoryMatchとLocationMatch

ApacheのDirectoryディレクティブやLocationディレクティブで正規表現を使いたいときは、DirectoryMatchやLocationMatchを使用しますが、今日ちょっと設定していて、なるほどと思ったのでメモ。

あと今日、はてダからはてなブログにインポートしてみたのでテスト投稿。

やりたいこと

とある階層にある、特定の画像ファイルがなかった場合(404の場合)、特定のエラー画像ページを出したい。

これは、DirectoryとErrorDocumentディレクティブの組み合わせで出来そうなものなんだけど、この「とある階層」ってのがちょっと厄介。

例えばドキュメントルートを/foo/barとした場合

/foo/bar/img/a/image1.jpg
/foo/bar/img/a/b/image2.jpg
/foo/bar/img/a/b/c/image3.jpg
/foo/bar/img/a/b/c/d/image4.jpg

こんなふうに/foo/bar/img配下のどこかにあるjpgファイルのみErrorDocumentの対象にしたい。

DirectoryMatch

/foo/bar/img配下のどこかにある…のだから初めは↓のように設定した。

DocumentRoot "/foo/bar"

<DirectoryMatch "/foo/bar/img/.*\.jpg$">
    ErrorDocument 404 /baz/404.jpg
</DirectoryMatch>

こうすると

http://aaaaaaaa/img/a/b/image2.jpg

→ これはファイルがあるので当然200で返る

http://aaaaaaaa/img/a/b/hogehogehoge.jpg

→ これはファイルがない、かつ正規表現にマッチするのでErrorDocumentで返る

http://aaaaaaaa/img/a/b/c/d/hogehogehoge.jpg

→ これも同じ。階層が深くなっても正規表現にマッチするのでErrorDocumentで返る

http://aaaaaaaa/img/baz/hogehogehoge.jpg

→ 問題はこれ。defaultの404ページなる

正規表現的には、.*で全マッチなので、/img/baz/hogehogehoge.jpgはマッチする。

だけど、ApacheのDirectoryディレクティブは、指定のディレクトリにマッチするかどうかなので、ディレクトリそのものがないこのパターンではDirectoryディレクティブが適用されない。
ファイルがない404とディレクトリがない404は違う。

LocationMatch

で結局Locatonを使って↓みたく書きなおした。

DocumentRoot "/foo/bar"

<LocationMatch "/img/.*\.jpg$">
    ErrorDocument 404 /baz/404.jpg
</LocationMatch>

LocationならばURLマッチなので、

http://aaaaaaaa/img/baz/hogehogehoge.jpg

のようなURLもErrorDocumentで返る。

Locationは

(なぜか)普段あまり使わないのでたまに使うと便利だなーと思う。