こんにちわ、北川です。
以前、Java1.5.x + Tomcat6.0.x の特定の組み合わせ、特定の条件下で 1バイトの文字が空白になる
という問題に遭遇したので tomcat users ML に確認したことがありました。
先日、Tomcat6 の RELEASE-NOTES を見ていると同様の問題に関して注意書きがあり
自分でも忘れているの備忘録として記載しておきます!
RELEASE-NOTESから抜粋
http://ftp.meisei-u.ac.jp/mirror/apache/dist/tomcat/tomcat-6/v6.0.37/RELEASE-NOTES
============================================
Multi-byte charset handling bug in Java 1.5:
============================================
Public versions of Sun/Oracle Java 1.5 are known to have a nasty bug in
implementation of Charset.decode() method for certain character sets.
For details, test and a list of affected character sets see:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196991
https://issues.apache.org/bugzilla/show_bug.cgi?id=52579
The UTF-8 charset is not affected by this issue.
原因
java.nio.charset.Charset.decode() メソッドを利用した場合 EUC-JPやShift_JIS,windows-31jなど特定の文字コードの場合、1バイト文字をデコードすると空文字にデコードされるという問題がありました。
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6196991
この問題は、java1.6 及び java 1.5.35 b31 で修正されています。
http://www.oracle.com/technetwork/java/javase/documentation/overview-137139.html#5.0u35-rev-b31
tomcat6.0.36のソースコードを確認してみると、 decodeメソッドを呼び出している箇所がありました。
/apache-tomcat-6.0.36-src/trunk/java/org/apache/tomcat/util/buf/ByteChunk.java
1 2 3 4 5 6 7 8 9 10 11 |
public String toStringInternal() { if (charset == null) { charset = DEFAULT_CHARSET; } // new String(byte[], int, int, Charset) takes a defensive copy of the // entire byte array. This is expensive if only a small subset of the // bytes will be used. The code below is from Apache Harmony. CharBuffer cb; cb = charset.decode(ByteBuffer.wrap(buff, start, end-start)); return new String(cb.array(), cb.arrayOffset(), cb.length()); } |
コミットログを確認してみると、6.0.33 の修正で上記のメソッドを利用するように修正されています。
対象のメソッドは、 Tomcat の web.xml で filters.SetCharacterEncodingFilter を設定すると呼び出されるので、
Tomcatに付属しているサンプルプログラムでも再現させることができます。
まとめ
原因は、Java の Bug によるものです。
Java 1.5.35 b31 未満とTomcat6.0.33 以上の組み合わせで発生しますので対応されたバージョンを利用しましょう。