diff --git a/quantum/api/v2/resource.py b/quantum/api/v2/resource.py index be710963022..97fc8a8adaf 100644 --- a/quantum/api/v2/resource.py +++ b/quantum/api/v2/resource.py @@ -83,7 +83,7 @@ def Resource(controller, faults=None, deserializers=None, serializers=None): except (exceptions.QuantumException, netaddr.AddrFormatError) as e: LOG.exception(_('%s failed'), action) - body = serializer.serialize({'QuantumError': str(e)}) + body = serializer.serialize({'QuantumError': e}) kwargs = {'body': body, 'content_type': content_type} for fault in faults: if isinstance(e, fault): @@ -91,7 +91,7 @@ def Resource(controller, faults=None, deserializers=None, serializers=None): raise webob.exc.HTTPInternalServerError(**kwargs) except webob.exc.HTTPException as e: LOG.exception(_('%s failed'), action) - e.body = serializer.serialize({'QuantumError': str(e)}) + e.body = serializer.serialize({'QuantumError': e}) e.content_type = content_type raise except Exception as e: diff --git a/quantum/tests/unit/test_api_v2_resource.py b/quantum/tests/unit/test_api_v2_resource.py index 7328c1c6d09..f4580de4d00 100644 --- a/quantum/tests/unit/test_api_v2_resource.py +++ b/quantum/tests/unit/test_api_v2_resource.py @@ -100,27 +100,81 @@ class RequestTestCase(base.BaseTestCase): class ResourceTestCase(base.BaseTestCase): - def test_unmapped_quantum_error(self): + def test_unmapped_quantum_error_with_json(self): + msg = u'\u7f51\u7edc' + + class TestException(q_exc.QuantumException): + message = msg + expected_res = {'body': {'QuantumError': msg}} controller = mock.MagicMock() - controller.test.side_effect = q_exc.QuantumException() + controller.test.side_effect = TestException() resource = webtest.TestApp(wsgi_resource.Resource(controller)) - environ = {'wsgiorg.routing_args': (None, {'action': 'test'})} + environ = {'wsgiorg.routing_args': (None, {'action': 'test', + 'format': 'json'})} res = resource.get('', extra_environ=environ, expect_errors=True) self.assertEqual(res.status_int, exc.HTTPInternalServerError.code) + self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body), + expected_res) - def test_mapped_quantum_error(self): + def test_unmapped_quantum_error_with_xml(self): + msg = u'\u7f51\u7edc' + + class TestException(q_exc.QuantumException): + message = msg + expected_res = {'body': {'QuantumError': msg}} controller = mock.MagicMock() - controller.test.side_effect = q_exc.QuantumException() + controller.test.side_effect = TestException() - faults = {q_exc.QuantumException: exc.HTTPGatewayTimeout} + resource = webtest.TestApp(wsgi_resource.Resource(controller)) + + environ = {'wsgiorg.routing_args': (None, {'action': 'test', + 'format': 'xml'})} + res = resource.get('', extra_environ=environ, expect_errors=True) + self.assertEqual(res.status_int, exc.HTTPInternalServerError.code) + self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body), + expected_res) + + def test_mapped_quantum_error_with_json(self): + msg = u'\u7f51\u7edc' + + class TestException(q_exc.QuantumException): + message = msg + expected_res = {'body': {'QuantumError': msg}} + controller = mock.MagicMock() + controller.test.side_effect = TestException() + + faults = {TestException: exc.HTTPGatewayTimeout} resource = webtest.TestApp(wsgi_resource.Resource(controller, faults=faults)) - environ = {'wsgiorg.routing_args': (None, {'action': 'test'})} + environ = {'wsgiorg.routing_args': (None, {'action': 'test', + 'format': 'json'})} res = resource.get('', extra_environ=environ, expect_errors=True) self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code) + self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body), + expected_res) + + def test_mapped_quantum_error_with_xml(self): + msg = u'\u7f51\u7edc' + + class TestException(q_exc.QuantumException): + message = msg + expected_res = {'body': {'QuantumError': msg}} + controller = mock.MagicMock() + controller.test.side_effect = TestException() + + faults = {TestException: exc.HTTPGatewayTimeout} + resource = webtest.TestApp(wsgi_resource.Resource(controller, + faults=faults)) + + environ = {'wsgiorg.routing_args': (None, {'action': 'test', + 'format': 'xml'})} + res = resource.get('', extra_environ=environ, expect_errors=True) + self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code) + self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body), + expected_res) def test_http_error(self): controller = mock.MagicMock() @@ -132,15 +186,37 @@ class ResourceTestCase(base.BaseTestCase): res = resource.get('', extra_environ=environ, expect_errors=True) self.assertEqual(res.status_int, exc.HTTPGatewayTimeout.code) - def test_unhandled_error(self): + def test_unhandled_error_with_json(self): + expected_res = {'body': {'QuantumError': + _('Request Failed: internal server error ' + 'while processing your request.')}} controller = mock.MagicMock() controller.test.side_effect = Exception() resource = webtest.TestApp(wsgi_resource.Resource(controller)) - environ = {'wsgiorg.routing_args': (None, {'action': 'test'})} + environ = {'wsgiorg.routing_args': (None, {'action': 'test', + 'format': 'json'})} res = resource.get('', extra_environ=environ, expect_errors=True) self.assertEqual(res.status_int, exc.HTTPInternalServerError.code) + self.assertEqual(wsgi.JSONDeserializer().deserialize(res.body), + expected_res) + + def test_unhandled_error_with_xml(self): + expected_res = {'body': {'QuantumError': + _('Request Failed: internal server error ' + 'while processing your request.')}} + controller = mock.MagicMock() + controller.test.side_effect = Exception() + + resource = webtest.TestApp(wsgi_resource.Resource(controller)) + + environ = {'wsgiorg.routing_args': (None, {'action': 'test', + 'format': 'xml'})} + res = resource.get('', extra_environ=environ, expect_errors=True) + self.assertEqual(res.status_int, exc.HTTPInternalServerError.code) + self.assertEqual(wsgi.XMLDeserializer().deserialize(res.body), + expected_res) def test_status_200(self): controller = mock.MagicMock() diff --git a/quantum/tests/unit/test_wsgi.py b/quantum/tests/unit/test_wsgi.py index c3d7561023b..b775a83eca9 100644 --- a/quantum/tests/unit/test_wsgi.py +++ b/quantum/tests/unit/test_wsgi.py @@ -614,6 +614,24 @@ class JSONDictSerializerTest(base.BaseTestCase): self.assertEqual(result, expected_json) + def test_json_with_utf8(self): + input_dict = dict(servers=dict(a=(2, '\xe7\xbd\x91\xe7\xbb\x9c'))) + expected_json = '{"servers":{"a":[2,"\\u7f51\\u7edc"]}}' + serializer = wsgi.JSONDictSerializer() + result = serializer.serialize(input_dict) + result = result.replace('\n', '').replace(' ', '') + + self.assertEqual(result, expected_json) + + def test_json_with_unicode(self): + input_dict = dict(servers=dict(a=(2, u'\u7f51\u7edc'))) + expected_json = '{"servers":{"a":[2,"\\u7f51\\u7edc"]}}' + serializer = wsgi.JSONDictSerializer() + result = serializer.serialize(input_dict) + result = result.replace('\n', '').replace(' ', '') + + self.assertEqual(result, expected_json) + class TextDeserializerTest(base.BaseTestCase): @@ -654,6 +672,20 @@ class JSONDeserializerTest(base.BaseTestCase): self.assertRaises( exception.MalformedRequestBody, deserializer.default, data_string) + def test_json_with_utf8(self): + data = '{"a": "\xe7\xbd\x91\xe7\xbb\x9c"}' + as_dict = {'body': {'a': u'\u7f51\u7edc'}} + deserializer = wsgi.JSONDeserializer() + self.assertEqual( + deserializer.deserialize(data), as_dict) + + def test_json_with_unicode(self): + data = '{"a": "\u7f51\u7edc"}' + as_dict = {'body': {'a': u'\u7f51\u7edc'}} + deserializer = wsgi.JSONDeserializer() + self.assertEqual( + deserializer.deserialize(data), as_dict) + class XMLDeserializerTest(base.BaseTestCase): def test_xml_empty(self): @@ -681,6 +713,14 @@ class XMLDeserializerTest(base.BaseTestCase): self.assertRaises( exception.MalformedRequestBody, deserializer.default, data_string) + def test_xml_with_utf8(self): + xml = '\xe7\xbd\x91\xe7\xbb\x9c' + as_dict = {'body': {'a': u'\u7f51\u7edc'}} + deserializer = wsgi.XMLDeserializer() + + self.assertEqual( + deserializer.deserialize(xml), as_dict) + class RequestHeadersDeserializerTest(base.BaseTestCase): @@ -1044,6 +1084,34 @@ class XMLDictSerializerTest(base.BaseTestCase): result = result.replace('\n', '').replace(' ', '') self.assertEqual(expected, result) + def test_xml_with_utf8(self): + data = {'servers': '\xe7\xbd\x91\xe7\xbb\x9c'} + serializer = wsgi.XMLDictSerializer() + expected = ( + '' + '' + '\xe7\xbd\x91\xe7\xbb\x9c' + ) + result = serializer(data) + result = result.replace('\n', '').replace(' ', '') + self.assertEqual(expected, result) + + def test_xml_with_unicode(self): + data = {'servers': u'\u7f51\u7edc'} + serializer = wsgi.XMLDictSerializer() + expected = ( + '' + '' + '\xe7\xbd\x91\xe7\xbb\x9c' + ) + result = serializer(data) + result = result.replace('\n', '').replace(' ', '') + self.assertEqual(expected, result) + class TestWSGIServerWithSSL(base.BaseTestCase): """WSGI server tests.""" diff --git a/quantum/wsgi.py b/quantum/wsgi.py index 5daec8b5847..8558729f855 100644 --- a/quantum/wsgi.py +++ b/quantum/wsgi.py @@ -334,7 +334,9 @@ class JSONDictSerializer(DictSerializer): """Default JSON request body serialization""" def default(self, data): - return jsonutils.dumps(data) + def sanitizer(obj): + return unicode(obj) + return jsonutils.dumps(data, default=sanitizer) class XMLDictSerializer(DictSerializer): @@ -467,7 +469,10 @@ class XMLDictSerializer(DictSerializer): LOG.debug(_("Data %(data)s type is %(type)s"), {'data': data, 'type': type(data)}) - result.text = str(data) + if isinstance(data, str): + result.text = unicode(data, 'utf-8') + else: + result.text = unicode(data) return result def _create_link_nodes(self, xml_doc, links):