diff --git a/lib/net/http/header.rb b/lib/net/http/header.rb
index d6f12956..547e7cd3 100644
--- a/lib/net/http/header.rb
+++ b/lib/net/http/header.rb
@@ -712,11 +712,16 @@ def chunked?
# res['Content-Range'] # => "bytes 0-499/1000"
# res.content_range # => 0..499
#
+ # Returns +nil+ for an unsatisfied range such as 'bytes */1000',
+ # which a 416 Range Not Satisfiable response may carry;
+ # see {RFC 9110 Section 14.4}[https://www.rfc-editor.org/rfc/rfc9110.html#section-14.4].
+ #
def content_range
return nil unless @header['content-range']
- m = %r<\A\s*(\w+)\s+(\d+)-(\d+)/(\d+|\*)>.match(self['Content-Range']) or
+ m = %r<\A\s*(\w+)\s+(?:(\d+)-(\d+)/(?:\d+|\*)|\*/\d+)>.match(self['Content-Range']) or
raise Net::HTTPHeaderSyntaxError, 'wrong Content-Range format'
return unless m[1] == 'bytes'
+ return unless m[2]
m[2].to_i .. m[3].to_i
end
diff --git a/test/net/http/test_httpheader.rb b/test/net/http/test_httpheader.rb
index b86d4868..004dd5d7 100644
--- a/test/net/http/test_httpheader.rb
+++ b/test/net/http/test_httpheader.rb
@@ -351,10 +351,14 @@ def test_content_range
assert_equal 1..1, @c.content_range
@c['Content-Range'] = "tokens 1-1/1000"
assert_equal nil, @c.content_range
+ @c['Content-Range'] = "bytes */1000"
+ assert_equal nil, @c.content_range
try_invalid_content_range "invalid"
try_invalid_content_range "bytes 123-abc"
try_invalid_content_range "bytes abc-123"
+ try_invalid_content_range "bytes */abc"
+ try_invalid_content_range "bytes */*"
end
def test_range_length
@@ -366,6 +370,8 @@ def test_range_length
assert_equal 1, @c.range_length
@c['Content-Range'] = "tokens 1-1/1000"
assert_equal nil, @c.range_length
+ @c['Content-Range'] = "bytes */1000"
+ assert_equal nil, @c.range_length
try_invalid_content_range "bytes 1-1/abc"
end
diff --git a/test/net/http/test_httpresponse.rb b/test/net/http/test_httpresponse.rb
index e902b4f3..55e5be6e 100644
--- a/test/net/http/test_httpresponse.rb
+++ b/test/net/http/test_httpresponse.rb
@@ -730,6 +730,27 @@ def test_read_body_content_encoding_deflate_content_range
assert_equal "\x1F\x8B\b\x00\x00\x00\x00\x00\x00\x03", body
end
+ def test_read_body_unsatisfied_content_range
+ io = dummy_io(<