def read_share_chunk( client: StorageClient, share_type: str, storage_index: bytes, share_number: int, offset: int, length: int, ) -> Deferred[bytes]: """ Download a chunk of data from a share. TODO https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3857 Failed downloads should be transparently retried and redownloaded by the implementation a few times so that if a failure percolates up, the caller can assume the failure isn't a short-term blip. NOTE: the underlying HTTP protocol is somewhat more flexible than this API, insofar as it doesn't always require a range. In practice a range is always provided by the current callers. """ url = client.relative_url("/v1/{}/{}/{}".format(share_type, _encode_si(storage_index), share_number)) response = yield client.request( "GET", url, headers=Headers({ "range": [Range("bytes", [(offset, offset + length)]).to_header()] }), ) if response.code == http.PARTIAL_CONTENT: body = yield response.content() returnValue(body) else: raise ClientException(response.code)
async def test_response_make_conditional() -> None: response = Response(b"abcdef") await response.make_conditional(Range("bytes", [(0, 3)])) assert b"abc" == (await response.get_data()) # type: ignore assert response.status_code == 206 assert response.accept_ranges == "bytes" assert response.content_range.units == "bytes" assert response.content_range.start == 0 assert response.content_range.stop == 2 assert response.content_range.length == 6
def parse_range_header(value, make_inclusive=True): """Parses a range header into a :class:`~werkzeug.datastructures.Range` object. If the header is missing or malformed `None` is returned. `ranges` is a list of ``(start, stop)`` tuples where the ranges are non-inclusive. .. versionadded:: 0.7 """ if not value or '=' not in value: return None ranges = [] last_end = 0 units, rng = value.split('=', 1) units = units.strip().lower() for item in rng.split(','): item = item.strip() if '-' not in item: return None if item.startswith('-'): if last_end < 0: return None try: begin = int(item) except ValueError: return None end = None last_end = -1 elif '-' in item: begin, end = item.split('-', 1) begin = begin.strip() end = end.strip() if not begin.isdigit(): return None begin = int(begin) if begin < last_end or last_end < 0: return None if end: if not end.isdigit(): return None end = int(end) + 1 if begin >= end: return None else: end = None last_end = end ranges.append((begin, end)) return Range(units, ranges)
@pytest.mark.asyncio async def test_response_make_conditional() -> None: response = Response(b"abcdef") await response.make_conditional(Range("bytes", [(0, 3)])) assert b"abc" == (await response.get_data()) # type: ignore assert response.status_code == 206 assert response.accept_ranges == "bytes" assert response.content_range.units == "bytes" assert response.content_range.start == 0 assert response.content_range.stop == 2 assert response.content_range.length == 6 @pytest.mark.asyncio @pytest.mark.parametrize("range_", [Range("", {}), Range("bytes", [(0, 6)])]) async def test_response_make_conditional_no_condition(range_: Range) -> None: response = Response(b"abcdef") await response.make_conditional(range_) assert b"abcdef" == (await response.get_data()) # type: ignore assert response.status_code == 200 assert response.accept_ranges == "bytes" @pytest.mark.asyncio @pytest.mark.parametrize( "range_", [ Range("seconds", [(0, 3)]), Range("bytes", [(0, 2), (3, 5)]), Range("bytes", [(0, 8)])
def test_range_to_header(ranges): header = Range("byes", ranges).to_header() r = http.parse_range_header(header) assert r.ranges == ranges