Pular para o conteúdo

Arquivos estáticos

CSS, imagens, downloads e a travessia de diretório que o Kiln recusa.

Servir uma pasta#

dataforge
server site on 8080:
    assets "/static" from "./www"

    route GET "/":
        respond html "<link rel=stylesheet href=/static/estilo.css>…"

/static/estilo.css passa a servir ./www/estilo.css. Uma pasta responde com o index.html de dentro dela, e o Content-Type sai do nome do arquivo.

`../` não escapa#

dataforge
GET /static/estilo.css               200
GET /static/../../../etc/passwd      403
GET /static/%2e%2e/%2e%2e/etc/passwd  403

O caminho é resolvido e comparado com a pasta declarada antes de qualquer arquivo ser aberto. Essa é a falha clássica de servidor de arquivos, e vale saber que ela está fechada.

Ainda assim: sirva só o que é público. O .git e o .env moram no mesmo disco, e uma pasta declarada larga demais entrega os dois de forma perfeitamente legítima.

Caminho relativo a quê?#

dataforge
adopt Arcane.OS as OS

server site on 8080:
    // relativo a de onde o usuário chamou — frágil
    assets "/static" from "./www"

    // relativo ao programa — sempre certo
    assets "/static" from OS.beside("../www")

OS.beside resolve a partir do arquivo .df em execução. Sem isso, rodar dataforge run src/main.df de duas pastas diferentes carrega — ou não carrega — arquivos diferentes, e o erro só aparece na máquina de outra pessoa.

Um arquivo específico#

dataforge
route GET "/manual.pdf":
    respond file "./docs/manual.pdf"

// forçando o download, com outro nome
route GET "/dados":
    respond Kiln.file("/tmp/export.csv", void, "dados-2026.csv")

Gerado na hora#

dataforge
route GET "/relatorio.xlsx":
    livro := Xls.new()
    Xls.sheet(livro, "Estoque", produtos_agora())
    Xls.save(livro, "/tmp/r.xlsx")
    respond file "/tmp/r.xlsx"

O arquivo não precisa existir antes do pedido. É assim que a loja-web entrega uma planilha com os dados do momento, fórmulas inclusive.

Cache#

Arquivos estáticos saem com Cache-Control: public, max-age=3600. Uma hora é curta o bastante para não atrapalhar durante o desenvolvimento e longa o bastante para valer a pena. Se você versiona os nomes (estilo.a1b2.css), sirva com um Kiln.header mais generoso.

Limite de corpo#

dataforge
Kiln.config(app, "limite_corpo", 5 * 1024 * 1024)   // 5 MB

O padrão é 10 MB, e um corpo maior é recusado com 413 antes de ser lido inteiro na memória. Sem esse limite, um POST de 2 GB derruba o processo — e ninguém precisa de permissão para tentar.