Play framework 1.2.7 で “Request exceeds 8192 bytes”が発生した
事象
Play framework 1.2.7 で実装した RestAPIに c# で実装した RestClient から GET /path/to/api?var1=hoge&var2=huga~以下省略
といった要領でQueryStringのパラメータを大量に設定すると logs/application.log に Request exceeds 8192 bytes
と出力され処理が異常終了します。
原因
ログのメッセージを出力しているのは play.server.PlayHandler#exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
です。
@Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { try { // If we get a TooLongFrameException, we got a request exceeding 8k. // Log this, we can't call serve500() Throwable t = e.getCause(); if (t instanceof TooLongFrameException) { Logger.error(t, "Request exceeds 8192 bytes"); } e.getChannel().close(); } catch (Exception ex) { } }
ならばと、例外 TooLongFrameException を送出している箇所を探すと、org.jboss.netty.handler.codec.http.HttpMessageDecoder.readLine(ChannelBuffer buffer, int maxLineLength)
でした。例外を送出する時に 変数 sb を確認すると、GET /path/to/api?var1=hoge&var2=huga~以下省略
が設定されていました。
private String readLine(ChannelBuffer buffer, int maxLineLength) throws TooLongFrameException { StringBuilder sb = new StringBuilder(64); int lineLength = 0; while (true) { byte nextByte = buffer.readByte(); if (nextByte == HttpCodecUtil.CR) { nextByte = buffer.readByte(); if (nextByte == HttpCodecUtil.LF) { return sb.toString(); } } else if (nextByte == HttpCodecUtil.LF) { return sb.toString(); } else { if (lineLength >= maxLineLength) { // TODO: Respond with Bad Request and discard the traffic // or close the connection. // No need to notify the upstream handlers - just log. // If decoding a response, just throw an exception. throw new TooLongFrameException( "An HTTP line is larger than " + maxLineLength + " bytes."); } lineLength ++; sb.append((char) nextByte); } } }
上限値の maxLineLength は HttpMessageDecoderのデフォルトコンストラクタで決まっていました。
対策
今回は時間の関係でQueryStringのパラメータ名を短くして対応しました。
が、maxLineLength の上限を引き上げるには play.server.play.server#getPipeline()
メソッドで行っている new HttpRequestDecoder()
に引数を指定すれば上限を引き上げられます。たぶん。
play-1.2.7.jar を作り直す必要があるので、QueryStringのパラメータ名を短くすることにしました。