Fix suffix-byte-range responses for zero-byte replicated objects.
Previously, given a GET request like "Range: bytes=-12345" for a zero-byte object, Swift would return a 206 response with the header "Content-Range: bytes 0--1/0". This is clearly incorrect. Now Swift returns a 200 with the whole (zero-byte) object. Note: this does not fix the bug for EC objects, only for replicated ones. The fix for EC objects will follow in a separate commit. Change-Id: If1edb665b0ae000da78c4efff6faddd94d75da6b Partial-Bug: 1736840
This commit is contained in:
parent
c53d5bfe9f
commit
dd9bc82826
@ -1256,6 +1256,20 @@ class Response(object):
|
||||
# body text from RESPONSE_REASONS.
|
||||
body = None
|
||||
app_iter = None
|
||||
elif self.content_length == 0:
|
||||
# If ranges_for_length found ranges but our content length
|
||||
# is 0, then that means we got a suffix-byte-range request
|
||||
# (e.g. "bytes=-512"). This is asking for *up to* the last N
|
||||
# bytes of the file. If we had any bytes to send at all,
|
||||
# we'd return a 206 with an apropriate Content-Range header,
|
||||
# but we can't construct a Content-Range header because we
|
||||
# have no byte indices because we have no bytes.
|
||||
#
|
||||
# The only reasonable thing to do is to return a 200 with
|
||||
# the whole object (all zero bytes of it). This is also what
|
||||
# Apache and Nginx do, so if we're wrong, at least we're in
|
||||
# good company.
|
||||
pass
|
||||
elif ranges:
|
||||
range_size = len(ranges)
|
||||
if range_size > 0:
|
||||
|
@ -2918,6 +2918,22 @@ class TestObjectController(unittest.TestCase):
|
||||
self.assertEqual(resp.headers['X-Backend-Timestamp'],
|
||||
utils.Timestamp(timestamp).internal)
|
||||
|
||||
def test_GET_range_zero_byte_object(self):
|
||||
timestamp = normalize_timestamp(time())
|
||||
req = Request.blank('/sda1/p/a/c/zero-byte',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': timestamp,
|
||||
'Content-Type': 'application/x-test'})
|
||||
req.body = ''
|
||||
resp = req.get_response(self.object_controller)
|
||||
self.assertEqual(resp.status_int, 201)
|
||||
|
||||
req = Request.blank('/sda1/p/a/c/zero-byte',
|
||||
environ={'REQUEST_METHOD': 'GET'},
|
||||
headers={'Range': 'bytes=-10'})
|
||||
resp = req.get_response(self.object_controller)
|
||||
self.assertEqual(resp.status_int, 200)
|
||||
|
||||
def test_GET_if_match(self):
|
||||
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={
|
||||
|
Loading…
x
Reference in New Issue
Block a user