うさ☆うさ日記 このページをアンテナに追加 RSSフィード

2006 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 05 | 06 |
2013 | 05 | 08 | 09 | 10 | 11 | 12 |
2014 | 08 |
2015 | 04 | 06 | 08 | 09 | 11 | 12 |
2016 | 01 | 02 | 04 | 05 | 09 | 11 | 12 |
2017 | 04 | 05 | 06 |

2009-01-20

[]ServletInputStreamを2回使う

個々のアクションとかの前処理段階で、HTTPリクエストに怪しいデータが入っていないかチェックするFilterを用意したりしていたんですが(・ω・)

これがmultipartのPOST(ファイルアップロードのある画面)の時に対応していないっていうんで、multipartの時の処理(内部的にはcommons-uploadを使用)を追加してみたところ、今度はアクションにパラメータが渡らないという状況に(;´Д`)


理由は、multipartのリクエストを解析するために使用しているServletInputStream(の実装)が再利用を考慮していないため、Filter内でServletInputStreamを使用してしまうと、アクションにパラメータを設定する際にはServletInputStreamのポインタがEOFになっているためですた(・ω・)

Tomcatの実装もWebLogicの実装も駄目ですね、reset()に対応していないし。


つーこって、下記の様なラッパーを用意して対応。

public class BufferedServletInputStream extends ServletInputStream {

    private ByteArrayInputStream inputStream;

    public BufferedServletInputStream(byte[] buffer) {
        this.inputStream = new ByteArrayInputStream( buffer );
    }

    @Override
    public int available() throws IOException {
        return inputStream.available();
    }

    @Override
    public int read() throws IOException {
        return inputStream.read();
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        return inputStream.read( b, off, len );
    }
}
public class BufferedServletRequestWrapper extends HttpServletRequestWrapper {

    private byte[] buffer;

    public BufferedServletRequestWrapper(HttpServletRequest request) throws IOException {
        super( request );

        InputStream is = request.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte buff[] = new byte[ 1024 ];
        int read;
        while( ( read = is.read( buff ) ) > 0 ) {
            baos.write( buff, 0, read );
        }

        this.buffer = baos.toByteArray();
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        return new BufferedServletInputStream( this.buffer );
    }
}

元のInputStreamからあらかじめバッファにデータを読み込んでおいて、それを元に都度InputStreamを作成するカンジですね。


使い方はこんなん(・ω・)

public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

    HttpServletRequest req = (HttpServletRequest)request;
    request = new BufferedRequestWrapper( req );

    InputStream is = request.getInputStream();

...

    chain.doFilter(request, response);
}

逆の処理として、レスポンスの書き換え(携帯用の絵文字変換、encodeURL()とか)に使用するBufferdServletOutputStream、BufferedServletResponseWrapperとかも用意したでよ(・∀・)

KatsuyaAndoKatsuyaAndo 2014/02/08 00:54 参考にさせていただきました。ありがとうございました。

tyrutyru 2016/10/01 02:32 大変助かります。ありがとうございます。
ちなみにサンプルコードのライセンスを伺ってもよろしいでしょうか?

machi_ponmachi_pon 2016/10/01 08:14 NYSLでいいっす。

tyrutyru 2016/10/02 03:05 ありがとうございます!

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証