2018年3月21日水曜日

Tomcatでポストサイズの上限を設定する

HTTP ConnectorにmaxPostSizeを設定するとポストサイズの上限を設定できるようなので動きを確認してみた。

確認用Servlet

確認用のServletではpostされた内容を標準出力にだしています。
override fun doPost(req: HttpServletRequest, resp: HttpServletResponse) {
    println("Content-Length: ${req.contentLengthLong}")
    println("parameter count: ${req.parameterMap.size}")
    req.parameterMap.forEach {
        println("${it.key}: ${it.value.joinToString(", ")}")
    }
    doGet(req, resp)
}

デフォルト設定で実行

デフォルト設定だと上限が2MBとなるのでエラーなどは発生しないでうまく処理が行われる。
➜  ~ curl http://localhost:8080/sample/hello --data-urlencode "param_key=値" -X POST -i     
HTTP/1.1 200 

サーバの標準出力の内容
Content-Length: 19
parameter count: 1
param_key: 値

maxPoolSizeを指定して実行

conf/server.xmlのConnector部分にmaxPostSizeの設定を追加する。簡単に上限を超えるように設定値は1バイトに。
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           maxPostSize="1"
           redirectPort="8443" />

デフォルトの設定だと、クライアントには200が返ってくる。
➜  ~ curl http://localhost:8080/sample/hello --data-urlencode "param_key=値" -X POST -i 
HTTP/1.1 200 

サーバのログを見ると、パラメータが存在しない状態でServletが呼び出されている。
このような場合、リクエストスコープのorg.apache.catalina.parameter_parse_failed_reasonの値(org.apache.tomcat.util.http.Parameters.FailReason)を見ると何が起きたかがわかるらしい。
Content-Length: 19
parameter count: 0

FailedRequestFilterを適用して実行

web.xmlにFailedRequestFilterを追加する。
<filter>
  <filter-name>failedRequestFilter</filter-name>
  <filter-class>org.apache.catalina.filters.FailedRequestFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>failedRequestFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Filterで指定サイズを超えた場合は処理を中断し、413 Request Entity Too Largeが返されるようになる。
➜  ~ curl http://localhost:8080/sample/hello --data-urlencode "param_key=値" -X POST -i 
HTTP/1.1 413 


ちなみにこのフィルターはapplication/x-www-form-urlencoded以外には影響を与えないようです。例えば、application/jsonの場合には下のように正常に処理が終わります。
➜  ~ curl http://localhost:8080/sample/hello -H "Content-Type: application/json" -d "{}"  -i   
HTTP/1.1 200