From b42d90a347f8f6c29e220e26b4e73ba9e4fe2b8e Mon Sep 17 00:00:00 2001 From: Romain de Joux Date: Thu, 20 Jul 2023 17:44:00 +0200 Subject: [PATCH] py3: apply str_to_wsgi to includes in _get_shard_ranges Allow to POST/PUT/DELETE object names with Unicode with sharded container. Closes-Bug: #2028264 Change-Id: I36acaa35f6443971b9a96374ca7de33059e62c9f --- swift/proxy/controllers/base.py | 2 +- test/unit/proxy/controllers/test_base.py | 37 +++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/swift/proxy/controllers/base.py b/swift/proxy/controllers/base.py index 6d03334e76..de836d87c6 100644 --- a/swift/proxy/controllers/base.py +++ b/swift/proxy/controllers/base.py @@ -2402,7 +2402,7 @@ class Controller(object): params.pop('limit', None) params['format'] = 'json' if includes: - params['includes'] = includes + params['includes'] = str_to_wsgi(includes) if states: params['states'] = states headers = {'X-Backend-Record-Type': 'shard'} diff --git a/test/unit/proxy/controllers/test_base.py b/test/unit/proxy/controllers/test_base.py index db9cc2abc7..51591fa1e7 100644 --- a/test/unit/proxy/controllers/test_base.py +++ b/test/unit/proxy/controllers/test_base.py @@ -30,7 +30,7 @@ from swift.proxy.controllers.base import headers_to_container_info, \ set_info_cache, NodeIter, headers_from_container_info, \ record_cache_op_metrics from swift.common.swob import Request, HTTPException, RESPONSE_REASONS, \ - bytes_to_wsgi + bytes_to_wsgi, wsgi_to_str from swift.common import exceptions from swift.common.utils import split_path, ShardRange, Timestamp, \ GreenthreadSafeIterator, GreenAsyncPile @@ -1492,6 +1492,41 @@ class TestFuncs(BaseTest): self.assertEqual(shard_ranges[1:2], [dict(pr) for pr in actual]) self.assertFalse(self.app.logger.get_lines_for_level('error')) + def test_get_shard_ranges_for_utf8_object_put(self): + ts_iter = make_timestamp_iter() + shard_ranges = [dict(ShardRange( + '.sharded_a/sr%d' % i, next(ts_iter), u'\u1234%d_lower' % i, + u'\u1234%d_upper' % i, object_count=i, bytes_used=1024 * i, + meta_timestamp=next(ts_iter))) + for i in range(3)] + base = Controller(self.app) + req = Request.blank('/v1/a/c/o', method='PUT') + resp_headers = {'X-Backend-Record-Type': 'shard'} + with mocked_http_conn( + 200, 200, + body_iter=iter([b'', + json.dumps(shard_ranges[1:2]).encode('ascii')]), + headers=resp_headers + ) as fake_conn: + actual, resp = base._get_shard_ranges( + req, 'a', 'c', wsgi_to_str('\xe1\x88\xb41_test')) + self.assertEqual(200, resp.status_int) + + # account info + captured = fake_conn.requests + self.assertEqual('HEAD', captured[0]['method']) + self.assertEqual('a', captured[0]['path'][7:]) + # container GET + self.assertEqual('GET', captured[1]['method']) + self.assertEqual('a/c', captured[1]['path'][7:]) + params = sorted(captured[1]['qs'].split('&')) + self.assertEqual( + ['format=json', 'includes=%E1%88%B41_test'], params) + self.assertEqual( + 'shard', captured[1]['headers'].get('X-Backend-Record-Type')) + self.assertEqual(shard_ranges[1:2], [dict(pr) for pr in actual]) + self.assertFalse(self.app.logger.get_lines_for_level('error')) + def _check_get_shard_ranges_bad_data(self, body): base = Controller(self.app) req = Request.blank('/v1/a/c/o', method='PUT')