Search code examples
scalaamazon-s3nettynio

Exception caught in RequestBodyHandler


below is the code when user uploads a video from mobile application to S3

def uploadVideo = Action(parse.multipartFormData) { implicit request =>
      try {
        var height = 0
        var width = 0
        request.body.files.map { mov =>
          var videoName = System.currentTimeMillis() + ".mpeg"
          amazonS3Client.putObject(bucketVideos, videoName, mov.ref.file)
        }
        val map = Map("result" -> "success")
        Ok(write(map))
      } catch {
        case e: Exception =>
          Ok(write(Map("result" -> "error")))
      }
  }

the above code work fine but in case user cancel while uploading of video then error occurs

    [error] play - Exception caught in RequestBodyHandler
java.nio.channels.ClosedChannelException: null
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.cleanUpWriteBuffer(AbstractNioWorker.java:434) ~[netty.jar:na]
    at org.jboss.netty.channel.socket.nio.AbstractNioWorker.writeFromUserCode(AbstractNioWorker.java:129) ~[netty.jar:na]
    at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.handleAcceptedSocket(NioServerSocketPipelineSink.java:99) ~[netty.jar:na]
    at org.jboss.netty.channel.socket.nio.NioServerSocketPipelineSink.eventSunk(NioServerSocketPipelineSink.java:36) ~[netty.jar:na]
    at org.jboss.netty.channel.Channels.write(Channels.java:725) ~[netty.jar:na]
    at org.jboss.netty.handler.codec.oneone.OneToOneEncoder.doEncode(OneToOneEncoder.java:71) ~[netty.jar:na]

and this doesn't go to catch block!!

1.can this is harmfull to server or not?(because it is not needed any response if error occours)

2.if yes, how to handle?


Solution

  • This is all happening in Play's internals that are handling parsing the body of the Request. In fact, during the upload to your server, you haven't even reached the try block yet because the file hasn't finished uploading. Only once the upload is complete do you have the TemporaryFile available.

    So no, you can't catch this error, and why would you want to? The user closed the connection. They're not even waiting for a response, so why send one? Let Play handle it.

    This is also not a good way of handling an upload, though. For small files, it's passable, but if someone is proxying a huge video upload through your server to S3, it's going to:

    1. Take almost twice is long to serve the response (which will cause the user to hang while you upload to S3).
    2. Block one of Play's threads for handling requests for the entire time that file is uploading to S3, and given enough of these uploads (not many at all), you will no longer be able to process requests until an upload has completed.

    Consider at least creating a separate ExecutionContext to use for handling uploads, or even better, look into having the user upload directly to S3 via a signed form, which would remove the need to proxy the upload at all.