File uploads

Uploading files

File upload support is included within Scalatra by default by leveraging the Servlet 3.0 API’s built-in support for multipart/form-data requests. For a working example, see FileUploadExample.scala.

To enable file upload support, extend your application with FileUploadSupport and set the upload configuration with a call to configureMultipartHandling:

import org.scalatra.ScalatraServlet
import org.scalatra.servlet.{FileUploadSupport, MultipartConfig, SizeConstraintExceededException}

class MyApp extends ScalatraServlet with FileUploadSupport {
  configureMultipartHandling(MultipartConfig(maxFileSize = Some(3*1024*1024)))
  // ...
}

If you prefer using your web.xml over MultipartConfig, you can also place <multipart-config> in your <servlet>:

<servlet>
  <servlet-name>myapp</servlet-name>
  <servlet-class>com.me.MyApp</servlet-class>

  <multipart-config>
    <max-file-size>3145728</max-file-size>
  </multipart-config>
</servlet>

See the javax.servlet.annotation.MultipartConfig Javadoc for more details on configurable attributes.

Note for Jetty users: MultipartConfig and the <multipart-config> tag in web.xml do not work correctly in Jetty prior to version 8.1.3.

If you are embedding Jetty, you must either mount the servlet in your ScalatraBootstrap, or you must configure it via the ServletHolder:

  import org.scalatra.servlet.MultipartConfig
  // ...
  val holder = context.addServlet(classOf[YourScalatraServlet], "/*")
  holder.getRegistration.setMultipartConfig(
    MultipartConfig(
      maxFileSize = Some(3*1024*1024),
      fileSizeThreshold = Some(1*1024*1024)
    ).toMultipartConfigElement
  )
  // ...
}

Be sure that your form is of type multipart/form-data:

get("/") {
  <form method="post" enctype="multipart/form-data">
    <input type="file" name="thefile" />
    <input type="submit" />
  </form>
}

Your files are available through the fileParams or fileMultiParams maps:

post("/") {
  processFile(fileParams("thefile"))
}

To handle the case where the user uploads too large a file, you can define an error handler:

error {
  case e: SizeConstraintExceededException => RequestEntityTooLarge("too much!")
}

Scalatra wraps IllegalStateException thrown by HttpServletRequest#getParts() inside SizeConstraintExceededException for convenience of use. If the container for some reason throws an exception other than IllegalStateException when it detects a file upload that’s too large (or a request body that’s too large), or you are getting false positives, you can configure the wrapping by overriding the isSizeConstraintException method.

For example, Jetty 8.1.3 incorrectly throws ServletException instead of IllegalStateException. You can configure that to be wrapped inside SizeConstraintExceededExceptions by including the following snippet in your servlet:

override def isSizeConstraintException(e: Exception) = e match {
  case se: ServletException if se.getMessage.contains("exceeds max filesize") ||
                               se.getMessage.startsWith("Request exceeds maxRequestSize") => true
  case _ => false
}