Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ Experimental Features
Bugfix
~~~~~~

- Suffix byte ranges larger than a non-empty selected representation now
return the entire representation, as required by RFC 9110 section 14.1.2,
instead of being treated as unsatisfiable and producing a 416 response.

- ``webob.cookies.serialize_cookie_date()`` now converts a timezone-aware
``datetime`` to UTC before serializing it, instead of writing its local
wall-clock time out as GMT. Naive datetimes continue to be treated as UTC.
Expand Down
2 changes: 1 addition & 1 deletion src/webob/byterange.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def range_for_length(self, length):
if end is None:
end = length
if start < 0:
start += length
start = max(0, start + length)
if _is_content_range_valid(start, end, length):
stop = min(end, length)
return (start, stop)
Expand Down
9 changes: 7 additions & 2 deletions tests/test_byterange.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,17 @@


def test_not_satisfiable():
range = Range.parse("bytes=-100")
assert range.range_for_length(50) is None
range = Range.parse("bytes=100-")
assert range.range_for_length(50) is None


@pytest.mark.parametrize("suffix", [50, 51, 100])
def test_suffix_range_covering_entire_representation(suffix):
range = Range.parse(f"bytes=-{suffix}")
assert range.range_for_length(50) == (0, 50)
assert tuple(range.content_range(50)) == (0, 50, 50)


def test_range_parse():
assert isinstance(Range.parse("bytes=0-99"), Range)
assert isinstance(Range.parse("BYTES=0-99"), Range)
Expand Down
11 changes: 11 additions & 0 deletions tests/test_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,17 @@ def test_conditional_response_range_not_satisfiable_response():
assert resp.body == b"Requested range not satisfiable: bytes=100-200"


def test_conditional_response_suffix_range_larger_than_body():
req = Request.blank("/", range="bytes=-100")
resp = req.get_response(Response(b"foo\n", conditional_response=True))
assert resp.status_code == 206
assert resp.content_range.start == 0
assert resp.content_range.stop == 4
assert resp.content_range.length == 4
assert resp.content_length == 4
assert resp.body == b"foo\n"


def test_HEAD_conditional_response_range_not_satisfiable_response():
req = Request.blank("/", method="HEAD", range="bytes=100-200")
resp = Response(app_iter=["foo\n"], content_length=4, conditional_response=True)
Expand Down
Loading