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
108
ranges.append((int(range_match.group('start')),
102
111
tail_match = self._tail_regexp.match(range_str)
103
112
if tail_match is not None:
104
113
tail = int(tail_match.group('tail'))
115
# Syntactically invalid range
105
117
return tail, ranges
107
119
def send_range_content(self, file, start, length):
168
180
ranges.append((file_size - tail, file_size))
182
satisfiable_ranges = True
171
183
if len(ranges) == 0:
184
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.
186
def check_range(range_specifier):
187
start, end = range_specifier
188
# RFC2616 14.35, ranges are invalid if start > end
189
# or start > file_size
190
if start > end or start > file_size:
191
satisfiable_ranges = False
193
# RFC2616 14.35, end values should be truncated
194
# to file_size -1 if they exceed it
195
end = min(end, file_size - 1)
198
ranges = map(check_range, ranges)
200
if not satisfiable_ranges:
201
# RFC2616 14.16 and 14.35 says that when a server
202
# encounters unsatisfiable range specifiers, it
203
# SHOULD return a 416.
205
# FIXME: We SHOULD send a Content-Range header too,
206
# but the implementation of send_error does not
207
# allows that. So far.
187
208
self.send_error(416, "Requested range not satisfiable")