def set_range_from_header(self, content_range): """Helper to set the new range from its description in the headers""" try: rtype, values = content_range.split() except ValueError: raise errors.InvalidHttpRange(self._path, content_range, 'Malformed header') if rtype != 'bytes': raise errors.InvalidHttpRange( self._path, content_range, "Unsupported range type '%s'" % rtype) try: # We don't need total, but note that it may be either the file size # or '*' if the server can't or doesn't want to return the file # size. start_end, total = values.split('/') start, end = start_end.split('-') start = int(start) end = int(end) except ValueError: raise errors.InvalidHttpRange(self._path, content_range, 'Invalid range values') size = end - start + 1 if size <= 0: raise errors.InvalidHttpRange(self._path, content_range, 'Invalid range, size <= 0') self.set_range(start, size)
def _get(self, relpath, offsets, tail_amount=0): """See HttpTransport._get""" abspath = self._remote_path(relpath) headers = {} accepted_errors = [200, 404] if offsets or tail_amount: range_header = self._attempted_range_header(offsets, tail_amount) if range_header is not None: accepted_errors.append(206) accepted_errors.append(400) accepted_errors.append(416) bytes = 'bytes=' + range_header headers = {'Range': bytes} request = Request('GET', abspath, None, headers, accepted_errors=accepted_errors) response = self._perform(request) code = response.code if code == 404: # not found raise errors.NoSuchFile(abspath) elif code in (400, 416): # We don't know which, but one of the ranges we specified was # wrong. raise errors.InvalidHttpRange(abspath, range_header, 'Server return code %d' % code) data = handle_response(abspath, code, response.info(), response) return code, data
def _get_ranged(self, relpath, offsets, tail_amount): """Make a request for just part of the file.""" curl = self._get_curl() abspath, data, header = self._setup_get_request(curl, relpath) range_header = self._attempted_range_header(offsets, tail_amount) if range_header is None: # Forget ranges, the server can't handle them return self._get_full(relpath) self._curl_perform(curl, header, ['Range: bytes=%s' % range_header]) data.seek(0) code = curl.getinfo(pycurl.HTTP_CODE) if code == 404: # not found raise errors.NoSuchFile(abspath) elif code in (400, 416): # We don't know which, but one of the ranges we specified was # wrong. raise errors.InvalidHttpRange( abspath, range_header, 'Server return code %d' % curl.getinfo(pycurl.HTTP_CODE)) msg = self._parse_headers(header) return code, response.handle_response(abspath, code, msg, data)
def test_invalid_http_range(self): error = errors.InvalidHttpRange('path', 'Content-Range: potatoes 0-00/o0oo0', 'bad range') self.assertEquals( "Invalid http range" " 'Content-Range: potatoes 0-00/o0oo0'" " for path: bad range", str(error))