Skip to content

Commit

Permalink
Add content type inference to static resources and files (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
lihaoyi authored Apr 4, 2023
1 parent 69abbc9 commit f2385a0
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 9 deletions.
22 changes: 15 additions & 7 deletions cask/src/cask/endpoints/StaticEndpoints.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,25 @@ package cask.endpoints
import cask.router.{HttpEndpoint, Result}
import cask.model.Request
object StaticUtil{
def makePath(t: String, ctx: Request) = {
(cask.internal.Util.splitPath(t) ++ ctx.remainingPathSegments)
def makePathAndContentType(t: String, ctx: Request) = {
val path = (cask.internal.Util.splitPath(t) ++ ctx.remainingPathSegments)
.filter(s => s != "." && s != "..")
.mkString("/")
}
val contentType = java.nio.file.Files.probeContentType(java.nio.file.Paths.get(path))

(path, Option(contentType))
}
}

class staticFiles(val path: String, headers: Seq[(String, String)] = Nil) extends HttpEndpoint[String, Seq[String]]{
val methods = Seq("get")
type InputParser[T] = QueryParamReader[T]
override def subpath = true
def wrapFunction(ctx: Request, delegate: Delegate) = {
delegate(Map()).map(t => cask.model.StaticFile(StaticUtil.makePath(t, ctx), headers))
delegate(Map()).map{t =>
val (path, contentTypeOpt) = StaticUtil.makePathAndContentType(t, ctx)
cask.model.StaticFile(path, headers ++ contentTypeOpt.map("Content-Type" -> _))
}
}

def wrapPathSegment(s: String): Seq[String] = Seq(s)
Expand All @@ -29,10 +35,12 @@ class staticResources(val path: String,
type InputParser[T] = QueryParamReader[T]
override def subpath = true
def wrapFunction(ctx: Request, delegate: Delegate) = {
delegate(Map()).map(t =>
cask.model.StaticResource(StaticUtil.makePath(t, ctx), resourceRoot, headers)
)
delegate(Map()).map { t =>
val (path, contentTypeOpt) = StaticUtil.makePathAndContentType(t, ctx)
cask.model.StaticResource(path, resourceRoot, headers ++ contentTypeOpt.map("Content-Type" -> _))
}
}


def wrapPathSegment(s: String): Seq[String] = Seq(s)
}
8 changes: 8 additions & 0 deletions example/todo/app/test/src/ExampleTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ object ExampleTests extends TestSuite{
test("TodoServer") - withServer(TodoServer){ host =>
val page = requests.get(host).text()
assert(page.contains("What needs to be done?"))

val cssResponse = requests.get(host + "/static/index.css")
assert(cssResponse.text().contains("font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;"))
assert(cssResponse.headers("content-type") == List("text/css"))

val jsResponse = requests.get(host + "/static/app.js")
assert(jsResponse.text().contains("initListeners()"))
assert(jsResponse.headers("content-type") == List("text/javascript"))
}
}

Expand Down
2 changes: 1 addition & 1 deletion example/todo/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import mill._, scalalib._
trait AppModule extends CrossScalaModule{

def ivyDeps = Agg[Dep](
ivy"org.xerial:sqlite-jdbc:3.18.0",
ivy"org.xerial:sqlite-jdbc:3.41.2.1",
ivy"io.getquill::quill-jdbc:3.4.10",
ivy"com.lihaoyi::scalatags:0.9.1",
)
Expand Down
2 changes: 1 addition & 1 deletion example/todoDb/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import mill._, scalalib._
trait AppModule extends CrossScalaModule{

def ivyDeps = Agg[Dep](
ivy"org.xerial:sqlite-jdbc:3.18.0",
ivy"org.xerial:sqlite-jdbc:3.41.2.1",
ivy"io.getquill::quill-jdbc:3.4.10"
)

Expand Down

0 comments on commit f2385a0

Please sign in to comment.