···234234Static files can be sent using [`ewe.file`](https://hexdocs.pm/ewe/ewe.html#file). It accepts a path and optional `offset`/`limit` parameters. This allows serving HTML pages, assets, or binary files with minimal effort.
235235236236```gleam
237237+import gleam/bool
237238import gleam/http/response
239239+import gleam/list
238240import gleam/string
239241240242fn serve_file(path: String) -> Response {
···243245 //
244246 let dir = absname("public")
245247 let relative = string.drop_start(path, 1)
248248+ let segments = string.split(relative, "/")
249249+250250+ use <- bool.guard(
251251+ when: list.any(segments, fn(seg) { seg == ".." }),
252252+ return: not_found(),
253253+ )
254254+246255 let resolved = absname_join(dir, relative)
247256248257 case string.starts_with(resolved, dir <> "/") {
+9
examples/src/serving_files.gleam
···11import ewe.{type Response}
22+import gleam/bool
23import gleam/erlang/process
34import gleam/http/response
55+import gleam/list
46import gleam/option.{None}
57import gleam/string
68import logging
···2628 //
2729 let dir = absname("public")
2830 let relative = string.drop_start(path, 1)
3131+ let segments = string.split(relative, "/")
3232+3333+ use <- bool.guard(
3434+ when: list.any(segments, fn(seg) { seg == ".." }),
3535+ return: not_found(),
3636+ )
3737+2938 let resolved = absname_join(dir, relative)
30393140 case string.starts_with(resolved, dir <> "/") {