| 11 | """ |
| 12 | |
| 13 | def process_response(self, request, response): |
| 14 | if response.status_code != 200 or not hasattr(response, "file_to_stream"): |
| 15 | return response |
| 16 | http_range = request.META.get("HTTP_RANGE") |
| 17 | if not (http_range and http_range.startswith("bytes=") and http_range.count("-") == 1): |
| 18 | return response |
| 19 | if_range = request.META.get("HTTP_IF_RANGE") |
| 20 | if if_range and if_range != response.get("Last-Modified") and if_range != response.get("ETag"): |
| 21 | return response |
| 22 | f = response.file_to_stream |
| 23 | statobj = os.fstat(f.fileno()) |
| 24 | start, end = http_range.split("=")[1].split("-") |
| 25 | if not start: # requesting the last N bytes |
| 26 | start = max(0, statobj.st_size - int(end)) |
| 27 | end = "" |
| 28 | start, end = int(start or 0), int(end or statobj.st_size - 1) |
| 29 | assert 0 <= start < statobj.st_size, (start, statobj.st_size) |
| 30 | end = min(end, statobj.st_size - 1) |
| 31 | f.seek(start) |
| 32 | old_read = f.read |
| 33 | f.read = lambda n: old_read(min(n, end + 1 - f.tell())) |
| 34 | response.status_code = 206 |
| 35 | response["Content-Length"] = end + 1 - start |
| 36 | response["Content-Range"] = "bytes %d-%d/%d" % (start, end, statobj.st_size) |
| 37 | return response |
| 38 | |
| 39 | |
| 40 | def to_django_header(header): |