多くのWebサーバやAPサーバでは、サーバリソースの過剰な消費やDoS攻撃に対する対処として、アップロードの最大サイズが決められている。(厳密には、ブラウザから入力値やファイル等のデータを送信するためのPOSTメソッドの最大サイズである。)
Wildfly13でのアップロードサイズの扱いについて調べた。
Wildflyでの設定箇所と既定値
POSTの上限サイズは、サブシステムundertowのhttp-listener要素のmax-post-size値で定義する。
デフォルトは10MB(10,485,760バイト)、最小値は0、最大値は無制限(-1)である。詳細な定義についてはWildflyのリファレンスを参照のこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ... <subsystem xmlns="urn:jboss:domain:undertow:6.0" default-server="default-server" default-virtual-host="default-host" default-servlet-container="default" default-security-domain="other"> <buffer-cache name="default"/> <server name="default-server"> <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true" max-post-size="10485760"/> <https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/> <host name="default-host" alias="localhost"> <http-invoker security-realm="ApplicationRealm"/> </host> </server> <servlet-container name="default"> <jsp-config/> <websockets/> </servlet-container> </subsystem> ... |
アップロード上限を超えた場合の挙動
アップロード上下を超えたPOSTを実行した場合、サーバ側ではログファイルに次のように記録される。
Webアプリ側の例外ハンドラより前にWildfly(undertow)がRequestTooBigException例外をスローしている。
1 2 3 4 5 6 7 8 9 10 11 12 13 | ... Caused by: io.undertow.server.RequestTooBigException: UT000020: Connection terminated as request was larger than 10485760 at io.undertow.conduits.FixedLengthStreamSourceConduit.checkMaxSize(FixedLengthStreamSourceConduit.java:168) at io.undertow.conduits.FixedLengthStreamSourceConduit.read(FixedLengthStreamSourceConduit.java:229) at org.xnio.conduits.ConduitStreamSourceChannel.read(ConduitStreamSourceChannel.java:127) at io.undertow.channels.DetachableStreamSourceChannel.read(DetachableStreamSourceChannel.java:209) at io.undertow.server.HttpServerExchange$ReadDispatchChannel.read(HttpServerExchange.java:2337) at org.xnio.channels.Channels.readBlocking(Channels.java:294) at io.undertow.servlet.spec.ServletInputStreamImpl.readIntoBuffer(ServletInputStreamImpl.java:192) at io.undertow.servlet.spec.ServletInputStreamImpl.read(ServletInputStreamImpl.java:168) at io.undertow.server.handlers.form.MultiPartParserDefinition$MultiPartUploadHandler.parseBlocking(MultiPartParserDefinition.java:213) at io.undertow.servlet.spec.HttpServletRequestImpl.parseFormData(HttpServletRequestImpl.java:833) ... 54 more |
ブラウザ側では、次のようにサーバ側からネットワーク接続が切断(リセット)された旨を示す、ERR_CONNECTION_RESETエラー画面(Chromeの例)が表示される。
アップロード上限エラーのハンドリング方法の検討
アップロード上限を超過した場合は、アップロード上限を超えている旨のエラー画面を、ユーザに表示したい。
HTTPではリクエストの送信中に送信を中断して、応答コードを返す仕組みは存在せず、送信の完了を待たざるを得ない。送信の完了を待つために送信されるデータを全て受信すると、サーバリソースの枯渇を招く可能性がある。そうなると、サーバを保護するためにHTTP(TCP)の接続を切断せざるを得ないので、このような結果になっても仕方ないかと考えられます。
Wildflyのフロントにロードバランサや配置される場合、転送先のWildflyから接続をリセットされたことを検知して、内部サーバエラー(500系)のエラー画面を出すことは可能かもしれませんが、リセットされた理由までは分からないので「アップロード上限を超えている」をピンポイントで指摘することは難しいと思います。