From: David Wolever Date: Thu, 16 May 2013 23:37:30 +0000 (-0400) Subject: (incomplete) Honnoring Range request header X-Git-Tag: v3.1.0~68^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=02e9e68f016cf6339ee17ebf8559b6a034c37433;p=thirdparty%2Ftornado.git (incomplete) Honnoring Range request header --- diff --git a/tornado/httputil.py b/tornado/httputil.py index 7573610b9..83e4558d8 100644 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -235,6 +235,63 @@ class HTTPFile(ObjectDict): """ pass +def parse_request_range(range_header): + """Parses a Range header. + + Returns either ``None`` or an instance of ``slice``:: + + >>> rh = parse_request_range("bytes=1-2") + >>> rh + slice(1, 3, None) + >>> [0, 1, 2, 3, 4][rh] + [1, 2] + >>> parse_request_range("bytes=6-") + slice(6, None, None) + >>> parse_request_range("bytes=") + slice(None, None, None) + >>> parse_request_range("foo=42") + >>> parse_request_range("bytes=1-2,6-10") + + Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed). + """ + unit, _, value = range_header.partition("=") + unit, value = unit.strip(), value.strip() + if unit != "bytes": + return None + start_b, _, end_b = value.partition("-") + try: + start = _int_or_none(start_b) + end = _int_or_none(end_b) + except ValueError: + return None + if end is not None: + end += 1 + return slice(start, end) + +def get_content_range(data, request_range): + """ Returns a suitable Content-Range header:: + + >>> print(get_content_range("abcd", slice(None, 1))) + 0-0/4 + >>> print(get_content_range("abcd", slice(1, 3))) + 1-2/4 + >>> print(get_content_range("abcd", slice(None, None))) + 0-3/4 + """ + + data_len = len(data) + return "%s-%s/%s" %( + request_range.start or 0, + (request_range.stop or data_len) - 1, + data_len, + ) + +def _int_or_none(val): + val = val.strip() + if val == "": + return None + return int(val) + def parse_body_arguments(content_type, body, arguments, files): """Parses a form request body. diff --git a/tornado/web.py b/tornado/web.py index 8b4d31738..b41c08c3f 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -1754,8 +1754,17 @@ class StaticFileHandler(RequestHandler): self.set_status(304) return + request_range = None + range_header = self.request.headers.get("Range") + if range_header: + request_range = httputil.parse_request_range(range_header) + with open(abspath, "rb") as file: data = file.read() + if request_range: + content_range = httputil.get_content_range(data, request_range) + self.set_header("Content-Range", content_range) + data = data[request_range] if include_body: self.write(data) else: