py3: Fix header_to_environ_key

When doing things for the sake of WSGI, .upper(), .title() etc. should
only be used on bytes.

Change-Id: I130ba5014b7eff458d87ab29eb42fe45607c9a12
This commit is contained in:
Tim Burke 2019-06-10 13:47:30 -07:00
parent dca658103a
commit 06e4533c2e
2 changed files with 23 additions and 9 deletions

View File

@ -209,8 +209,12 @@ def header_to_environ_key(header_name):
# Why the to/from wsgi dance? Headers that include something like b'\xff' # Why the to/from wsgi dance? Headers that include something like b'\xff'
# on the wire get translated to u'\u00ff' on py3, which gets upper()ed to # on the wire get translated to u'\u00ff' on py3, which gets upper()ed to
# u'\u0178', which is nonsense in a WSGI string. # u'\u0178', which is nonsense in a WSGI string.
real_header = wsgi_to_str(header_name) # Note that we have to only get as far as bytes because something like
header_name = 'HTTP_' + str_to_wsgi(real_header.upper()).replace('-', '_') # b'\xc3\x9f' on the wire would be u'\u00df' as a native string on py3,
# which would upper() to 'SS'.
real_header = wsgi_to_bytes(header_name)
header_name = 'HTTP_' + bytes_to_wsgi(
real_header.upper()).replace('-', '_')
if header_name == 'HTTP_CONTENT_LENGTH': if header_name == 'HTTP_CONTENT_LENGTH':
return 'CONTENT_LENGTH' return 'CONTENT_LENGTH'
if header_name == 'HTTP_CONTENT_TYPE': if header_name == 'HTTP_CONTENT_TYPE':
@ -257,7 +261,8 @@ class HeaderEnvironProxy(MutableMapping):
def keys(self): def keys(self):
# See the to/from WSGI comment in header_to_environ_key # See the to/from WSGI comment in header_to_environ_key
keys = [str_to_wsgi(wsgi_to_str(key[5:]).replace('_', '-').title()) keys = [
bytes_to_wsgi(wsgi_to_bytes(key[5:]).replace(b'_', b'-').title())
for key in self.environ if key.startswith('HTTP_')] for key in self.environ if key.startswith('HTTP_')]
if 'CONTENT_LENGTH' in self.environ: if 'CONTENT_LENGTH' in self.environ:
keys.append('Content-Length') keys.append('Content-Length')

View File

@ -32,21 +32,26 @@ class TestHeaderEnvironProxy(unittest.TestCase):
def test_proxy(self): def test_proxy(self):
environ = {} environ = {}
proxy = swift.common.swob.HeaderEnvironProxy(environ) proxy = swift.common.swob.HeaderEnvironProxy(environ)
self.assertIs(environ, proxy.environ)
proxy['Content-Length'] = 20 proxy['Content-Length'] = 20
proxy['Content-Type'] = 'text/plain' proxy['Content-Type'] = 'text/plain'
proxy['Something-Else'] = 'somevalue' proxy['Something-Else'] = 'somevalue'
self.assertEqual( # NB: WSGI strings
proxy.environ, {'CONTENT_LENGTH': '20', proxy['X-Object-Meta-Unicode-\xff-Bu\xc3\x9fe'] = '\xe2\x98\xb9'
self.assertEqual(proxy.environ, {
'CONTENT_LENGTH': '20',
'CONTENT_TYPE': 'text/plain', 'CONTENT_TYPE': 'text/plain',
'HTTP_SOMETHING_ELSE': 'somevalue'}) 'HTTP_SOMETHING_ELSE': 'somevalue',
'HTTP_X_OBJECT_META_UNICODE_\xff_BU\xc3\x9fE': '\xe2\x98\xb9'})
self.assertEqual(proxy['content-length'], '20') self.assertEqual(proxy['content-length'], '20')
self.assertEqual(proxy['content-type'], 'text/plain') self.assertEqual(proxy['content-type'], 'text/plain')
self.assertEqual(proxy['something-else'], 'somevalue') self.assertEqual(proxy['something-else'], 'somevalue')
self.assertEqual(set(['Something-Else', self.assertEqual(set(['Something-Else',
'X-Object-Meta-Unicode-\xff-Bu\xc3\x9fE',
'Content-Length', 'Content-Type']), 'Content-Length', 'Content-Type']),
set(proxy.keys())) set(proxy.keys()))
self.assertEqual(list(iter(proxy)), proxy.keys()) self.assertEqual(list(iter(proxy)), proxy.keys())
self.assertEqual(3, len(proxy)) self.assertEqual(4, len(proxy))
def test_ignored_keys(self): def test_ignored_keys(self):
# Constructor doesn't normalize keys # Constructor doesn't normalize keys
@ -58,6 +63,8 @@ class TestHeaderEnvironProxy(unittest.TestCase):
self.assertEqual(0, len(proxy)) self.assertEqual(0, len(proxy))
self.assertRaises(KeyError, proxy.__getitem__, key) self.assertRaises(KeyError, proxy.__getitem__, key)
self.assertNotIn(key, proxy) self.assertNotIn(key, proxy)
self.assertIn(key, proxy.environ)
self.assertIs(environ, proxy.environ)
proxy['Content-Type'] = 'text/plain' proxy['Content-Type'] = 'text/plain'
self.assertEqual(['Content-Type'], list(iter(proxy))) self.assertEqual(['Content-Type'], list(iter(proxy)))
@ -77,6 +84,8 @@ class TestHeaderEnvironProxy(unittest.TestCase):
del proxy['Something-Else'] del proxy['Something-Else']
self.assertEqual(proxy.environ, {}) self.assertEqual(proxy.environ, {})
self.assertEqual(0, len(proxy)) self.assertEqual(0, len(proxy))
with self.assertRaises(KeyError):
del proxy['Content-Length']
def test_contains(self): def test_contains(self):
environ = {} environ = {}