Move handling binary responses to a shared space

This commit is contained in:
Eike Kettner 2020-11-08 14:19:08 +01:00
parent d376ef3ef1
commit 8cc89fd3b7
2 changed files with 64 additions and 35 deletions

View File

@ -0,0 +1,54 @@
package docspell.restserver.http4s
import cats.data.NonEmptyList
import cats.effect._
import cats.implicits._
import docspell.backend.ops._
import bitpeace.FileMeta
import org.http4s._
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
import org.http4s.headers.ETag.EntityTag
import org.http4s.headers._
object BinaryUtil {
def withResponseHeaders[F[_]: Sync](dsl: Http4sDsl[F], resp: F[Response[F]])(
data: OItemSearch.BinaryData[F]
): F[Response[F]] = {
import dsl._
val mt = MediaType.unsafeParse(data.meta.mimetype.asString)
val ctype = `Content-Type`(mt)
val cntLen: Header = `Content-Length`.unsafeFromLong(data.meta.length)
val eTag: Header = ETag(data.meta.checksum)
val disp: Header =
`Content-Disposition`("inline", Map("filename" -> data.name.getOrElse("")))
resp.map(r =>
if (r.status == NotModified) r.withHeaders(ctype, eTag, disp)
else r.withHeaders(ctype, cntLen, eTag, disp)
)
}
def makeByteResp[F[_]: Sync](
dsl: Http4sDsl[F]
)(data: OItemSearch.BinaryData[F]): F[Response[F]] = {
import dsl._
withResponseHeaders(dsl, Ok(data.data.take(data.meta.length)))(data)
}
def matchETag[F[_]](
fileData: Option[FileMeta],
noneMatch: Option[NonEmptyList[EntityTag]]
): Boolean =
(fileData, noneMatch) match {
case (Some(meta), Some(nm)) =>
meta.checksum == nm.head.tag
case _ =>
false
}
}

View File

@ -1,6 +1,5 @@
package docspell.restserver.routes
import cats.data.NonEmptyList
import cats.effect._
import cats.implicits._
@ -10,14 +9,13 @@ import docspell.backend.ops._
import docspell.common.Ident
import docspell.restapi.model._
import docspell.restserver.conv.Conversions
import docspell.restserver.http4s.BinaryUtil
import docspell.restserver.webapp.Webjars
import bitpeace.FileMeta
import org.http4s._
import org.http4s.circe.CirceEntityDecoder._
import org.http4s.circe.CirceEntityEncoder._
import org.http4s.dsl.Http4sDsl
import org.http4s.headers.ETag.EntityTag
import org.http4s.headers._
object AttachmentRoutes {
@ -26,24 +24,13 @@ object AttachmentRoutes {
val dsl = new Http4sDsl[F] {}
import dsl._
def withResponseHeaders(
resp: F[Response[F]]
)(data: OItemSearch.BinaryData[F]): F[Response[F]] = {
val mt = MediaType.unsafeParse(data.meta.mimetype.asString)
val ctype = `Content-Type`(mt)
val cntLen: Header = `Content-Length`.unsafeFromLong(data.meta.length)
val eTag: Header = ETag(data.meta.checksum)
val disp: Header =
`Content-Disposition`("inline", Map("filename" -> data.name.getOrElse("")))
resp.map(r =>
if (r.status == NotModified) r.withHeaders(ctype, eTag, disp)
else r.withHeaders(ctype, cntLen, eTag, disp)
)
}
def withResponseHeaders(resp: F[Response[F]])(
data: OItemSearch.BinaryData[F]
): F[Response[F]] =
BinaryUtil.withResponseHeaders[F](dsl, resp)(data)
def makeByteResp(data: OItemSearch.BinaryData[F]): F[Response[F]] =
withResponseHeaders(Ok(data.data.take(data.meta.length)))(data)
BinaryUtil.makeByteResp(dsl)(data)
HttpRoutes.of {
case HEAD -> Root / Ident(id) =>
@ -59,7 +46,7 @@ object AttachmentRoutes {
for {
fileData <- backend.itemSearch.findAttachment(id, user.account.collective)
inm = req.headers.get(`If-None-Match`).flatMap(_.tags)
matches = matchETag(fileData.map(_.meta), inm)
matches = BinaryUtil.matchETag(fileData.map(_.meta), inm)
resp <-
fileData
.map { data =>
@ -82,7 +69,7 @@ object AttachmentRoutes {
for {
fileData <- backend.itemSearch.findAttachmentSource(id, user.account.collective)
inm = req.headers.get(`If-None-Match`).flatMap(_.tags)
matches = matchETag(fileData.map(_.meta), inm)
matches = BinaryUtil.matchETag(fileData.map(_.meta), inm)
resp <-
fileData
.map { data =>
@ -107,7 +94,7 @@ object AttachmentRoutes {
fileData <-
backend.itemSearch.findAttachmentArchive(id, user.account.collective)
inm = req.headers.get(`If-None-Match`).flatMap(_.tags)
matches = matchETag(fileData.map(_.meta), inm)
matches = BinaryUtil.matchETag(fileData.map(_.meta), inm)
resp <-
fileData
.map { data =>
@ -122,7 +109,7 @@ object AttachmentRoutes {
fileData <-
backend.itemSearch.findAttachmentPreview(id, user.account.collective)
inm = req.headers.get(`If-None-Match`).flatMap(_.tags)
matches = matchETag(fileData.map(_.meta), inm)
matches = BinaryUtil.matchETag(fileData.map(_.meta), inm)
resp <-
fileData
.map { data =>
@ -173,16 +160,4 @@ object AttachmentRoutes {
} yield resp
}
}
private def matchETag[F[_]](
fileData: Option[FileMeta],
noneMatch: Option[NonEmptyList[EntityTag]]
): Boolean =
(fileData, noneMatch) match {
case (Some(meta), Some(nm)) =>
meta.checksum == nm.head.tag
case _ =>
false
}
}