|
[2007年01月31日]
各種プロトコル用文字コード変換プロキシの構成例を追加。
[2007年01月23日]
文字コード異常の例とDeleGateによる回避方法
を追加、
文字コード変換プロキシの問題点
加筆。
[2006年12月30日]
DeleGate
9.4.2
では、10年ばかり御無沙汰気味だった日本語文字コード変換機能
について見直しを行い、以下の拡張を行いました。
■ 文字コード変換リバースプロキシとしてのDeleGate |
■ リバースプロキシの構成 |
[http://www.com.dom:80] [http://serv:8880] client -------------------> DeleGate -------------------> HTTP-server |
[ DeleGateの起動コマンド ] delegated +=httpd.cnf [ httpd.cnf ファイルの内容 ] -P80 SERVER=http MOUNT="/* http://serv:8880/* nvhost=www.com.dom" URICONV=where:any PERMIT="http:serv:*" RELAY=no |
■ 文字コード変換プロキシ |
client <----- EUC-JP ------- DeleGate <===== Japanese ==== HTTP-server ------ EUC-JP ------> ------ EUC-JP -----> |
これが、DeleGateが当初から持っていた機能なのですが、これだけですと、逆に クライアント側からサーバへ、日本語テキストを送信する場合に問題が起こります。 典型的には検索エンジンへの検索語の送信や、掲示版への書き込みなどです。
まず、一般にクライアントは、サーバから返されたレスポンスの文字コードに 合わせてリクエストの文字コードを決定して送信します。 ここで、DeleGateによってレスポンスがサーバの文字コードと異なるコードに 変換され、クライアントがそのコードに合わせてリクエストを送信し、 サーバがその文字コードを認識してくれないと、文字化けが起こります。 また、一度もサーバからの応答を得ていない状態で、クライアントから日本語 を送信する場合には、文字コードはクライアントの一存で決められ、 サーバの期待する文字コードになっていない可能性があります。
このことから、DeleGate は 9.0.3以降、 上の例のように CHARCODE オプションによってサーバからのレスポンスに対して 文字コード変換を行った場合、サーバからのレスポンスの元の文字コードを Cookieに入れてクライアント送り、それを 次のリクエスト時に返送してもらうことで、サーバの文字コードを知り、 サーバ向けの文字コード変換を行うようになっています (ただし、サーバ向けの文字コード変換を明示的にCHARCODEオプションで 指定した場合(†1)には、そちらが優先します)。
ただこの方法には、サーバからの文字コードを一度も見ていない段階(あるいは それを記憶したCookieがクリアされた状態)でクライアントからのリクエストを サーバに中継する場合には、必要な文字コード変換が行えない、 という問題があります。
■ 文字コード変換リバースプロキシの構成 |
[http://www.com.dom:80] [http://serv:8880] client <----- UTF-8 ------- DeleGate <=================== HTTP-server ===================> DeleGate ----- EUC-JP ------> |
クライアント向けのレスポンス中の日本語コードの変換は、 CHARCODE=UTF-8 と指定します。 一方、サーバ向けのリクエスト中の文字コードの変換は CHARCODE=charcode:tosv のように指定します (†2)。
[ httpd.cnfの内容 ] -P80 SERVER=http MOUNT="/* http://serv:8880/* nvhost=www.com.dom" URICONV=where:any PERMIT="http:serv:*" RELAY=no CHARCODE=UTF-8 CHARCODE=EUC-JP:tosv |
最近のブラウザは、任意の文字コードに対応しているものが多いので、 サーバが受理するコードだけが限定されるという状況ならば、この例の クライアント向けの文字コード変換は不必要であるかも知れません (†3)。
ただし、一方を Unicode に、他方を JIS の文字セットに固定することで、 Unicode と JIS の文字セットの変換を行う際に、変換表を限定することで、 変換表に無い文字がコード変換時に自動的に除外されるという効果があり、 これが有効である場合が考えられます (現状のDeleGateでは、この変換の際に JIS X 0213 文字セット中の文字 が自動的に除外されます)。 また、EUC-JPあるいはISO-2022-XX系から Shift_JIS への変換でも同様です (補助漢字が自動的に除外されます)。
■ 文字コード変換プロキシの問題点 |
■ 日本語テキストの検出・文字コードの判別の問題
サーバ向けの文字コード変換は、リクエストヘッダのURLの中、 およびPOSTリクエストのボディ(†p1)の中に、 %XX%XX (URLのエスケープ表記) あるいは &#ddddd; (Unicode文字のHTML表記) のようにエンコードされた日本語テキストに対して適用されます。 (†p2) ここで、%XX%XX の形式でエンコードされたものについては、 それが日本語テキストであるのか、またどの日本語コードで表現され ているのかは、どこにも指示されていません。このため一つの文字列が、例えば EUC-JP としても Shift_JIS としても解釈可能な場合、 変換結果が期待通りにならない場合があります (†p3)。
■ サーバ固有の文字コード指示との不整合の問題
サーバ固有の何らかの形式で、リクエスト中の非ASCII文字の文字コードが指示 されている場合があります。(†p4) DeleGateがそのようなリクエスト中の日本語テキストに文字コード変換を行った 場合、併せてそのような指示も書換えないと、サーバ側での文字コードの判別を 誤らせることになります。 残念ながらそのような指示の形式は標準化されたものでなく、個別に対処する しかない、一般的な解決が困難な問題です。
■ 日本語文字コード間の文字セットの不整合の問題
DeleGate/9.4.2 現在、DeleGate がサポートしている(と思われる)日本語の 文字セットは、JIS X 0201, JIS X 0208, JIS X 0212 です。 文字コードは、ISO-2022-JP, EUC-JP, Shift_JIS および UTF-8 です。 ここで、文字コードの間で、表現できる文字セットは、それぞれに異なります。 例えば「半角カナ」は、ISO-2022-JP には含まれていないので、例えば Shift_JIS から ISO-2022-JP に変換すると、半角から全角に変換されます。 例えば EUC-JP でコード化されている「補助漢字」は、Shift_JIS に変換すると 失われます。 変換先のコードが存在しない場合その文字は(デフォルトでは)ゲタ記号(〓) にしています (†p5)。
■ Unicodeの問題
UTF-8 (Unicode文字セット) と JIS文字セットのコードと間の変換では、 Unicode.Org から配布されている変換表を、DeleGate の起動時に (CHARSET オプションが指定されている場合)、 DeleGate.ORG 経由でダウンロードして、用いています。 DeleGate/9.4.2 現在、用いているのは、OBSOLETE と分類されている変換表で、 これは JIS X 0213 を含んでいません。 今後、必要性があると判断された段階で、実装したいと思っています。 (Unihan.txt の表から日本語の文字コードを抽出することになると思います) なお、Unicode については、よく言われているように、JISコードとの間の変換が 一意でないという問題もあります。
■ 文字コード異常の例とDeleGateによる回避方法 |
■ 特定の文字コードにしか対応していないクライアント
もともと DeleGateの日本語文字コード変換の機能は、黎明期のウェブブラウザ
(日本語対応前の、Win/Mac 版 NCSA Mozaic)でとりあえず日本語が読めるよう、
追加されたものでした。
現在ではメジャーなHTTPのクライアントは、各種の日本語文字コードをサポート
しているので、この問題はほとんど無いでしょう。
ただ、HTTP以外のプロトコルにおいては、このような変換が必要な状況は未だに
あるようです。
この問題は、サーバからクライアントにテキストを中継する際に、文字コードを
クライアントがサポートしているものに変換してやることで回避できます。
例えばクライアントが EUC-JP に対応しているなら、
CHARCODE=euc-jp
のように指定します。
(†b1)
■ サーバへ送られるメール・ニュースの文字コードの統一
これもDeleGateの歴史的な用途として、ニュースリーダ(NNTPクライアント)から
投稿された記事の文字コードを、DeleGateでISO-2022-JP に強制変換してサーバに
送出するという機能が、しばらく使われていました。
この使われ方も、クライアント側の文字コード対応やネットニュースの衰退とともに、
現在ではほとんど見られなくなっていると思います。
現在では、メールを配送するSMTPの中継において、文字コードの強制や文字セットの
制限などを行う上で、必要性があるかも知れません。
メール・ニュースのケースは、受信者(の使用クライアントプログラム)が不特定
多数であるため、受理可能な文字コードが特定できない場合といえます。
このため、日本語メール・ニュースについては、推奨されている(はずの)
ISO-2022-JP に揃えるのが安全策(であるはず)です。
例えばサーバに送出(中継)するメッセージの文字コードを ISO-2022-JP に統一する
には、
CHARCODE=iso-2022-jp:tosv
のように指定します。
(†b2)
(†b3)
■ 文字コードが指示されていない日本語テキストによる字化け
サーバから送られて来た応答テキストが、どのような文字コードによるものか、
どこにも(HTTPやMIMEのヘッダにも、HTMLのMETAタグにも)指示されていない場合
があります。
この時、その文字コードが何であるかはクライアント(ブラウザ)側で推定する
ことになりますが、その自動判別に失敗した時や、デフォルトが非日本語の状態
に設定されている時に、字化けが発生します。
(†b4)
このようなケースの多くは、リバースプロキシあるいはクライアント側のDeleGate
において、応答の文字コードを推定し、HTTPヘッダ (Content-Type 中の charset
パラメタ) に指示してやることで、回避することができます。
DeleGateにこれを行わせるには、
CHARCODE=guess
のように指定します。
■ 文字コードが混在した日本語テキストによる字化け
サーバから送られて来た応答テキストが、複数の文字コードの混在したものである
場合があります。ほとんどのライアント(ブラウザ)はそれに対処してくれません
ので、ここで字化けが発生します。
(†b5)
これは、サーバ側で日本語文字コードを考慮せずに、複数のソースからのデータを
マージしてレスポンスを合成した場合などに発生します。
そもそも、このようなテキストは通常の規格上許容されていないものですし、
文字コードの自動判別がより困難になりますが、DeleGateではいくつかの
ケースについて、文字コードの混在した入力を判別して、対応しています。
このようなケースでもやはり、リバースプロキシあるいはクライアント側のDeleGate
において、特定の文字コードへのコード変換を行えば解消します。
例えば文字コードを EUC-JP に揃えるには、
CHARCODE=euc-jp
のように指定します。
■ サーバ側のサポートしない文字コードでのリクエストで字化け
検索サーバや掲示版への書き込みなど、クライアント側から送信した日本語
テキストの文字コードを、サーバ側で認識・受理できない場合に字化けが起こります。
この問題は、サーバ側がどの文字コードを受理できるかをクライアントが認識・考慮
していない場合や、そのコードに対処していない場合、そのコードで表現できない
文字を送ろうとする場合、などに発生します。
この問題は、DeleGateによってサーバ向けのデータ中の文字コードを適切に
変換してやることで回避することができます。
DeleGateをリバースプロキシとしての使用する場合など、対象サーバの数が
少なくその受理できる文字コードが特定できる場合には、
CHARCODE=euc-jp:tosv
あるいは、
CHARCODE=euc-jp:tosv:http:server1,server2
などと指定することで対応できます。
(HTTPの)クライアント側のプロキシで、対象サーバが特定できない場合、
クライアント向けの文字コード変換、例えば
CHARCODE=euc-jp
などを指定すると、クライアント向けの変換の際にサーバの元の文字コードを
Cookie中
(svcc) に記憶させ、
これに基づいてサーバ向けの文字コード変換を行います。
■ 各種プロトコル用文字コード変換プロキシの構成例 |
上述のような、拡張された CHARCODE パラメタによる文字コード変換が、 DeleGate/9.4.3 以降、HTTP以外のプロトコルにも適用できるようになりました。 (†c1) また、9.4.1で拡張された SOCKSTAP 機能を使用すると、SOCKS対応のクライアントソフトであれば、 プロキシで仲介していることをユーザに意識させることなく、 文字コード変換を行うことができます。
■ 文字コード変換FTPプロキシ |
さて、DeleGateを FTPプロキシとして実行するには、以下の例のように実行します。
delegated -P8021 SERVER=ftp |
delegated -P8021 SERVER=ftp CHARCODE=Shift_JIS |
delegated -P8021 SERVER=ftp CHARCODE=Shift_JIS CHARCODE=utf-8:tosv |
delegated -P1080 SERVER=socks SOCKSTAP=ftp CHARCODE=Shift_JIS |
[ DeleGateの起動コマンド ] delegated +=ftpd.cnf [ ftpd.cnf ファイルの内容 ] -P21 SERVER=ftp MOUNT="/* ftp://ftpserv:21/*" RELAY=no CHARCODE=Shift_JIS CHARCODE=utf-8:tosv |
■ 文字コード変換Telnetプロキシ |
Telnetでは一つのセッションの中で、複数の文字コードが混在したテキストを容易に 端末に送ることができますので、それによって、DeleGateによる入力文字コード認識の 状態が適切でなくなることがあります。そのような場合には、 ブレーク(control-Cなど)を送ってやると、文字コード認識状態を初期化できます。
無変換中継プロキシ:
delegated -P23 SERVER=telnet://server |
delegated -P23 SERVER=telnet://server CHARCODE=iso-2022-jp CHARCODE=Shift_JIS:tosv |
delegated -P23 SERVER=telnet CHARCODE=iso-2022-jp |
delegated -P1080 SERVER=socks SOCKSTAP=telnet CHARCODE=iso-2022-jp:tocl:telnet |
■ 文字コード変換POPプロキシ |
無変換中継プロキシ:
delegated -P110 SERVER=pop://server |
delegated -P110 SERVER=pop://server CHARCODE=EUC-JP |
delegated -P110 SERVER=pop CHARCODE=iso-2022-jp |
delegated -P1080 SERVER=socks SOCKSTAP=pop CHARCODE=iso-2022-jp:tocl:pop |
■ 文字コード変換SMTPプロキシ |
無変換中継プロキシ:
delegated -P25 SERVER=smtp://server |
delegated -P25 SERVER=smtp://server CHARCODE=iso-2022-jp:tosv |
■ 文字コード変換SOCKSプロキシ |
delegated -P1080 SERVER=socks SOCKSTAP=ftp,telnet,pop CHARCODE=iso-2022-jp |
PageViews: 4,684 hits / 384 nets |
以下は、DeleGate の参照マニュアル Manual.htm からの抜粋です。
The pseudo code name "guess" means not doing conversion but supplement
the "charset" attribute in "Content-Type" header in a message
when it is lacking, guessing it from the body of the message.
This is useful when a viewer program (ex. a web browser)
of the message is not localized to Japanese thus non-ASCII codes like
EUC-JP are guessed as European or so by the viewer.
If "tosv" is specified, the conversion is applied to
the request message (or a message toward a server).
The conversion is also applied to fragments of Japanese text in a HTTP request
message encoded in "%XX" in its request URL or in the body of a POST
message (when it is encoded in Content-Type: application/x-www-form-urlencoded).
The set of values of Content-Type to which the conversion is applied can be
specified with HTTPCONF=post-ccx-type.
The application of the conversion can be limited only to a specified
set of protocols, servers and clients specified with connMap.
In the connMap, the default value of ProtoList,
dstHostList and srcHostList is "*" which matches
any protocols or hosts.
Example: send response in UTF8 to clients and send request
in Shift_JIS to HTTP servers
For the FTP protocol, the conversion is applied only to the data
of the ASCII type relayed on the data-connections by default.
It is applied also to binary data or data on the control-connection
with FTPCONF="ccx:any".
To enable this parameter for internet-mail/news protocols
(SMTP, POP and NNTP),
also MIMECONV parameter must be specified
so that it enables character conversion (enabled by default).
A HTTP client can override this specification by sending its choice
in "Accept-Language" field in a request message,
which may be configurable in each client (WWW browser).
For example, if
"Accept-Language: (charcode=EUC)" is sent in a request from client,
the response text will be converted into EUC regardless of CHARCODE
specification of the DeleGate. If
"Accept-Language: (charcode=THRU)" is specified,
any conversion specified by the administrator of this DeleGate is disabled.
A character to be mapped is represented in a hexa-decimal value of it
(represented in more than 2 columns), or a direct character in a single columns.
The characters in the JIS X 0208 character set encoded in the variants of its
encoding (ISO-2022-JP, EUC-JP, and Shift_JIS) are represented in
its JIS code value without the most significant bits (8080) as "2121".
The characters in the JIS X 0212 character set are represented in its
JIS code value prefixed with "1" as "1222F".
The mapType is one of followings:
Example: reverse lowercase and upper case
Example: "rot13" encoding
Example: replace any Japanese character in JIS X 0208 with "GETA MARK"
Example: replace any Japanese character in JIS X 0212 with "GETA MARK"
Example: represents unknown characters by "WHITE SQUARE" instead of "GETA MARK"
CHARCODE parameter* == CHARCODE=[inputCode/]outputCode[:[tosv][:connMap]]
outputCode == charCode
charCode == iso-2022-jp | euc-jp | shift_jis | utf-8 | us-ascii |
JIS | EUC | SJIS | UTF8 | ASCII | guess
connMap == [ProtoList][:[dstHostList][:[srcHostList]]]
-- restriction: applicable to HTTP, FTP, SMTP, POP,
NNTP, Telnet, Tcprelay
-- default: none
If specified, DeleGate will convert the JIS code in text type response
message into the specified character code.
When UTF8 is specified, a mapping table necessary for conversion between
Unicode and JIS code is downloaded automatically from the server
at Unicode.Org via DeleGate.ORG.
CHARMAP parameter* == CHARMAP=mapType:charMap[,charMap]*[:tosv]
mapType == ascii | ucs | jis | ucsjis | jisucs
charMap == inCharCode1[-inCharCode2]/outCharCode2[-[outCharCode2]]
charCode == hexa-decimal code | single ASCII character
-- default: none
If specified, a character in texts relayed in a message of an application
protocol is mapped to another character.
By default, the mapping is applied to the response data to client.
It can be applied to the request data to server specifying ":tosv".
If inCharCode2 and outCharCode2 is specified, each character in
the range is mapped to the corresponding character.
If no -outCharCode2 is given, any input characters in the range
is mapped to outCharCode1.
CHARMAP=ascii:a-z/A-Z,A-Z/a-z
CHARMAP=ascii:a-m/n-z,n-z/a-m,A-M/N-Z,N-Z/A-M
CHARMAP=jis:0100-7F7F/222E
CHARMAP=jis:10000-1FFFF/222E
CHARMAP=jis:0000/2222