Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

Spring Frameworkのmax-file-sizeによるアップロードファイルサイズ制限のまとめ

satob.hatenablog.com

  • application.propertiesspring.servlet.multipart.max-file-size=100のように設定することでサイズ制限設定可能。
    • Spring Frameworkのファイルアップロード機能は、Webコンテナが持っているmultipartリクエストの処理機能をそのまま使う*1。ファイルサイズ上限のチェックに引っかかったときのスタックトレースを見ると、Tomcatではorg.apache.tomcat.util.http.fileuploadパッケージが使われている。これにはcommons-fileuploadからコピーされてきたコードが使われている*2
    • Webコンテナのmultipartリクエストのサイズ制限機能は、web.xmlからも設定できる*3。プログラム内でも指定はできるが、指定をするためのMultipartConfigElementはSpringアプリケーション1つに対して1個のようなので*4、Controllerごと・URLごとのファイルサイズ制限は行えない模様*5
    • URLごとのファイルサイズ制限を指定するアノテーションググる@MultipartConfigがある。これはJavaEE仕様(javax.servlet.annotation.MultipartConfig)なので、少なくともSpringだけでは利用できない模様*6
  • max-file-sizeによって発生したエラーは、Controllerではハンドリングできない。URLごとに個別のファイルサイズ制限をしたい、またはファイルサイズ上限エラーのハンドリングをビジネスロジックの中で行い、ビジネスロジックのエラーとしてレスポンスに含めたいという場合は、MultipartFile#getSize()を呼び出して自分で判定を行う必要がある*7。例外としてはSpring Frameworkorg.springframework.web.multipart.MaxUploadSizeExceededExceptionを提供しているのでこれを使えばよい。
  • application.propertiesfile-size-thresholdがデフォルトなら、アップロードされたファイルは常に一時ファイルへ格納されJavaヒープ上には格納されないので、大きいファイルをアップロードされてJavaのヒープが溢れるといったことはなさそう。
  • 一時ファイルはリクエストが処理されたらすぐに削除されるので、ハウスキープ処理は基本的に必要なさそう。
  • 一時ファイルが作られる先は、OSのテンポラリディレクトリの下のtomcat.【ポート番号】.【Tomcatを立ち上げるたびに決まる乱数?】\work\Tomcat\【ホスト名】\以下。ファイル削除が必要な場合はそこを削除する。
01: POST /upload HTTP/1.1
02: HOST: localhost:8080
03: content-type: multipart/form-data; boundary=----WebKitFormBoundaryqx0dK5IFp8lW2Hjr
04: content-length: 500
05: 
06: ------WebKitFormBoundaryqx0dK5IFp8lW2Hjr
07: Content-Disposition: form-data; name="hoge"; filename="blob"
08: Content-Type: text/plain
09: 
10: piyo
11: ------WebKitFormBoundaryqx0dK5IFp8lW2Hjr
12: Content-Disposition: form-data; name="file"; filename="100.txt"
13: Content-Type: text/plain
14: Content-Length: 150
15: 
16: 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890............................................................
17: ------WebKitFormBoundaryqx0dK5IFp8lW2Hjr--
  • 上記のようなリクエストがあった場合、以下のように処理が行われる。
    • 4行目のContent-Lengthは必須。これがなかった場合、multipartリクエストとして扱われない(ファイル部分は無視されてしまう)。
    • 4行目のContent-Lengthからファイル部分のサイズを逆算するなどはしない。
    • 14行目のContent-Lengthはあってもなくてもよい。ChromeのAdvanced REST Clientの場合、14行目のContent-Lengthは付与されない。
    • 14行目のContent-Lengthがある場合、これを読み込んだ時点でmax-file-sizeとの比較が行われる。パスしなかった場合は即エラーとなり、以降のデータは読み込まれない。
    • 14行目のContent-Lengthがない場合は、16行目以降の内容を読み込み始める。max-file-sizeを超える内容を読み込んだ時点で即エラーとなる。エラーとなった場合、以降のデータは読み込まれない。
    • 14行目のContent-Lengthがあって、かつmax-file-sizeよりも小さい場合は、Content-Lengthがない場合と同じ処理になる。
    • 上記で「即エラーとなる」というのは、101バイト目を読み込んだ時点でエラーとなるわけではなく、もう少し(数十バイト?)読み込んでからエラーが返る。