From be688c31562a5789fba678a0675eff1040308202 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Fri, 19 Jul 2013 20:07:27 -0700 Subject: [PATCH] Encode unicode from JSON before using it as a string. Right now this code fails when used with a JSON decoder that always produces unicode. This isn't usually the case with CPython, where simplejson is used most of the time, however with the stdlib JSON library (as used on PyPy), this code fails. Change-Id: Ib2343243f40194d5b2784551a807c7f58970a6e9 --- swift/common/middleware/staticweb.py | 30 +++++++++---------- test/unit/common/middleware/test_staticweb.py | 21 +++++++++++++ 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/swift/common/middleware/staticweb.py b/swift/common/middleware/staticweb.py index 8874096beb..8a2061cb17 100644 --- a/swift/common/middleware/staticweb.py +++ b/swift/common/middleware/staticweb.py @@ -125,13 +125,17 @@ from swift.common.swob import Response, HTTPMovedPermanently, HTTPNotFound from swift.proxy.controllers.base import get_container_info +def ensure_utf8_bytes(value): + if isinstance(value, unicode): + value = value.encode('utf-8') + return value + + def quote(value, safe='/'): """ Patched version of urllib.quote that encodes utf-8 strings before quoting """ - if isinstance(value, unicode): - value = value.encode('utf-8') - return urllib_quote(value, safe) + return urllib_quote(ensure_utf8_bytes(value), safe) class _StaticWebContext(WSGIContext): @@ -272,10 +276,7 @@ class _StaticWebContext(WSGIContext): ' \n' for item in listing: if 'subdir' in item: - if isinstance(item['subdir'], unicode): - subdir = item['subdir'].encode('utf-8') - else: - subdir = item['subdir'] + subdir = ensure_utf8_bytes(item['subdir']) if prefix: subdir = subdir[len(prefix):] body += ' \n' \ @@ -286,23 +287,22 @@ class _StaticWebContext(WSGIContext): (quote(subdir), cgi.escape(subdir)) for item in listing: if 'name' in item: - if isinstance(item['name'], unicode): - name = item['name'].encode('utf-8') - else: - name = item['name'] + name = ensure_utf8_bytes(item['name']) if prefix: name = name[len(prefix):] + content_type = ensure_utf8_bytes(item['content_type']) + bytes = ensure_utf8_bytes(human_readable(item['bytes'])) + last_modified = (cgi.escape(item['last_modified']). + split('.')[0].replace('T', ' ')) body += ' \n' \ ' %s\n' \ ' %s\n' \ ' %s\n' \ ' \n' % \ (' '.join('type-' + cgi.escape(t.lower(), quote=True) - for t in item['content_type'].split('/')), + for t in content_type.split('/')), quote(name), cgi.escape(name), - human_readable(item['bytes']), - cgi.escape(item['last_modified']).split('.')[0]. - replace('T', ' ')) + bytes, ensure_utf8_bytes(last_modified)) body += ' \n' \ ' \n' \ '\n' diff --git a/test/unit/common/middleware/test_staticweb.py b/test/unit/common/middleware/test_staticweb.py index 886e744c59..11c34fcb28 100644 --- a/test/unit/common/middleware/test_staticweb.py +++ b/test/unit/common/middleware/test_staticweb.py @@ -17,8 +17,11 @@ try: import simplejson as json except ImportError: import json +import json as stdlib_json import unittest +import mock + from swift.common.swob import Request, Response from swift.common.middleware import staticweb @@ -659,12 +662,30 @@ class TestStaticWeb(unittest.TestCase): self.test_staticweb) self.assertEquals(resp.status_int, 200) + def test_container12unredirectedrequest(self): resp = Request.blank('/v1/a/c12/').get_response( self.test_staticweb) self.assertEquals(resp.status_int, 200) self.assert_('index file' in resp.body) + def test_container_unicode_stdlib_json(self): + with mock.patch('swift.common.middleware.staticweb.json', new=stdlib_json): + resp = Request.blank( + '/v1/a/c10/').get_response(self.test_staticweb) + self.assertEquals(resp.status_int, 200) + self.assert_('Listing of /v1/a/c10/' in resp.body) + resp = Request.blank( + '/v1/a/c10/\xe2\x98\x83/').get_response(self.test_staticweb) + self.assertEquals(resp.status_int, 200) + self.assert_('Listing of /v1/a/c10/\xe2\x98\x83/' in resp.body) + resp = Request.blank( + '/v1/a/c10/\xe2\x98\x83/\xe2\x98\x83/' + ).get_response(self.test_staticweb) + self.assertEquals(resp.status_int, 200) + self.assert_( + 'Listing of /v1/a/c10/\xe2\x98\x83/\xe2\x98\x83/' in resp.body) + def test_subrequest_once_if_possible(self): resp = Request.blank( '/v1/a/c4/one.txt').get_response(self.test_staticweb)