ensure that we safely encode ec2 utf8 responses

The ec2 response layer assumed that all strings coming back for
results were always ascii, and exploded horribly if they weren't due
to the use of a str() function late in the game. This updates the code
to use safe_encode correctly when the object gets rendered.

This also adds unit tests for the rendering functionality in
ec2/apirequest so that we can actually feel confident that it does the
right things with unicode.

Change-Id: I348a728e3559fdbf0d1bc66616cc278c3370cd29
Closes-Bug: #1306479
This commit is contained in:
Sean Dague 2014-09-11 08:52:43 -04:00
parent a5f09ddddf
commit 0da4d72ae6
2 changed files with 77 additions and 1 deletions

View File

@ -23,10 +23,12 @@ import datetime
from xml.dom import minidom
from lxml import etree
import six
from nova.api.ec2 import ec2utils
from nova import exception
from nova.openstack.common import log as logging
from nova.openstack.common import strutils
LOG = logging.getLogger(__name__)
@ -134,6 +136,7 @@ class APIRequest(object):
data_el.appendChild(
xml.createTextNode(_database_to_isoformat(data)))
elif data is not None:
data_el.appendChild(xml.createTextNode(str(data)))
data_el.appendChild(xml.createTextNode(
strutils.safe_encode(six.text_type(data))))
return data_el

View File

@ -0,0 +1,73 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Unit tests for the API Request internals."""
import copy
from nova.api.ec2 import apirequest
from nova import test
class APIRequestTestCase(test.NoDBTestCase):
def setUp(self):
super(APIRequestTestCase, self).setUp()
self.req = apirequest.APIRequest("FakeController", "FakeAction",
"FakeVersion", {})
self.resp = {
'string': 'foo',
'int': 1,
'long': long(1),
'bool': False,
'dict': {
'string': 'foo',
'int': 1,
}
}
# The previous will produce an output that looks like the
# following (excusing line wrap for 80 cols):
#
# <FakeActionResponse xmlns="http://ec2.amazonaws.com/doc/\
# FakeVersion/">
# <requestId>uuid</requestId>
# <int>1</int>
# <dict>
# <int>1</int>
# <string>foo</string>
# </dict>
# <bool>false</bool>
# <string>foo</string>
# </FakeActionResponse>
#
# We don't attempt to ever test for the full document because
# hash seed order might impact it's rendering order. The fact
# that running the function doesn't explode is a big part of
# the win.
def test_render_response_ascii(self):
data = self.req._render_response(self.resp, 'uuid')
self.assertIn('<FakeActionResponse xmlns="http://ec2.amazonaws.com/'
'doc/FakeVersion/', data)
self.assertIn('<int>1</int>', data)
self.assertIn('<string>foo</string>', data)
def test_render_response_utf8(self):
resp = copy.deepcopy(self.resp)
resp['utf8'] = unichr(40960) + u'abcd' + unichr(1972)
data = self.req._render_response(resp, 'uuid')
self.assertIn('<utf8>&#40960;abcd&#1972;</utf8>', data)