diff --git a/nova/api/openstack/compute/servers.py b/nova/api/openstack/compute/servers.py index c7b7c411b99b..46ca50d32acd 100644 --- a/nova/api/openstack/compute/servers.py +++ b/nova/api/openstack/compute/servers.py @@ -67,7 +67,7 @@ class ServersController(wsgi.Controller): link = [l for l in robj.obj['server']['links'] if l['rel'] == 'self'] if link: - robj['Location'] = utils.utf8(link[0]['href']) + robj['Location'] = link[0]['href'] # Convenience return return robj diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index e95cb612d395..b9a9b9c74125 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -274,6 +274,9 @@ class ResponseObject(object): Utility method for serializing the wrapped object. Returns a webob.Response object. + + Header values are set to the appropriate Python type and + encoding demanded by PEP 3333: whatever the native str type is. """ serializer = self.serializer @@ -284,24 +287,24 @@ class ResponseObject(object): response = webob.Response(body=body) response.status_int = self.code for hdr, val in self._headers.items(): - if not isinstance(val, six.text_type): - val = six.text_type(val) if six.PY2: - # In Py2.X Headers must be byte strings + # In Py2.X Headers must be a UTF-8 encode str. response.headers[hdr] = encodeutils.safe_encode(val) else: - # In Py3.X Headers must be utf-8 strings + # In Py3.X Headers must be a str that was first safely + # encoded to UTF-8 (to catch any bad encodings) and then + # decoded back to a native str. response.headers[hdr] = encodeutils.safe_decode( encodeutils.safe_encode(val)) # Deal with content_type if not isinstance(content_type, six.text_type): content_type = six.text_type(content_type) if six.PY2: - # In Py2.X Headers must be byte strings + # In Py2.X Headers must be a UTF-8 encode str. response.headers['Content-Type'] = encodeutils.safe_encode( content_type) else: - # In Py3.X Headers must be utf-8 strings + # In Py3.X Headers must be a str. response.headers['Content-Type'] = encodeutils.safe_decode( encodeutils.safe_encode(content_type)) return response @@ -571,10 +574,10 @@ class Resource(wsgi.Application): if not isinstance(val, six.text_type): val = six.text_type(val) if six.PY2: - # In Py2.X Headers must be byte strings + # In Py2.X Headers must be UTF-8 encoded string response.headers[hdr] = encodeutils.safe_encode(val) else: - # In Py3.X Headers must be utf-8 strings + # In Py3.X Headers must be a string response.headers[hdr] = encodeutils.safe_decode( encodeutils.safe_encode(val)) diff --git a/nova/tests/unit/api/openstack/compute/test_server_actions.py b/nova/tests/unit/api/openstack/compute/test_server_actions.py index 56aa5db27aa6..32615f0e20f1 100644 --- a/nova/tests/unit/api/openstack/compute/test_server_actions.py +++ b/nova/tests/unit/api/openstack/compute/test_server_actions.py @@ -301,7 +301,9 @@ class ServerActionsControllerTestV21(test.TestCase): self.assertEqual(len(body['server']['adminPass']), CONF.password_length) - self.assertEqual(robj['location'], self_href.encode('utf-8')) + self.assertEqual(robj['location'], self_href) + # pep3333 requires applications produces headers which are str + self.assertEqual(str, type(robj['location'])) def test_rebuild_instance_with_image_uuid(self): info = dict(image_href_in_call=None) @@ -355,7 +357,9 @@ class ServerActionsControllerTestV21(test.TestCase): self.assertEqual(body['server']['image']['id'], '2') self.assertNotIn("adminPass", body['server']) - self.assertEqual(robj['location'], self_href.encode('utf-8')) + self.assertEqual(robj['location'], self_href) + # pep3333 requires applications produces headers which are str + self.assertEqual(str, type(robj['location'])) def test_rebuild_raises_conflict_on_invalid_state(self): body = {