Files

The Files module serves resources to clients, either one at a time with a fixed path or as a whole browsable directory tree. The content type of a file is automatically determined by its extension unless overridden.

Serving a Single File

Asset.from(...) accepts a resource, a java.nio.file.Path or a file path directly and serves it under the path it is mounted at:

Kotlin
val layout = Layout.create()
    .add("agb.pdf", Asset.from("/var/www/documents/agb.pdf"))

In this example, the file would be available at http://localhost:8080/agb.pdf. To force a specific content type instead of guessing it from the extension, use .type(...):

Kotlin
val asset = Asset.from("./data.bin").type(ContentType.ApplicationOctetStream)

Downloads

To have the browser download the file instead of rendering it inline, call .asDownload(...), optionally passing the file name to send to the client (falling back to the resource’s own name if omitted):

Kotlin
val layout = Layout.create()
    .add("agb.pdf", Asset.from("/var/www/documents/agb.pdf").asDownload())

Serving a Directory

Assets.from(...) serves a whole resource tree or directory, resolving the requested path against it:

Kotlin
val layout = Layout.create()

// serve all resources in the "static" folder of the classpath (src/main/resources/static)
val tree = ResourceTree.fromClasspath("static")

layout.add("res", Assets.from(tree))

// or, directly from a folder on disk
layout.add("files", Assets.from("./static"))

Host.create()
    .handler(layout)
    .run()

For example, a stylesheet named main.css in the styles subfolder would be made available at http://localhost:8080/res/styles/main.css.

Precompressed Files

If your build already produces precompressed variants of your static assets (e.g. main.css.br next to main.css), allowPrecompressed(...) lets the handler serve those directly instead of compressing the response on every request:

Kotlin
import org.genhttp.modules.compression.algorithms.BrotliAlgorithm
import org.genhttp.modules.files.Assets

val assets = Assets.from("./dist")
    .allowPrecompressed(BrotliAlgorithm())

With this configuration, a request for main.css with Accept-Encoding: br will be answered with the contents of main.css.br (falling back to main.css if no precompressed variant is found or accepted).