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とかも用意したでよ(・∀・)