diff --git a/swift/common/middleware/slo.py b/swift/common/middleware/slo.py index 5aedb91997..03dd22d3b6 100644 --- a/swift/common/middleware/slo.py +++ b/swift/common/middleware/slo.py @@ -703,7 +703,9 @@ class SloGetContext(WSGIContext): if lheader == SYSMETA_SLO_ETAG: slo_etag = value elif lheader == SYSMETA_SLO_SIZE: - content_length = value + # it's from sysmeta, so we don't worry about non-integer + # values here + content_length = int(value) elif lheader not in ('etag', 'content-length'): response_headers.append((header, value)) diff --git a/test/functional/test_slo.py b/test/functional/test_slo.py index e1c6f3d806..8f34e13e1a 100644 --- a/test/functional/test_slo.py +++ b/test/functional/test_slo.py @@ -354,6 +354,33 @@ class TestSlo(Base): self.assertEqual('b', file_contents[-2]) self.assertEqual('c', file_contents[-1]) + def test_slo_ranged_get_half_open_on_right(self): + file_item = self.env.container.file('manifest-abcde') + file_contents = file_item.read( + hdrs={"Range": "bytes=1048571-"}) + grouped_file_contents = [ + (char, sum(1 for _char in grp)) + for char, grp in itertools.groupby(file_contents)] + self.assertEqual([ + ('a', 5), + ('b', 1048576), + ('c', 1048576), + ('d', 1048576), + ('e', 1) + ], grouped_file_contents) + + def test_slo_ranged_get_half_open_on_left(self): + file_item = self.env.container.file('manifest-abcde') + file_contents = file_item.read( + hdrs={"Range": "bytes=-123456"}) + grouped_file_contents = [ + (char, sum(1 for _char in grp)) + for char, grp in itertools.groupby(file_contents)] + self.assertEqual([ + ('d', 123455), + ('e', 1), + ], grouped_file_contents) + def test_slo_multi_ranged_get(self): file_item = self.env.container.file('manifest-abcde') file_contents = file_item.read( diff --git a/test/unit/common/middleware/test_slo.py b/test/unit/common/middleware/test_slo.py index f932a1d5aa..c54ffb616d 100644 --- a/test/unit/common/middleware/test_slo.py +++ b/test/unit/common/middleware/test_slo.py @@ -3017,6 +3017,16 @@ class TestSloConditionalGetOldManifest(SloTestCase): self.assertNotIn('X-Backend-Etag-Is-At', self.app.headers[0]) self.assertNotIn('X-Backend-Etag-Is-At', self.app.headers[1]) + def test_range_resume_download(self): + req = Request.blank( + '/v1/AUTH_test/gettest/manifest-abcd', + environ={'REQUEST_METHOD': 'GET'}, + headers={'Range': 'bytes=20-'}) + status, headers, body = self.call_slo(req) + + self.assertEqual(status, '206 Partial Content') + self.assertEqual(body, 'ccccccccccdddddddddddddddddddd') + class TestSloConditionalGetNewManifest(TestSloConditionalGetOldManifest): def setUp(self):