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

  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)