てきとうなメモ

本の感想とか技術メモとか

ServletRequest#setCharacterEncodingする時の注意事項

setCharacterEncoding
void setCharacterEncoding(java.lang.String env)
    throws java.io.UnsupportedEncodingException

このリクエストのメッセージボディで使われている文字エンコーディング名を上書きします。 このメソッドはリクエストのパラメータを読み込む前に、また getReader() メソッドを使って入力ストリームから読み込む前に実行されなければなりません。

http://mergedoc.sourceforge.jp/tomcat-servletapi-5-ja/javax/servlet/ServletRequest.html#setCharacterEncoding(java.lang.String)

というわけなので、今回のStruts脆弱性対応のFilterなどrequestのパラメタを読み込むフィルターをsetCharacterEncodingするフィルターの前に入れてしまうとうまくいかなくなる。

これはパラメタの値だけでなくパラメタ名を読み込む場合でも同じらしくgetParameterNames()などをつかうとsetCharacterEncodingがうまく実行されない。

Tomcat6のコードだとこんな感じ

    public Enumeration getParameterNames() {

        if (!parametersParsed)
            parseParameters();

        return coyoteRequest.getParameters().getParameterNames();

    }

事前にparametersParsedでパラメタがparse済みかどうかチェックして、parseParameters()で文字コードを設定している

    protected void parseParameters() {

        parametersParsed = true;

        Parameters parameters = coyoteRequest.getParameters();
        // Set this every time in case limit has been changed via JMX
        parameters.setLimit(getConnector().getMaxParameterCount());

        // getCharacterEncoding() may have been overridden to search for
        // hidden form field containing request encoding
        String enc = getCharacterEncoding();

        boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
        if (enc != null) {
            parameters.setEncoding(enc);
            if (useBodyEncodingForURI) {
                parameters.setQueryStringEncoding(enc);
            }
        } else {
            parameters.setEncoding
                (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
            if (useBodyEncodingForURI) {
                parameters.setQueryStringEncoding
                    (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
            }
        }
    ...
    }