From 0590d20fccd0ca2202c6246eb6b213115427f237 Mon Sep 17 00:00:00 2001 From: Samuel Merritt Date: Thu, 12 Jan 2017 13:42:57 -0800 Subject: [PATCH] Fix download resumption for new SLOs. SLOs created after commit 2d25fe6ad3573b2a06b6b3e5e66493d7b0c55693 have an explicit X-Object-Sysmeta-SLO-Size attribute. Fetching one of those with a range like "bytes=100-" would crash and cause a 500. This commit fixes the crash. Closes-Bug: #1656147 Change-Id: I174ed98b4f01a5943af12177d6f8c3586f049778 --- swift/common/middleware/slo.py | 4 +++- test/functional/test_slo.py | 27 +++++++++++++++++++++++++ test/unit/common/middleware/test_slo.py | 10 +++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) 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):