Fix DirectClientExceptions with utf-8 encoded paths
Because the direct_client module uses the buffered_http module it's requests are already robust to receiving either unicode or utf-8 paths. The DirectClientException message however encodes the given path with the device key from a ring node - which having come from a json de-serialized ring will be a unicode type. Despite the device key almost always being only ascii characters; python string interpolation with any unicode type will always force all binary strings to be converted to unicode - which will raise an error if any byte strings includes non-ascii characters. To maintain robustness in DirectClientException, when the provided path is not already unicode we decode the bytes as utf-8 before mixing them with the other unicode strings and then normalize everything back to a quoted utf-8 byte string. Change-Id: I162d2e093a3110856d6e1d513de3c7919079c9e7
This commit is contained in:
parent
87340e5f29
commit
87eaaebd67
@ -42,6 +42,8 @@ class DirectClientException(ClientException):
|
||||
# host can be used to override the node ip and port reported in
|
||||
# the exception
|
||||
host = host if host is not None else node
|
||||
if not isinstance(path, six.text_type):
|
||||
path = path.decode("utf-8")
|
||||
full_path = quote('/%s/%s%s' % (node['device'], part, path))
|
||||
msg = '%s server %s:%s direct %s %r gave status %s' % (
|
||||
stype, host['ip'], host['port'], method, full_path, resp.status)
|
||||
|
@ -99,8 +99,9 @@ def mocked_http_conn(*args, **kwargs):
|
||||
class TestDirectClient(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.node = {'ip': '1.2.3.4', 'port': '6200', 'device': 'sda',
|
||||
'replication_ip': '1.2.3.5', 'replication_port': '7000'}
|
||||
self.node = json.loads(json.dumps({ # json roundtrip to ring-like
|
||||
'ip': '1.2.3.4', 'port': '6200', 'device': 'sda',
|
||||
'replication_ip': '1.2.3.5', 'replication_port': '7000'}))
|
||||
self.part = '0'
|
||||
|
||||
self.account = u'\u062a account'
|
||||
@ -837,7 +838,8 @@ class TestDirectClient(unittest.TestCase):
|
||||
self.assertEqual(err_ctx.exception.http_status, 500)
|
||||
self.assertIn('DELETE', err_ctx.exception.message)
|
||||
self.assertIn(quote('/%s/%s/%s/%s/%s'
|
||||
% (self.node['device'], self.part, self.account,
|
||||
% (self.node['device'].encode('utf-8'),
|
||||
self.part, self.account,
|
||||
self.container, self.obj)),
|
||||
err_ctx.exception.message)
|
||||
self.assertIn(self.node['ip'], err_ctx.exception.message)
|
||||
@ -872,5 +874,14 @@ class TestDirectClient(unittest.TestCase):
|
||||
for line in error_lines:
|
||||
self.assertIn('Kaboom!', line)
|
||||
|
||||
|
||||
class TestUTF8DirectClient(TestDirectClient):
|
||||
|
||||
def setUp(self):
|
||||
super(TestUTF8DirectClient, self).setUp()
|
||||
self.account = self.account.encode('utf-8')
|
||||
self.container = self.container.encode('utf-8')
|
||||
self.obj = self.obj.encode('utf-8')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
Reference in New Issue
Block a user