| Index: Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/ranges.py
|
| diff --git a/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/ranges.py b/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/ranges.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..12935fd91b1d009ed42644fec0793e9d912e7b18
|
| --- /dev/null
|
| +++ b/Tools/Scripts/webkitpy/thirdparty/wpt/wpt/tools/wptserve/wptserve/ranges.py
|
| @@ -0,0 +1,90 @@
|
| +from utils import HTTPException
|
| +
|
| +
|
| +class RangeParser(object):
|
| + def __call__(self, header, file_size):
|
| + prefix = "bytes="
|
| + if not header.startswith(prefix):
|
| + raise HTTPException(416, message="Unrecognised range type %s" % (header,))
|
| +
|
| + parts = header[len(prefix):].split(",")
|
| + ranges = []
|
| + for item in parts:
|
| + components = item.split("-")
|
| + if len(components) != 2:
|
| + raise HTTPException(416, "Bad range specifier %s" % (item))
|
| + data = []
|
| + for component in components:
|
| + if component == "":
|
| + data.append(None)
|
| + else:
|
| + try:
|
| + data.append(int(component))
|
| + except ValueError:
|
| + raise HTTPException(416, "Bad range specifier %s" % (item))
|
| + try:
|
| + ranges.append(Range(data[0], data[1], file_size))
|
| + except ValueError:
|
| + raise HTTPException(416, "Bad range specifier %s" % (item))
|
| +
|
| + return self.coalesce_ranges(ranges, file_size)
|
| +
|
| + def coalesce_ranges(self, ranges, file_size):
|
| + rv = []
|
| + target = None
|
| + for current in reversed(sorted(ranges)):
|
| + if target is None:
|
| + target = current
|
| + else:
|
| + new = target.coalesce(current)
|
| + target = new[0]
|
| + if len(new) > 1:
|
| + rv.append(new[1])
|
| + rv.append(target)
|
| +
|
| + return rv[::-1]
|
| +
|
| +
|
| +class Range(object):
|
| + def __init__(self, lower, upper, file_size):
|
| + self.file_size = file_size
|
| + self.lower, self.upper = self._abs(lower, upper)
|
| + if self.lower >= self.upper or self.lower >= self.file_size:
|
| + raise ValueError
|
| +
|
| + def __repr__(self):
|
| + return "<Range %s-%s>" % (self.lower, self.upper)
|
| +
|
| + def __lt__(self, other):
|
| + return self.lower < other.lower
|
| +
|
| + def __gt__(self, other):
|
| + return self.lower > other.lower
|
| +
|
| + def __eq__(self, other):
|
| + return self.lower == other.lower and self.upper == other.upper
|
| +
|
| + def _abs(self, lower, upper):
|
| + if lower is None and upper is None:
|
| + lower, upper = 0, self.file_size
|
| + elif lower is None:
|
| + lower, upper = max(0, self.file_size - upper), self.file_size
|
| + elif upper is None:
|
| + lower, upper = lower, self.file_size
|
| + else:
|
| + lower, upper = lower, min(self.file_size, upper + 1)
|
| +
|
| + return lower, upper
|
| +
|
| + def coalesce(self, other):
|
| + assert self.file_size == other.file_size
|
| +
|
| + if (self.upper < other.lower or self.lower > other.upper):
|
| + return sorted([self, other])
|
| + else:
|
| + return [Range(min(self.lower, other.lower),
|
| + max(self.upper, other.upper) - 1,
|
| + self.file_size)]
|
| +
|
| + def header_value(self):
|
| + return "bytes %i-%i/%i" % (self.lower, self.upper - 1, self.file_size)
|
|
|