Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

partially fixed #2805 (multiple http byte ranges are not yet supported) #2812

Merged
merged 5 commits into from
Mar 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES/2805.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Property `BaseRequest.http_range` now returns a python-like slice when requesting the tail of the range.
It's now indicated by a negative value in `range.start` rather then in `range.stop`
6 changes: 3 additions & 3 deletions aiohttp/web_fileresponse.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,9 @@ async def prepare(self, request):
# If a range request has been made, convert start, end slice notation
# into file pointer offset and count
if start is not None or end is not None:
if start is None and end < 0: # return tail of file
start = file_size + end
count = -end
if start < 0 and end is None: # return tail of file
start = file_size + start
count = file_size - start
else:
count = (end or file_size) - start

Expand Down
4 changes: 3 additions & 1 deletion aiohttp/web_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,8 @@ def http_range(self, *, _RANGE=hdrs.RANGE):

if start is None and end is not None:
# end with no start is to return tail of content
end = -end
start = -end
end = None

if start is not None and end is not None:
# end is inclusive in range header, exclusive for slice
Expand All @@ -450,6 +451,7 @@ def http_range(self, *, _RANGE=hdrs.RANGE):

if start is end is None: # No valid range supplied
raise ValueError('No start or end of range specified')

return slice(start, end, 1)

@property
Expand Down
52 changes: 52 additions & 0 deletions tests/test_web_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,58 @@ def test_content_length():
assert 123 == req.content_length


def test_range_to_slice_head():
def bytes_gen(size):
for i in range(size):
yield i % 256
payload = bytearray(bytes_gen(10000))
req = make_mocked_request(
'GET', '/',
headers=CIMultiDict([('RANGE', 'bytes=0-499')]),
payload=payload)
assert isinstance(req.http_range, slice)
assert req.content[req.http_range] == payload[:500]


def test_range_to_slice_mid():
def bytes_gen(size):
for i in range(size):
yield i % 256
payload = bytearray(bytes_gen(10000))
req = make_mocked_request(
'GET', '/',
headers=CIMultiDict([('RANGE', 'bytes=500-999')]),
payload=payload)
assert isinstance(req.http_range, slice)
assert req.content[req.http_range] == payload[500:1000]


def test_range_to_slice_tail_start():
def bytes_gen(size):
for i in range(size):
yield i % 256
payload = bytearray(bytes_gen(10000))
req = make_mocked_request(
'GET', '/',
headers=CIMultiDict([('RANGE', 'bytes=9500-')]),
payload=payload)
assert isinstance(req.http_range, slice)
assert req.content[req.http_range] == payload[-500:]


def test_range_to_slice_tail_stop():
def bytes_gen(size):
for i in range(size):
yield i % 256
payload = bytearray(bytes_gen(10000))
req = make_mocked_request(
'GET', '/',
headers=CIMultiDict([('RANGE', 'bytes=-500')]),
payload=payload)
assert isinstance(req.http_range, slice)
assert req.content[req.http_range] == payload[-500:]


def test_non_keepalive_on_http10():
req = make_mocked_request('GET', '/', version=HttpVersion(1, 0))
assert not req.keep_alive
Expand Down