diff --git a/glanceclient/common/http.py b/glanceclient/common/http.py index 84cdc69..b5bea8a 100644 --- a/glanceclient/common/http.py +++ b/glanceclient/common/http.py @@ -42,6 +42,7 @@ LOG = logging.getLogger(__name__) USER_AGENT = 'python-glanceclient' CHUNKSIZE = 1024 * 64 # 64kB REQ_ID_HEADER = 'X-OpenStack-Request-ID' +TOKEN_HEADERS = ['X-Auth-Token', 'X-Service-Token'] def encode_headers(headers): @@ -61,16 +62,20 @@ def encode_headers(headers): # Bug #1766235: According to RFC 8187, headers must be encoded as ASCII. # So we first %-encode them to get them into range < 128 and then turn # them into ASCII. - if six.PY2: - # incoming items may be unicode, so get them into something - # the py2 version of urllib can handle before percent encoding - encoded_dict = dict((urlparse.quote(encodeutils.safe_encode(h)), - urlparse.quote(encodeutils.safe_encode(v))) - for h, v in headers.items() if v is not None) - else: - encoded_dict = dict((urlparse.quote(h), urlparse.quote(v)) - for h, v in headers.items() if v is not None) - + encoded_dict = {} + for h, v in headers.items(): + if v is not None: + # if the item is token, do not quote '+' as well. + safe = '+/' if h in TOKEN_HEADERS else '/' + if six.PY2: + # incoming items may be unicode, so get them into something + # the py2 version of urllib can handle before percent encoding + key = urlparse.quote(encodeutils.safe_encode(h), safe) + value = urlparse.quote(encodeutils.safe_encode(v), safe) + else: + key = urlparse.quote(h, safe) + value = urlparse.quote(v, safe) + encoded_dict[key] = value return dict((encodeutils.safe_encode(h, encoding='ascii'), encodeutils.safe_encode(v, encoding='ascii')) for h, v in encoded_dict.items()) diff --git a/glanceclient/tests/unit/test_http.py b/glanceclient/tests/unit/test_http.py index efd15bf..cdc1895 100644 --- a/glanceclient/tests/unit/test_http.py +++ b/glanceclient/tests/unit/test_http.py @@ -467,11 +467,11 @@ class TestClient(testtools.TestCase): headers = self.mock.last_request.headers self.assertEqual(refreshed_token, headers['X-Auth-Token']) # regression check for bug 1448080 - unicode_token = u'ni\xf1o' + unicode_token = u'ni\xf1o+' http_client.auth_token = unicode_token http_client.get(path) headers = self.mock.last_request.headers # Bug #1766235: According to RFC 8187, headers must be # encoded as 7-bit ASCII, so expect to see only displayable - # chars in percent-encoding - self.assertEqual(b'ni%C3%B1o', headers['X-Auth-Token']) + # chars in percent-encoding. The '+' char will be not be changed. + self.assertEqual(b'ni%C3%B1o+', headers['X-Auth-Token'])