I'm attempting to create a controller method that serves a video file backed by some CMS-like database entry. My controller method looks like this:
def getVideo(id: Int) = DBAction { request => implicit dbSession =>
{ for {
dbFile <- fetchDBFile(id)
fsFile <- fetchFilesystemFile(dbFile)
rangeOpt <- request.headers.get(RANGE).map(_.replaceAll("bytes=", "").split("-").toList match {
case rangeStart :: rangeEnd :: Nil => Some(rangeStart.toLong, rangeEnd.toLong)
case rangeStart :: Nil => Some(rangeStart.toLong, fsFile.length())
case _ => None
})
(rangeStart, rangeEnd) <- rangeOpt
} yield SimpleResult(
header = ResponseHeader(
status = PARTIAL_CONTENT,
headers = Map(
CONTENT_TYPE -> MimeTypes.forExtension("mp4").get,
ACCEPT_RANGES -> "bytes",
DATE -> new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").format(new Date()),
CONTENT_LENGTH -> fsFile.length.toString,
CONTENT_RANGE -> s"bytes $rangeStart-$rangeEnd/${fsFile.length}",
CONNECTION -> "keep-alive"
)
),
body = Enumerator.fromStream(new FileInputStream(fsFile))
)
} getOrElse {
NotFound
}
}
It's mostly based on two sources to implement the logic to handle the specific byte range request necessary to serve videos.
When using either Chrome or Safari on OS X to access this controller method, the developer tools report that the request is cancelled - no response, be it a 200 or 404, is received. I have confirmed that the SimpleResponse is actually returned by this controller action on requests I expect it to deliver a good response, but either Play won't finish the response or my browsers won't accept it. Am I doing something wrong here in response, or have I stumbled upon a bug in the framework?
My Play version is 2.1.3.