Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
@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)])
Exemplo n.º 5
0
def test_range_to_header(ranges):
    header = Range("byes", ranges).to_header()
    r = http.parse_range_header(header)
    assert r.ranges == ranges