久しぶりに記事を書いてみます。
今回はApache+Tomcatで2GB以上のファイルを扱う方法です。2GB以上のファイルがアップできないよーと言われたのが発端なのですが、まぁちょっと調べてみました。(2GB以上をアップする事なんて普通無いだろうと思うわけですが、それが結構あるんですよw)2GBの壁ということはsigned intのMAXという事になります。
問題になったシステムはSolaris10_x86(uいくつか忘れた。たぶん5くらい?w)にApache2.2.11+mod_proxy_ajp+Tomcat6.0.18 (JDK6u13)という構成です。原因はいくつかありますが、順番にチェックしていきました。
まずはログを調べてみたらTomcatがparseLongでエラーを吐いている。Content-Lengthの値がおかしいという事で、Tomcatにデバッガをしかけてチェック!。どうやら値がマイナス値のご様子。この時点でTomcatは悪くないという事に。(ちなみにTomcat6.0.13だとparseIntを使っているので注意)
次に簡単に調べられるところは、、、ApacheのログでContent-Lengthを出力するようにしてみた(${Content-Length}i)。見事にマイナス値。
この時点でおかしいのはApacheかブラウザという事に。
ブラウザが対応していないのではないか?説。
確かに検索をしてみるとブラウザによっては2GB以上のファイルはそもそもブラウザ側がPOST制限をかけている場合があるようです。その回避策としてはFLASHやJavaアプレットで分割させたりしましょうというらしい。で、問題になっているシステムはFlashでアップロードしていたのでした。どんな値を送っているのかな。と思ってWireSharkでパケットキャプチャ。ここでは見事に4GB以上のファイルも正の値で送信されていました。
原因はApacheにあり!
という事でApacheにログを仕込んでビルドしようと思ったけど、ビルドの時間を待つのが耐えられないのでソースを追ってみた。Content-Lengthでソースを検索すればそれっぽいのがいっぱい出てくる。server/util_script.cで処理しているみたい。さらにソースを読み進めていきます。
リクエストの情報はrequest_recという構造体に格納するようになっていて、Content-Lengthはそのclengthというメンバに格納される。この型はapr_off_t。これはsrclib/apr.hで定義されていてoff_tのtypedefである。で、off_tっていうのはlongで定義されているわけです。つまり32ビット!謎はとけました。
Solarisのマニュアルはこちら http://jp.sun.com/practice/software/solaris/jp/wp/Sol_file/sol_3.html
off_tを64ビット(long long)にするには、マクロを定義すればいいらしい。
Configure時にこうかな。「-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64」
本当は_FILE_OFFSET_BITS=64のみで良いらしいけど、一応前者もつけておく。
APR, APR-UTIL, Apacheをこのオプションつけてビルドすれば解決できそうです。
(ApacheだけあなくてAPRとAPR-UTILも必要ですよね・・?)
(追記)
家で見たソースはoff_tだったのに、問題のシステムのところのソースをみたらoff64_tで定義されてた。
あれー・・・。(´・ω・`)