読者です 読者をやめる 読者になる 読者になる

よかろうもん!

アプリからインフラまで幅広くこなすいまどきのクラウドエンジニアが記す技術ブログ

Apache+SubversionでLocationディレクティブにおいて正規表現が利用できない!?

Subversion(WebDav)にアクセスできるようにする際に、Locationディレクティブで正規表現を用いることができるか(過去のエントリ『Locationディレクティブで正規表現』で書いた内容)を試してみたところ、正規表現が利用できないという状況に陥りました。

今回、なぜLocationディレクティブで正規表現を利用してみようと思ったかと言いますと、Subversion(WebDav)にアクセスするURIが変更になった場合などに、変更前・変更後の両方のURIでユーザがアクセスできるようにするにはどうしたらよいかについて考えてみたからです。

それでは、調査内容を以下にまとめておきます。

環境

RedHat EL4にて動作確認をしましたが、そのときのミドルウェアのインストール方法については、『Suvbersionとapacheの組み合わせで気をつけておくこと』のエントリのApache2.2.9のインストールSubversion1.5.2のインストールを参考にしてください。
#本エントリに貼り付けてあるログはUbuntuで試したときのログですが、
RedHatでも同様の出力だったことは確認しています。
#紛らわしくてすみません・・・

動作確認

普段、リポジトリWebDavでアクセスできるようにする際は、httpd.confに以下のような内容を追加するのが一般的です。


DAV svn
SVNPath /var/svn/repos/test

#上記の例だと、http://localhost/project/testで/var/svn/repos以下のtestリポジトリの内容を閲覧できるようになります。

しかしこのLocationディレクティブで正規表現を利用すると、Subversion(WebDav)にアクセスできなくなってしまいました。
そのときの設定内容を以下に記します。


DAV svn
SVNPath /var/svn/repos/test

ちなみに、http://localhost/project/test/ にアクセスすると、以下のような結果となってしまいます。

Not Found
The requested URL /project/test/ was not found on this server.

Locationディレクティブで正規表現を用いるのが悪いのかもしれないと思い、念のためLocationMatchディレクティブで試してみましたが、こちらもうまくいきませんでした。


DAV svn
SVNPath /var/svn/repos/test

#他にも正規表現の箇所を変更し、数パターン試してみましたがいづれもうまくいかず・・・

正規表現を利用した際のログを確認してみたところ、Errorログには何も出力されておらず、Accessログには、HTTPステータスコード404が返っていました。

127.0.0.1 - - [15/Oct/2008:01:17:55 +0900] "GET /unit/test/ HTTP/1.1" 404 338 "-" "Mozilla/5.0 (X11; U; Linux x86_64; ja; rv:1.9.0.3) Gecko/--------- Ubuntu/8.04 (hardy) Firefox/3.0.3"

404が返っているためNotFoundで間違いないですね。

ここで行き詰った感があったので、システムコールをトレースできるstraceコマンドで、正規表現を利用せず正常に動作するパターンと、正規表現を利用して動作がおかしくなるパターンのトレースログを比較してみます。

Locationディレクティブで正規表現を利用せず正常に動作するパターン

$ sudo strace -p [ApacheのプロセスID]
Process 14352 attached - interrupt to quit
restart_syscall(<... resuming interrupted call ...>

・・・(略)

) = 1
read(8, "GET /project/test/ HTTP/1.1\r\nHost: "..., 8000) = 494
stat("/var/www/project/test/", 0x7fff5ef905f0) = -1 ENOENT (No such file or directory)
lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/var/www/project", 0x7fff5ef905f0) = -1 ENOENT (No such file or directory)

open("/var/www/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|0x80000) = 9
fstat(9, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
getdents(9, /* 4 entries */, 4096) = 120
getdents(9, /* 0 entries */, 4096) = 0
close(9) = 0
open("/var/svn/repos/test/db/current", O_RDONLY) = 9
read(9, "0 1 1\n", 80) = 6
close(9) = 0
open("/var/svn/repos/test/db/revs/0", O_RDONLY) = 9
fstat(9, {st_mode=S_IFREG|0644, st_size=115, ...}) = 0
lseek(9, 115, SEEK_SET) = 115
lseek(9, 51, SEEK_SET) = 51
read(9, "ext: 0 0 4 4 2d2977d1c96f487abe4"..., 4096) = 64
lseek(9, 17, SEEK_SET) = 17
read(9, "id: 0.0.r0/17\ntype: dir\ncount: 0"..., 4096) = 98
close(9) = 0
open("/var/svn/repos/test/db/revs/0", O_RDONLY) = 9
lseek(9, 17, SEEK_SET) = 17
read(9, "id: 0.0.r0/17\ntype: dir\ncount: 0"..., 4096) = 98
close(9) = 0
open("/var/svn/repos/test/db/revs/0", O_RDONLY) = 9
lseek(9, 17, SEEK_SET) = 17
read(9, "id: 0.0.r0/17\ntype: dir\ncount: 0"..., 4096) = 98
close(9) = 0
open("/var/svn/repos/test/db/revprops/0", O_RDONLY) = 9
read(9, "K 8\nsvn:date\nV 27\n2008-10-14T15:"..., 4096) = 50
close(9) = 0
open("/var/svn/repos/test/db/revs/0", O_RDONLY) = 9
lseek(9, 17, SEEK_SET) = 17
read(9, "id: 0.0.r0/17\ntype: dir\ncount: 0"..., 4096) = 98
close(9) = 0
writev(8, [{"HTTP/1.1 200 OK\r\nDate: Tue, 14 O"..., 343}, {"<html><head><title>Revision 0: /"..., 218}], 2) = 561
read(8, 0xa0e648, 8000) = -1 EAGAIN (Resource temporarily unavailable)
write(6, "127.0.0.1 - - [15/Oct/2008:01:09"..., 186) = 186
poll(

Locationディレクティブで正規表現を利用して動作がおかしくなるパターン

$ sudo strace -p [ApacheのプロセスIP]
Process 13627 attached - interrupt to quit
restart_syscall(<... resuming interrupted call ...>

・・・(略)

) = 1
read(8, "GET /project/test HTTP/1.1\r\nHos"..., 8000) = 397
stat("/var/www/project/test", 0x7fff86bb01f0) = -1 ENOENT (No such file or directory)
lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/var/www", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/var/www/project", 0x7fff86bb01f0) = -1 ENOENT (No such file or directory)
open("/var/www/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|0x80000) = 9
fstat(9, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
getdents(9, /* 4 entries */, 4096) = 120
getdents(9, /* 0 entries */, 4096) = 0
close(9) = 0
open("/var/svn/repos/test/db/current", O_RDONLY) = 9
read(9, "0 1 1\n", 80) = 6
close(9) = 0
open("/var/svn/repos/test/db/revs/0", O_RDONLY) = 9

fstat(9, {st_mode=S_IFREG|0644, st_size=115, ...}) = 0
lseek(9, 115, SEEK_SET) = 115
lseek(9, 51, SEEK_SET) = 51
read(9, "ext: 0 0 4 4 2d2977d1c96f487abe4"..., 4096) = 64
lseek(9, 17, SEEK_SET) = 17
read(9, "id: 0.0.r0/17\ntype: dir\ncount: 0"..., 4096) = 98
close(9) = 0
open("/var/svn/repos/test/db/revs/0", O_RDONLY) = 9
lseek(9, 17, SEEK_SET) = 17
read(9, "id: 0.0.r0/17\ntype: dir\ncount: 0"..., 4096) = 98
close(9) = 0
open("/var/svn/repos/test/db/revs/0", O_RDONLY) = 9
lseek(9, 17, SEEK_SET) = 17
read(9, "id: 0.0.r0/17\ntype: dir\ncount: 0"..., 4096) = 98
close(9) = 0
writev(8, [{"HTTP/1.1 404 Not Found\r\nDate: Tu"..., 272}, {"
read(8, 0x9f6608, 8000) = -1 EAGAIN (Resource temporarily unavailable)
write(6, "127.0.0.1 - - [15/Oct/2008:00:58"..., 189) = 189
poll(

考察

この2パターンの結果を比較してみると、正規表現を利用したときとしていないときでは、ログの後半のwritevの箇所が異なっていることがわかります。
正規表現を利用した場合であっても、/var/svn/repos/test/db/revs/0 をOPENできていることが確認できます。
mod_dav_svn を利用しない場合は、Locationディレクティブで正規表現も利用できるため、ApacheのCoreではなく mod_dav_svn の方に問題がありそうです。

今の実力ではここまでしか追及できず。

悔しい・・・悔しい・・・悔し過ぎる!!!

対応策

できないことがわかったならば、代替案を考えるというのも技術。
代替案としては、2パターンがすぐに思いつきます。

  • mod_rewriteでアクセスURIを書き換える
  • Locationディレクティブで正規表現を利用せず、複数のLocationディレクティブを定義する

前者はある特定の条件の際にうまく動作しない場合があることが調査でわかりましたので、今回は後者の案で乗り切ることにしたいと思います。


DAV svn
SVNPath /var/svn/repos/test



DAV svn
SVNPath /var/svn/repos/test

mod_rewriteで書き換えた場合、どのようなシーンで問題となるかについては、
#近日中にエントリをあげたいと思います。

最後に

現時点ではまだ結論が出せていませんので、有識者の方はどんなことでもいいですのでアドバイスしていただけるとうれしいです。