Skip to content

Instantly share code, notes, and snippets.

@dcwatson
Last active May 6, 2023 20:10

Revisions

  1. dcwatson renamed this gist May 1, 2014. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. dcwatson created this gist May 1, 2014.
    59 changes: 59 additions & 0 deletions gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    from django.http import StreamingHttpResponse
    from wsgiref.util import FileWrapper
    import mimetypes
    import os
    import re

    range_re = re.compile(r'bytes\s*=\s*(\d+)\s*-\s*(\d*)', re.I)

    class RangeFileWrapper (object):
    def __init__(self, filelike, blksize=8192, offset=0, length=None):
    self.filelike = filelike
    self.filelike.seek(offset, os.SEEK_SET)
    self.remaining = length
    self.blksize = blksize

    def close(self):
    if hasattr(self.filelike, 'close'):
    self.filelike.close()

    def __iter__(self):
    return self

    def next(self):
    if self.remaining is None:
    # If remaining is None, we're reading the entire file.
    data = self.filelike.read(self.blksize)
    if data:
    return data
    raise StopIteration()
    else:
    if self.remaining <= 0:
    raise StopIteration()
    data = self.filelike.read(min(self.remaining, self.blksize))
    if not data:
    raise StopIteration()
    self.remaining -= len(data)
    return data

    def stream(request, path):
    range_header = request.META.get('HTTP_RANGE', '').strip()
    range_match = range_re.match(range_header)
    size = os.path.getsize(path)
    content_type, encoding = mimetypes.guess_type(path)
    content_type = content_type or 'application/octet-stream'
    if range_match:
    first_byte, last_byte = range_match.groups()
    first_byte = int(first_byte) if first_byte else 0
    last_byte = int(last_byte) if last_byte else size - 1
    if last_byte >= size:
    last_byte = size - 1
    length = last_byte - first_byte + 1
    resp = StreamingHttpResponse(RangeFileWrapper(open(path, 'rb'), offset=first_byte, length=length), status=206, content_type=content_type)
    resp['Content-Length'] = str(length)
    resp['Content-Range'] = 'bytes %s-%s/%s' % (first_byte, last_byte, size)
    else:
    resp = StreamingHttpResponse(FileWrapper(open(path, 'rb')), content_type=content_type)
    resp['Content-Length'] = str(size)
    resp['Accept-Ranges'] = 'bytes'
    return resp