๐Ÿ‘ a fluffy Gleam web server
23

Configure Feed

Select the types of activity you want to include in your feed.

add path traversal protection to file serving

authored by

Vladislav Shakitskiy and committed by
GitHub
(May 9, 2026, 10:34 AM +0300) a5f6cc55 3f9efe0a

+18
+9
README.md
··· 234 234 Static 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. 235 235 236 236 ```gleam 237 + import gleam/bool 237 238 import gleam/http/response 239 + import gleam/list 238 240 import gleam/string 239 241 240 242 fn serve_file(path: String) -> Response { ··· 243 245 // 244 246 let dir = absname("public") 245 247 let relative = string.drop_start(path, 1) 248 + let segments = string.split(relative, "/") 249 + 250 + use <- bool.guard( 251 + when: list.any(segments, fn(seg) { seg == ".." }), 252 + return: not_found(), 253 + ) 254 + 246 255 let resolved = absname_join(dir, relative) 247 256 248 257 case string.starts_with(resolved, dir <> "/") {
+9
examples/src/serving_files.gleam
··· 1 1 import ewe.{type Response} 2 + import gleam/bool 2 3 import gleam/erlang/process 3 4 import gleam/http/response 5 + import gleam/list 4 6 import gleam/option.{None} 5 7 import gleam/string 6 8 import logging ··· 26 28 // 27 29 let dir = absname("public") 28 30 let relative = string.drop_start(path, 1) 31 + let segments = string.split(relative, "/") 32 + 33 + use <- bool.guard( 34 + when: list.any(segments, fn(seg) { seg == ".." }), 35 + return: not_found(), 36 + ) 37 + 29 38 let resolved = absname_join(dir, relative) 30 39 31 40 case string.starts_with(resolved, dir <> "/") {