def streamTargetContent()

in app/controllers/Application.scala [138:202]


  def streamTargetContent(targetUriString:String) = IsAuthenticatedAsync { uid=> request=>
    val maybeTargetUri = Try {
      URI.create(targetUriString)
    }

    val maybeLocator = maybeTargetUri.flatMap(targetUri => OMLocator.fromUri(targetUri))

    /*
    look up the object, using cache if possible, and get hold of the metadata
     */
    val objectEntryFut = Future.fromTry(maybeLocator).flatMap(locator=>{
      (objectCache ? Lookup(locator)).mapTo[OCMsg].map({
        case ObjectNotFound(_) =>
          val auditFile = AuditFile("",locator.filePath)
          auditActor ! actors.Audit.LogEvent(AuditEvent.NOTFOUND, uid, Some(auditFile), Seq())
          Left(NotFound(GenericErrorResponse("not_found", s"no object at $targetUriString").asJson))
        case ObjectLookupFailed(_, err) =>
          val auditFile = AuditFile("",locator.filePath)
          auditActor ! actors.Audit.LogEvent(AuditEvent.OMERROR, uid, Some(auditFile), Seq(),notes=Some(err.toString))
          logger.error(s"Could not look up object for $targetUriString: ", err)
          Left(InternalServerError(GenericErrorResponse("server_error", s"lookup failed for $targetUriString").asJson))
        case ObjectFound(_, objectEntry) =>
          Right(objectEntry)
      })
    })


    /*
    break down the ranges header into structured data
     */
    val rangesOrFailureFut = Future.fromTry(request.headers.get("Range") match {
      case Some(hdr)=>RangeHeader.fromStringHeader(hdr)
      case None=>Success(Seq())
    })

    /*
    get hold of a streaming source, if possible
     */
    //maybeLocator.get is safe because if maybeLocator is a Failure we don't execute this block
    val srcOrFailureFut = getSourceFuture(maybeLocator.get, objectEntryFut, rangesOrFailureFut, uid)

    /*
    now either manifest the source to stream data to the client or output an error response to explain why we couldn't
     */
    srcOrFailureFut.map({
      case Right((byteSource, maybeResponseSize, headers, maybeMimetype, isPartialTransfer)) =>
        logger.info(s"maybeResponseSize is $maybeResponseSize")

        Result(
          ResponseHeader(if(isPartialTransfer) 206 else 200, headers),
          HttpEntity.Streamed(byteSource.log("outputstream").addAttributes(
            Attributes.logLevels(
              onElement = Attributes.LogLevels.Info,
              onFailure = Attributes.LogLevels.Error,
              onFinish = Attributes.LogLevels.Info)), None, maybeMimetype)
        ) //we can't give a proper content length, because if we are sending multipart chunks that adds overhead to the request size.
      case Left(response)=>response
    }).recover({
      case err:BadDataError=>
        BadRequest(err.getMessage)
      case err:Throwable=>
        logger.error(s"Could not get data for $targetUriString: ", err)
        InternalServerError("see the logs for more information")
    })
  }