Servir un fichier¶
Objectif : relire un fichier stocké via serve_media_file, sans jamais
laisser sortir de la racine d'upload.
Ce que vous allez apprendre : serve_media_file prend un chemin relatif,
vérifie qu'il reste dans la racine d'upload (anti-traversal), et renvoie le fichier,
ou 404 s'il est absent ou le chemin invalide.
Troisième palier du niveau débutant de la progression files.
Module opt-in
Ce starter suppose forge-mvc-files installé (palier « Installation »).
Ce que ce starter montre¶
- une page d'explication + un champ pour un chemin de fichier ;
serve_media_file(path)qui renvoie le fichier (ou404) ;- la protection anti-traversal intégrée (un
../est refusé).
Classes Forge utilisées¶
| Classe / fonction | Rôle dans ce starter | Référence |
|---|---|---|
forge_mvc_files.serve_media_file |
Servir un fichier par son chemin relatif, anti-traversal + 404. | Médias |
request.query(...) |
Lire le chemin demandé. | Request |
Tester¶
Stockez un fichier au palier précédent, notez son chemin, puis ouvrez
https://localhost:8000/file-serve et demandez-le. Un chemin ../secret est
refusé (404).
Le contrôleur¶
# mvc/controllers/file_serve_controller.py
from core.http.request import Request
from core.http.response import Response
from core.mvc.controller.base_controller import BaseController
from forge_mvc_files import serve_media_file
class FileServeController(BaseController):
"""Starter pédagogique : servir un fichier stocké, sans faille de chemin."""
@staticmethod
def index(request: Request) -> Response:
return BaseController.render(
"file_serve/index.html", context={}, request=request
)
@staticmethod
def download(request: Request) -> Response:
path = request.query("path") or ""
if not path:
return Response.text("Paramètre « path » requis.", status=400)
# serve_media_file gère lui-même l'anti-traversal et le 404.
return serve_media_file(path)
La vue¶
<!-- mvc/views/file_serve/index.html -->
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Servir un fichier — Forge</title>
</head>
<body>
<h1>Servir un fichier</h1>
<p>
Indiquez le <strong>chemin relatif</strong> d'un fichier stocké (celui
renvoyé par le palier « Stocker un document », p. ex.
<code>documents/mon-fichier-abcd.pdf</code>).
</p>
<form method="get" action="/file-serve/download">
<input type="text" name="path" placeholder="documents/..." required>
<button type="submit">Télécharger</button>
</form>
<p>
Un chemin qui tente de sortir de la racine d'upload (p. ex.
<code>../secret</code>) est <strong>refusé</strong> : <code>serve_media_file</code>
protège contre la traversée de répertoire et répond <code>404</code>.
</p>
</body>
</html>
La route¶
# mvc/routes.py
from mvc.controllers.file_serve_controller import FileServeController
with router.group("", public=True) as public:
public.add("GET", "/file-serve", FileServeController.index, name="file_serve_index")
public.add("GET", "/file-serve/download", FileServeController.download, name="file_serve_download")
Comprendre ce code¶
- On passe un chemin relatif (celui du
SavedUpload.path), jamais un chemin
absolu :serve_media_filerésout par rapport à la racine d'upload. - L'anti-traversal est dans la primitive, pas dans le contrôleur : impossible
d'oublier la garde. - Fichier absent ou chemin piégé →
404, jamais une fuite hors zone.
À retenir¶
- Servir un fichier = donner son chemin relatif à
serve_media_file. - La protection anti-traversal est portée par la primitive.
- Stocker (
save_upload) et servir (serve_media_file) sont les deux faces du
cycle de vie d'un fichier.
Après ce starter¶
Vous savez stocker et servir. La suite : comprendre pourquoi un fichier est
parfois refusé.