2007 年 4 月 9 日 23 時 58 分

フォームを受信したサーバ側の処理


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


フォームをブラウザが送信する時点では、
UTF-8 文字エンコーディングを使ったバイト表現として扱い、
それをパーセントエンコードすることによって文字列化し、
application/x-www-form-urlencoded で送信されていた。

では、その先を追いかけてみよう。

まずは、HTTP プロトコルだ。
ブラウザと Web サーバは HTTP で通信を行うため、
もし HTTP 自身に何かしらの制約があれば、
この時点で問題が起きることになる。

今回のケースでは、POST メソッドを使って送信するため、
フォームの内容は、エンティティボディとして、
ヘッダの後に送信されることになる。

HTTP のエンティティボディではバイナリ値が許容され、
任意の 8 ビット表現が利用可能である。
そもそも、パーセントエンコードによって変換されたので、
送信されるデータには ASCII 文字しか含まれていない。
つまり、HTTP の送信においては問題とはならない。

次は、フォームを受け取る Web サーバを考えてみよう。
Java アプリケーションの場合、リクエストは、
Servlet Container である Tomcat が受け取る。

Tomcat は受け取ったリクエストを元に、
HttpServletRequest オブジェクトを作成する。

Servlet は、HttpServletRequest オブジェクトを参照し、
リクエストの情報にアクセスするため、
HttpServletRequest から正常に値が取り出せなければ、
それを使う Servlet も正常に動作するはずがない。

ということで調べてみよう。

HttpServletRequest から、POST メソッドで送信された
データを読み取るには、3 種類の方法がある。

・getInputStream
・getReader
・getParameter 系

これらは排他的であるため、どれか 1 つしか使えない。
Servlet が POST されたデータにアクセスするためには、
必ず上記のどれかのメソッドを使う必要がある。

上のものほど水準が低くなっている。

getInputStream() は、HTTP リクエストで受け取った情報を、
加工なしにそのままバイトストリームとして取得する。
これでデータを読み出した場合、
application/x-www-form-urlencoded で符号化されたままの、
生のデータをバイト配列として読み出すことができる。

getReader() は、getInputStream() に、
InputStreamReader や BufferedReader を被せたものだ。
Reader は文字単位のストリームなので、
バイトから文字へのデータ変換が行われる。

このデータ変換には、Content-Type のパラメータ等で、
クライアントが指定した、文字エンコーディングが使われる。
これは getCharacterEncoding() で取得できる。
もしクライアントによる指定がなければ、
既定で ISO-8859-1(所謂、Latin-1)が使われる。

application/x-www-form-urlencoded の場合、
送信されるデータが ASCII の範囲に限られるため、
getCharacterEncoding の値に関係なく、
生のデータを文字列として読み出すことができる。
(US-ASCII は ISO-8859-1 のサブセットだから)

getParameter 系メソッドは、上記 2 つと違い、
application/x-www-form-urlencoded に特化している。
これらメソッドは符号化を自動的にデコードし、
Map のような形でデータを読み出せるようになっている。

getParameter や getParameterNames の説明を見てみると、
名前や値は、String として取得できるようになっている。
これも、getReader() と同様に
バイトから文字へのデータ変換が行われる。

さて、Struts はフォームからのデータの読み取りに、
getParameter 系のメソッドを利用している。

と、ここまでの分析を元に考えてみると、
どうも getParameter 系の挙動があやしそうである。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.