88
88
_tail_regexp = re.compile(r'^-(?P<tail>\d+)$')
90
90
def parse_ranges(self, ranges_header):
91
"""Parse the range header value and returns ranges and tail"""
91
"""Parse the range header value and returns ranges and tail.
93
RFC2616 14.35 says that syntactically invalid range
94
specifiers MUST be ignored. In that case, we return 0 for
95
tail and [] for ranges.
94
assert ranges_header.startswith('bytes=')
99
if not ranges_header.startswith('bytes='):
100
# Syntactically invalid header
95
103
ranges_header = ranges_header[len('bytes='):]
96
104
for range_str in ranges_header.split(','):
105
# FIXME: RFC2616 says end is optional and default to file_size
97
106
range_match = self._range_regexp.match(range_str)
98
107
if range_match is not None:
99
ranges.append((int(range_match.group('start')),
100
int(range_match.group('end'))))
108
start = int(range_match.group('start'))
109
end = int(range_match.group('end'))
111
# Syntactically invalid range
113
ranges.append((start, end))
102
115
tail_match = self._tail_regexp.match(range_str)
103
116
if tail_match is not None:
104
117
tail = int(tail_match.group('tail'))
119
# Syntactically invalid range
105
121
return tail, ranges
107
123
def send_range_content(self, file, start, length):
168
184
ranges.append((file_size - tail, file_size))
186
self._satisfiable_ranges = True
171
187
if len(ranges) == 0:
188
self._satisfiable_ranges = False
174
for (start, end) in ranges:
175
if start >= file_size or end >= file_size:
179
# RFC2616 14.35 says that invalid Range headers must
180
# be ignored. If they are, the whole file should be
181
# returned as though no Range header was present. If
182
# they aren't, the server should return a 416 error.
183
# FIXME: per 14.35, ranges are only invalid if start > end.
184
# end values should be truncated to file_size -1 if they exceed it.
185
# only start values >= file_size should produce a 416.
190
def check_range(range_specifier):
191
start, end = range_specifier
192
# RFC2616 14.35, ranges are invalid if start >= file_size
193
if start >= file_size:
194
self._satisfiable_ranges = False # Side-effect !
196
# RFC2616 14.35, end values should be truncated
197
# to file_size -1 if they exceed it
198
end = min(end, file_size - 1)
201
ranges = map(check_range, ranges)
203
if not self._satisfiable_ranges:
204
# RFC2616 14.16 and 14.35 says that when a server
205
# encounters unsatisfiable range specifiers, it
206
# SHOULD return a 416.
208
# FIXME: We SHOULD send a Content-Range header too,
209
# but the implementation of send_error does not
210
# allows that. So far.
187
211
self.send_error(416, "Requested range not satisfiable")