You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

77 lines
2.7 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. import os
  2. from django.conf import settings
  3. from django.contrib.auth.middleware import RemoteUserMiddleware
  4. from django.utils.deprecation import MiddlewareMixin
  5. class RangesMiddleware(MiddlewareMixin):
  6. """Quick solution. See:
  7. https://stackoverflow.com/questions/14324250/byte-ranges-in-django/35928017#35928017
  8. """
  9. def process_response(self, request, response):
  10. if response.status_code != 200 or not hasattr(response, "file_to_stream"):
  11. return response
  12. http_range = request.META.get("HTTP_RANGE")
  13. if not (http_range and http_range.startswith("bytes=") and http_range.count("-") == 1):
  14. return response
  15. if_range = request.META.get("HTTP_IF_RANGE")
  16. if if_range and if_range != response.get("Last-Modified") and if_range != response.get("ETag"):
  17. return response
  18. f = response.file_to_stream
  19. statobj = os.fstat(f.fileno())
  20. start, end = http_range.split("=")[1].split("-")
  21. if not start: # requesting the last N bytes
  22. start = max(0, statobj.st_size - int(end))
  23. end = ""
  24. start, end = int(start or 0), int(end or statobj.st_size - 1)
  25. assert 0 <= start < statobj.st_size, (start, statobj.st_size)
  26. end = min(end, statobj.st_size - 1)
  27. f.seek(start)
  28. old_read = f.read
  29. f.read = lambda n: old_read(min(n, end + 1 - f.tell()))
  30. response.status_code = 206
  31. response["Content-Length"] = end + 1 - start
  32. response["Content-Range"] = "bytes %d-%d/%d" % (start, end, statobj.st_size)
  33. return response
  34. def to_django_header(header):
  35. return f"HTTP_{header.replace('-', '_').upper()}"
  36. class HeaderAuthMiddleware(RemoteUserMiddleware):
  37. header = to_django_header(settings.HEADER_AUTH_USER_NAME)
  38. def process_request(self, request):
  39. if request.user.is_authenticated:
  40. return
  41. username = request.META.get(self.header)
  42. if not username:
  43. return
  44. super().process_request(request)
  45. self.process_user_groups(request.user, request.META)
  46. @classmethod
  47. def process_user_groups(cls, user, headers):
  48. if not user.is_authenticated:
  49. return
  50. groups = cls.parse_user_groups_from_header(headers)
  51. is_superuser = settings.HEADER_AUTH_ADMIN_GROUP_NAME in groups
  52. if user.is_superuser != is_superuser:
  53. user.is_superuser = is_superuser
  54. user.save()
  55. @classmethod
  56. def parse_user_groups_from_header(cls, headers):
  57. try:
  58. groups_header = headers[to_django_header(settings.HEADER_AUTH_USER_GROUPS)]
  59. except KeyError:
  60. return []
  61. else:
  62. return groups_header.split(settings.HEADER_AUTH_GROUPS_SEPERATOR)