Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/views/static.py: 18%

61 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1""" 

2Views and functions for serving static files. These are only to be used 

3during development, and SHOULD NOT be used in a production setting. 

4""" 

5import mimetypes 

6import posixpath 

7import re 

8from pathlib import Path 

9 

10from django.http import FileResponse, Http404, HttpResponse, HttpResponseNotModified 

11from django.template import Context, Engine, TemplateDoesNotExist, loader 

12from django.utils._os import safe_join 

13from django.utils.http import http_date, parse_http_date 

14from django.utils.translation import gettext as _ 

15from django.utils.translation import gettext_lazy 

16 

17 

18def serve(request, path, document_root=None, show_indexes=False): 

19 """ 

20 Serve static files below a given point in the directory structure. 

21 

22 To use, put a URL pattern such as:: 

23 

24 from django.views.static import serve 

25 

26 path('<path:path>', serve, {'document_root': '/path/to/my/files/'}) 

27 

28 in your URLconf. You must provide the ``document_root`` param. You may 

29 also set ``show_indexes`` to ``True`` if you'd like to serve a basic index 

30 of the directory. This index view will use the template hardcoded below, 

31 but if you'd like to override it, you can create a template called 

32 ``static/directory_index.html``. 

33 """ 

34 path = posixpath.normpath(path).lstrip("/") 

35 fullpath = Path(safe_join(document_root, path)) 

36 if fullpath.is_dir(): 

37 if show_indexes: 

38 return directory_index(path, fullpath) 

39 raise Http404(_("Directory indexes are not allowed here.")) 

40 if not fullpath.exists(): 

41 raise Http404(_("“%(path)s” does not exist") % {"path": fullpath}) 

42 # Respect the If-Modified-Since header. 

43 statobj = fullpath.stat() 

44 if not was_modified_since( 

45 request.META.get("HTTP_IF_MODIFIED_SINCE"), statobj.st_mtime, statobj.st_size 

46 ): 

47 return HttpResponseNotModified() 

48 content_type, encoding = mimetypes.guess_type(str(fullpath)) 

49 content_type = content_type or "application/octet-stream" 

50 response = FileResponse(fullpath.open("rb"), content_type=content_type) 

51 response.headers["Last-Modified"] = http_date(statobj.st_mtime) 

52 if encoding: 

53 response.headers["Content-Encoding"] = encoding 

54 return response 

55 

56 

57DEFAULT_DIRECTORY_INDEX_TEMPLATE = """ 

58{% load i18n %} 

59<!DOCTYPE html> 

60<html lang="en"> 

61 <head> 

62 <meta http-equiv="Content-type" content="text/html; charset=utf-8"> 

63 <meta http-equiv="Content-Language" content="en-us"> 

64 <meta name="robots" content="NONE,NOARCHIVE"> 

65 <title>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</title> 

66 </head> 

67 <body> 

68 <h1>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</h1> 

69 <ul> 

70 {% if directory != "/" %} 

71 <li><a href="../">../</a></li> 

72 {% endif %} 

73 {% for f in file_list %} 

74 <li><a href="{{ f|urlencode }}">{{ f }}</a></li> 

75 {% endfor %} 

76 </ul> 

77 </body> 

78</html> 

79""" 

80template_translatable = gettext_lazy("Index of %(directory)s") 

81 

82 

83def directory_index(path, fullpath): 

84 try: 

85 t = loader.select_template( 

86 [ 

87 "static/directory_index.html", 

88 "static/directory_index", 

89 ] 

90 ) 

91 except TemplateDoesNotExist: 

92 t = Engine(libraries={"i18n": "django.templatetags.i18n"}).from_string( 

93 DEFAULT_DIRECTORY_INDEX_TEMPLATE 

94 ) 

95 c = Context() 

96 else: 

97 c = {} 

98 files = [] 

99 for f in fullpath.iterdir(): 

100 if not f.name.startswith("."): 

101 url = str(f.relative_to(fullpath)) 

102 if f.is_dir(): 

103 url += "/" 

104 files.append(url) 

105 c.update( 

106 { 

107 "directory": path + "/", 

108 "file_list": files, 

109 } 

110 ) 

111 return HttpResponse(t.render(c)) 

112 

113 

114def was_modified_since(header=None, mtime=0, size=0): 

115 """ 

116 Was something modified since the user last downloaded it? 

117 

118 header 

119 This is the value of the If-Modified-Since header. If this is None, 

120 I'll just return True. 

121 

122 mtime 

123 This is the modification time of the item we're talking about. 

124 

125 size 

126 This is the size of the item we're talking about. 

127 """ 

128 try: 

129 if header is None: 

130 raise ValueError 

131 matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header, re.IGNORECASE) 

132 header_mtime = parse_http_date(matches[1]) 

133 header_len = matches[3] 

134 if header_len and int(header_len) != size: 

135 raise ValueError 

136 if int(mtime) > header_mtime: 

137 raise ValueError 

138 except (AttributeError, ValueError, OverflowError): 

139 return True 

140 return False