diff --git a/swift/common/utils.py b/swift/common/utils.py index 055d10e3c6..792f7f5bc1 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -3821,8 +3821,9 @@ def document_iters_to_http_response_body(ranges_iter, boundary, multipart, # so if that finally block fires before we read response_body_iter, # there's nothing there. def string_along(useful_iter, useless_iter_iter, logger): - for x in useful_iter: - yield x + with closing_if_possible(useful_iter): + for x in useful_iter: + yield x try: next(useless_iter_iter) diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py index bfa7ddb072..813256bded 100644 --- a/test/unit/common/test_utils.py +++ b/test/unit/common/test_utils.py @@ -5703,6 +5703,28 @@ class TestDocumentItersToHTTPResponseBody(unittest.TestCase): part2 + "\r\n" + "--boundaryboundary--")) + def test_closed_part_iterator(self): + print('test') + useful_iter_mock = mock.MagicMock() + useful_iter_mock.__iter__.return_value = [''] + body_iter = utils.document_iters_to_http_response_body( + iter([{'part_iter': useful_iter_mock}]), 'dontcare', + multipart=False, logger=FakeLogger()) + body = '' + for s in body_iter: + body += s + self.assertEqual(body, '') + useful_iter_mock.close.assert_called_once_with() + + # Calling "close" on the mock will now raise an AttributeError + del useful_iter_mock.close + body_iter = utils.document_iters_to_http_response_body( + iter([{'part_iter': useful_iter_mock}]), 'dontcare', + multipart=False, logger=FakeLogger()) + body = '' + for s in body_iter: + body += s + class TestPairs(unittest.TestCase): def test_pairs(self):