Coverage for api\views\media_views.py: 90.0%
32 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-30 20:58 +0200
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-30 20:58 +0200
1from django.http import Http404, HttpResponse
2from django.conf import settings
3from rest_framework.permissions import IsAuthenticated
4from rest_framework.decorators import api_view, permission_classes
5import os
6import mimetypes
9def _safe_path(filename):
10 """
11 Devuelve la ruta absoluta del fichero pedido, o `None` si se sale del sitio.
12 """
13 # Se rechaza lo que nunca puede ser un nombre de fichero
14 if not filename or filename in ('.', '..') or '/' in filename or '\\' in filename:
15 return None
17 base = os.path.realpath(os.path.join(settings.MEDIA_ROOT, 'profile_pics'))
18 full_path = os.path.realpath(os.path.join(base, filename))
20 if full_path != base and not full_path.startswith(base + os.sep): 20 ↛ 21line 20 didn't jump to line 21 because the condition on line 20 was never true
21 return None
23 return full_path
26@api_view(['GET'])
27@permission_classes([IsAuthenticated])
28def serve_protected_profile_picture(request, filename):
29 """
30 Endpoint para servir las imagenes de perfil, es necesario la autenticacion previa
31 Uso: GET /api/v1/media/profile_pics/{filename}
32 """
33 file_path = _safe_path(filename)
35 if file_path is None or not os.path.exists(file_path):
36 raise Http404
38 # Coge el tipo de contenido del archivo
39 content_type, _ = mimetypes.guess_type(file_path)
40 if content_type is None:
41 content_type = 'application/octet-stream'
43 # Se lee y se devuelve el archivo
44 try:
45 with open(file_path, 'rb') as f:
46 response = HttpResponse(f.read(), content_type=content_type)
47 response['Content-Length'] = os.path.getsize(file_path)
48 # Se añade un encabezado para controlar el chacheo del archivo
49 response['Cache-Control'] = 'max-age=3600' # Se pone por una hora
50 response['X-Content-Type-Options'] = 'nosniff'
51 return response
52 except IOError:
53 return HttpResponse("File could not be read", status=500)