Skip to content

Commit 4cf0b46

Browse files
committed
Add support for suffix in Range header
1 parent 0f7ac7d commit 4cf0b46

2 files changed

Lines changed: 21 additions & 6 deletions

File tree

Lib/http/server.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,12 @@ def send_head(self):
767767

768768
if self.range:
769769
start, end = self.range
770+
if start is None:
771+
# `end` here means suffix length
772+
start = fs.st_size - end
773+
end = fs.st_size - 1
774+
if start < 0:
775+
start = 0
770776
if start >= fs.st_size:
771777
# 416 REQUESTED_RANGE_NOT_SATISFIABLE means that none of the range values overlap the extent of the resource
772778
f.close()
@@ -946,15 +952,19 @@ def parse_range(self):
946952
range_header = self.headers.get('range')
947953
if not range_header:
948954
return None
949-
m = re.match(r'bytes=(\d+)-(\d*)$', range_header)
955+
m = re.match(r'bytes=(\d*)-(\d*)$', range_header)
950956
if not m:
951957
return None
952-
start = int(m.group(1))
953-
if not m.group(2):
954-
return start, None
955-
end = int(m.group(2))
956-
if start > end:
958+
959+
start = int(m.group(1)) if m.group(1) else None
960+
end = int(m.group(2)) if m.group(2) else None
961+
962+
if start is None and end is None:
963+
return None
964+
965+
if start is not None and end is not None and start > end:
957966
return None
967+
958968
return start, end
959969

960970

Lib/test/test_httpservers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,11 @@ def test_range_get(self):
554554
self.assertEqual(response.getheader('content-length'), '27')
555555
self.check_status_and_reason(response, HTTPStatus.PARTIAL_CONTENT, data=self.data[3:])
556556

557+
response = self.request(self.base_url + '/test', headers={'Range': 'bytes=-5'})
558+
self.assertEqual(response.getheader('content-range'), 'bytes 25-29/30')
559+
self.assertEqual(response.getheader('content-length'), '5')
560+
self.check_status_and_reason(response, HTTPStatus.PARTIAL_CONTENT, data=self.data[25:])
561+
557562
response = self.request(self.base_url + '/test', headers={'Range': 'bytes=100-200'})
558563
self.check_status_and_reason(response, HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
559564

0 commit comments

Comments
 (0)