Skip to content

Commit ac7b0fa

Browse files
committed
Add support for suffix in Range header
1 parent 9bc811f commit ac7b0fa

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
@@ -773,6 +773,12 @@ def send_head(self):
773773

774774
if self.range:
775775
start, end = self.range
776+
if start is None:
777+
# `end` here means suffix length
778+
start = fs.st_size - end
779+
end = fs.st_size - 1
780+
if start < 0:
781+
start = 0
776782
if start >= fs.st_size:
777783
# 416 REQUESTED_RANGE_NOT_SATISFIABLE means that none of the range values overlap the extent of the resource
778784
f.close()
@@ -953,15 +959,19 @@ def parse_range(self):
953959
range_header = self.headers.get('range')
954960
if not range_header:
955961
return None
956-
m = re.match(r'bytes=(\d+)-(\d*)$', range_header)
962+
m = re.match(r'bytes=(\d*)-(\d*)$', range_header)
957963
if not m:
958964
return None
959-
start = int(m.group(1))
960-
if not m.group(2):
961-
return start, None
962-
end = int(m.group(2))
963-
if start > end:
965+
966+
start = int(m.group(1)) if m.group(1) else None
967+
end = int(m.group(2)) if m.group(2) else None
968+
969+
if start is None and end is None:
970+
return None
971+
972+
if start is not None and end is not None and start > end:
964973
return None
974+
965975
return start, end
966976

967977

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)