def handle_request_range(self, file): # check if we have a range in the request ranges = None header_range = self.request.getHeader('Range', None) if_range = self.request.getHeader('If-Range', None) if header_range is not None: ranges = parseRange(header_range) if if_range is not None: # We delete the ranges, which causes us to skip to the 200 # response. return {} # XXX: multipart ranges not implemented if ranges and len(ranges) == 1: try: length = file.getSize() [(start, end)] = expandRanges(ranges, length) size = end - start self.request.response.setHeader('Content-Length', size) self.request.response.setHeader( 'Content-Range', 'bytes {0}-{1}/{2}'.format(start, end - 1, length)) self.request.response.setStatus(206) # Partial content return dict(start=start, end=end) except ValueError: return {} return {}
def index_html(self, REQUEST, RESPONSE=None): """Default view for VirtualBinary file""" ranges = None if RESPONSE is None: RESPONSE = REQUEST.RESPONSE if self.__content_class__ is None: # Build your own headers RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', self.size) else: # Call index_html method of content class with a fake # self.data attribute which will return empty value # Use this artifice to make sure content class is not loading # all data in memory since it is better to return a stream iterator # There is an exception with multiple range if REQUEST.environ.has_key('HTTP_RANGE'): ranges = parseRange(REQUEST.environ.get('HTTP_RANGE')) ## in case of mutiple range we don't know do with an iterator if ranges is not None and len(ranges) > 1: ## call normally OFS.image with data return self.__content_class__.index_html( self, REQUEST, RESPONSE) else: ### now we deal correctly with 304 header if self._if_modified_since_request_handler(REQUEST, RESPONSE): self.ZCacheable_set(None) return '' ### set correctly header RESPONSE.setHeader('Last-Modified', rfc1123_date(self._p_mtime)) RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', self.size) RESPONSE.setHeader('Accept-Ranges', 'bytes') self.ZCacheable_set(None) # This is a default header that can be bypassed by other products # such as attachment field. if RESPONSE.getHeader('content-disposition') is None: # headers are in lower case in HTTPResponse RESPONSE.setHeader('Content-Disposition', 'inline; filename="%s"' % self.filename) if ranges and len(ranges) == 1: ## is an range request with one range , ## return an iterator with this range [(start, end)] = ranges if end is None: end = self.size iterator = range_filestream_iterator(self.path, start, end, mode='rb') return iterator else: return filestream_iterator(self.path, mode='rb')
def index_html(self, REQUEST, RESPONSE=None): """Default view for VirtualBinary file""" ranges = None if RESPONSE is None: RESPONSE = REQUEST.RESPONSE if self.__content_class__ is None: # Build your own headers RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', self.size) else: # Call index_html method of content class with a fake # self.data attribute which will return empty value # Use this artifice to make sure content class is not loading # all data in memory since it is better to return a stream iterator # There is an exception with multiple range if REQUEST.environ.has_key('HTTP_RANGE'): ranges = parseRange(REQUEST.environ.get('HTTP_RANGE')) ## in case of mutiple range we don't know do with an iterator if ranges is not None and len(ranges) > 1: ## call normally OFS.image with data return self.__content_class__.index_html(self, REQUEST, RESPONSE) else: ### now we deal correctly with 304 header if self._if_modified_since_request_handler(REQUEST, RESPONSE): self.ZCacheable_set(None) return '' ### set correctly header RESPONSE.setHeader('Last-Modified', rfc1123_date(self._p_mtime)) RESPONSE.setHeader('Content-Type', self.content_type) RESPONSE.setHeader('Content-Length', self.size) RESPONSE.setHeader('Accept-Ranges', 'bytes') self.ZCacheable_set(None) # This is a default header that can be bypassed by other products # such as attachment field. if RESPONSE.getHeader('content-disposition') is None: # headers are in lower case in HTTPResponse RESPONSE.setHeader( 'Content-Disposition', 'inline; filename="%s"' % self.filename ) if ranges and len(ranges) == 1: ## is an range request with one range , ## return an iterator with this range [(start,end)] = ranges if end is None: end = self.size iterator = range_filestream_iterator(self.path, start, end, mode='rb') return iterator else: return filestream_iterator(self.path, mode='rb')
def handleRequestRange(instance, length, REQUEST, RESPONSE): # check if we have a range in the request ranges = None range = REQUEST.get_header('Range', None) request_range = REQUEST.get_header('Request-Range', None) if request_range is not None: # Netscape 2 through 4 and MSIE 3 implement a draft version # Later on, we need to serve a different mime-type as well. range = request_range if_range = REQUEST.get_header('If-Range', None) if range is not None: ranges = parseRange(range) if if_range is not None: # Only send ranges if the data isn't modified, otherwise send # the whole object. Support both ETags and Last-Modified dates! if len(if_range) > 1 and if_range[:2] == 'ts': # ETag: if if_range != instance.http__etag(): # Modified, so send a normal response. We delete # the ranges, which causes us to skip to the 200 # response. ranges = None else: # Date date = if_range.split(';')[0] try: mod_since = long(DateTime(date).timeTime()) except Exception: mod_since = None if mod_since is not None: if instance._p_mtime: last_mod = long(instance._p_mtime) else: last_mod = long(0) if last_mod > mod_since: # Modified, so send a normal response. We delete # the ranges, which causes us to skip to the 200 # response. ranges = None RESPONSE.setHeader('Accept-Ranges', 'bytes') if ranges and len(ranges) == 1: try: [(start, end)] = expandRanges(ranges, length) size = end - start RESPONSE.setHeader('Content-Length', size) RESPONSE.setHeader( 'Content-Range', 'bytes {0}-{1}/{2}'.format(start, end - 1, length)) RESPONSE.setStatus(206) # Partial content return dict(start=start, end=end) except ValueError: return {} return {}
def handleRequestRange(instance, length, REQUEST, RESPONSE): # check if we have a range in the request ranges = None range = REQUEST.get_header('Range', None) request_range = REQUEST.get_header('Request-Range', None) if request_range is not None: # Netscape 2 through 4 and MSIE 3 implement a draft version # Later on, we need to serve a different mime-type as well. range = request_range if_range = REQUEST.get_header('If-Range', None) if range is not None: ranges = parseRange(range) if if_range is not None: # Only send ranges if the data isn't modified, otherwise send # the whole object. Support both ETags and Last-Modified dates! if len(if_range) > 1 and if_range[:2] == 'ts': # ETag: if if_range != instance.http__etag(): # Modified, so send a normal response. We delete # the ranges, which causes us to skip to the 200 # response. ranges = None else: # Date date = if_range.split(';')[0] try: mod_since = long(DateTime(date).timeTime()) except Exception: mod_since = None if mod_since is not None: if instance._p_mtime: last_mod = long(instance._p_mtime) else: last_mod = 0 if last_mod > mod_since: # Modified, so send a normal response. We delete # the ranges, which causes us to skip to the 200 # response. ranges = None RESPONSE.setHeader('Accept-Ranges', 'bytes') if ranges and len(ranges) == 1: try: [(start, end)] = expandRanges(ranges, length) size = end - start RESPONSE.setHeader('Content-Length', size) RESPONSE.setHeader( 'Content-Range', 'bytes {0}-{1}/{2}'.format(start, end - 1, length)) RESPONSE.setStatus(206) # Partial content return dict(start=start, end=end) except ValueError: return {} return {}
def have_ranges(self): """Return range information if partial content was requested. """ range_header = self.request.environ.get('HTTP_RANGE', None) if range_header is not None: range_if_header = self.request.environ.get('HTTP_IF_RANGE', None) if range_if_header: # If there is an If-Range header, with a date # prior to the modification, return all the file. if_date = parse_datetime(range_if_header) if (if_date and self._modification_datetime and self._modification_datetime > if_date): return (None, None, None) ranges = parseRange(range_header) if len(ranges) == 1: size = self.context.get_file_size() satisfiable = expandRanges(ranges, size) if len(satisfiable) == 1: return (satisfiable[0][0], satisfiable[0][1] - 1, size) return (None, None, size) return (None, None, None)
def expectSets(self, header, sets): result = parseRange(header) self.assertTrue( result == sets, 'Expected %r, got %r' % (sets, result))
def expectNone(self, header): result = parseRange(header) self.assertTrue(result is None, 'Expected None, got %r' % result)
def expectSets(self, header, sets): result = parseRange(header) self.assertTrue(result == sets, 'Expected %s, got %s' % ( ` sets `, ` result `))
def expectNone(self, header): result = parseRange(header) self.assertTrue(result is None, 'Expected None, got %s' % ` result `)
def expectSets(self, header, sets): result = parseRange(header) self.failUnless(result == sets, 'Expected %s, got %s' % (`sets`, `result`))
def expectNone(self, header): result = parseRange(header) self.failUnless(result is None, 'Expected None, got %s' % `result`)
def expectSets(self, header, sets): result = parseRange(header) self.assertTrue(result == sets, 'Expected %s, got %s' % (`sets`, `result`))
def expectSets(self, header, sets): result = parseRange(header) self.assertTrue(result == sets, 'Expected %r, got %r' % (sets, result))
def expectSets(self, header, sets): result = parseRange(header) self.assertTrue(result == sets, f'Expected {sets!r}, got {result!r}')