)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"a25344b6492649c8391c658b71574516aa2e7cb9","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Prevent a UnicodeDecodeError in the s3token middleware"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Mixing \"str\" and \"unicode\" can lead to a UnicodeDecodeError. We encode unicode"},{"line_number":10,"context_line":"values before using them with text strings."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Change-Id: Ib7fdf60f8369ea9546fcd92f1ac385c777478d10"},{"line_number":13,"context_line":"Closes-Bug: #1428706"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"9a80dd14_3eb56acd","line":10,"updated":"2015-03-11 14:03:47.000000000","message":"It\u0027s not clear where the bug occurs or when it occurs.\n\nIt looks like the bug occurs if the URL contains a non-ASCII character in the tenant id: \"hého\" in \"/v1/AUTH_cfa/c/hého\" (\"/v1/AUTH_cfa/c/h\\xc3\\xa9ho\" in UTF-8) for example.\n\nThe bug occurs on Python 2 in s3_token.py because the tenant id is retrieved from identity_info[\u0027access\u0027][\u0027token\u0027][\u0027tenant\u0027] and identity_info comes from resp.json().\n\nThe problem is that in Python, JSON decoder always create Unicode strings. Example in Python 2:\n\n\u003e\u003e\u003e json.loads(\u0027{\"key\": \"value\"}\u0027)\n{u\u0027key\u0027: u\u0027value\u0027}\n\nPython 3 doesn\u0027t look to be affected by this issue.\n\nError of test_unicode_path() when the fix on s3_token.py is not applied.\n\nTraceback (most recent call last):\n  File \"keystoneclient/tests/unit/test_s3_token_middleware.py\", line 148, in test_unicode_path\n    req.get_response(self.middleware)\n  File \"/opt/stack/python-keystoneclient/.tox/py27/lib/python2.7/site-packages/webob/request.py\", line 1320, in send\n    application, catch_exc_info\u003dFalse)\n  File \"/opt/stack/python-keystoneclient/.tox/py27/lib/python2.7/site-packages/webob/request.py\", line 1284, in call_application\n    app_iter \u003d application(self.environ, start_response)\n  File \"keystoneclient/middleware/s3_token.py\", line 256, in __call__\n    new_tenant_name)\nUnicodeDecodeError: \u0027ascii\u0027 codec can\u0027t decode byte 0xc3 in position 15: ordinal not in range(128)","commit_id":"a53fd7785a29985e9b0e6be9a577a7f96095a0e9"},{"author":{"_account_id":8122,"name":"Cyril Roelandt","email":"cyril@redhat.com","username":"cyril.roelandt.enovance"},"change_message_id":"a332cc50713d68358c0d41ab2f8adc07ad662cd5","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Prevent a UnicodeDecodeError in the s3token middleware"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Mixing \"str\" and \"unicode\" can lead to a UnicodeDecodeError. We encode unicode"},{"line_number":10,"context_line":"values before using them with text strings."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Change-Id: Ib7fdf60f8369ea9546fcd92f1ac385c777478d10"},{"line_number":13,"context_line":"Closes-Bug: #1428706"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"9a80dd14_34b90bea","line":10,"in_reply_to":"9a80dd14_3eb56acd","updated":"2015-03-11 14:36:42.000000000","message":"Yes, this is exactly that. I\u0027ll probably reword the changelog if others are OK with it.","commit_id":"a53fd7785a29985e9b0e6be9a577a7f96095a0e9"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"081c8fe474b4635822bf88f690a7780481b22ec6","unresolved":false,"context_lines":[{"line_number":20,"context_line":"The problem is that in Python, the JSON decoder always create Unicode strings."},{"line_number":21,"context_line":"Example in Python 2:"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"\u003e\u003e\u003e json.loads(\u0027{\"key\": \"value\"}\u0027) {u\u0027key\u0027: u\u0027value\u0027}"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"There is no issue in Python 3, since all text strings are Unicode."},{"line_number":26,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"fa963961_69dbb61c","line":23,"updated":"2015-03-26 16:03:34.000000000","message":"Indentation issue?","commit_id":"b965751ccdd9b4399b8148b1639712bc5577dd12"},{"author":{"_account_id":8122,"name":"Cyril Roelandt","email":"cyril@redhat.com","username":"cyril.roelandt.enovance"},"change_message_id":"38756d2904d28a755249dac4d2c591388a513b40","unresolved":false,"context_lines":[{"line_number":20,"context_line":"The problem is that in Python, the JSON decoder always create Unicode strings."},{"line_number":21,"context_line":"Example in Python 2:"},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"\u003e\u003e\u003e json.loads(\u0027{\"key\": \"value\"}\u0027) {u\u0027key\u0027: u\u0027value\u0027}"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"There is no issue in Python 3, since all text strings are Unicode."},{"line_number":26,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"fa963961_8c3e08b7","line":23,"in_reply_to":"fa963961_69dbb61c","updated":"2015-03-26 16:10:56.000000000","message":"Done","commit_id":"b965751ccdd9b4399b8148b1639712bc5577dd12"}],"keystoneclient/middleware/s3_token.py":[{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"0d159820978b76b48ba5ec0eab14acf5efd6aea6","unresolved":false,"context_lines":[{"line_number":251,"context_line":"        req.headers[\u0027X-Auth-Token\u0027] \u003d token_id"},{"line_number":252,"context_line":"        tenant_to_connect \u003d force_tenant or tenant[\u0027id\u0027]"},{"line_number":253,"context_line":"        if six.PY2 and isinstance(tenant_to_connect, six.text_type):"},{"line_number":254,"context_line":"            tenant_to_connect \u003d tenant_to_connect.encode(\u0027utf-8\u0027)"},{"line_number":255,"context_line":"        self.logger.debug(\u0027Connecting with tenant: %s\u0027, tenant_to_connect)"},{"line_number":256,"context_line":"        new_tenant_name \u003d \u0027%s%s\u0027 % (self.reseller_prefix, tenant_to_connect)"},{"line_number":257,"context_line":"        environ[\u0027PATH_INFO\u0027] \u003d environ[\u0027PATH_INFO\u0027].replace(account,"}],"source_content_type":"text/x-python","patch_set":1,"id":"9a80dd14_fe3592f7","line":254,"updated":"2015-03-11 14:11:20.000000000","message":"If tenant_to_connect is a tenant identifier: why would it be non-ASCII? Tenant identifiers are not UUID?","commit_id":"a53fd7785a29985e9b0e6be9a577a7f96095a0e9"},{"author":{"_account_id":7191,"name":"Jamie Lennox","email":"jamielennox@gmail.com","username":"jamielennox"},"change_message_id":"f20a6da16ee81a42be0c3ad64bb59ccb50716f87","unresolved":false,"context_lines":[{"line_number":251,"context_line":"        req.headers[\u0027X-Auth-Token\u0027] \u003d token_id"},{"line_number":252,"context_line":"        tenant_to_connect \u003d force_tenant or tenant[\u0027id\u0027]"},{"line_number":253,"context_line":"        if six.PY2 and isinstance(tenant_to_connect, six.text_type):"},{"line_number":254,"context_line":"            tenant_to_connect \u003d tenant_to_connect.encode(\u0027utf-8\u0027)"},{"line_number":255,"context_line":"        self.logger.debug(\u0027Connecting with tenant: %s\u0027, tenant_to_connect)"},{"line_number":256,"context_line":"        new_tenant_name \u003d \u0027%s%s\u0027 % (self.reseller_prefix, tenant_to_connect)"},{"line_number":257,"context_line":"        environ[\u0027PATH_INFO\u0027] \u003d environ[\u0027PATH_INFO\u0027].replace(account,"}],"source_content_type":"text/x-python","patch_set":1,"id":"9a80dd14_62a04ea6","line":254,"updated":"2015-03-16 10:46:03.000000000","message":"why would you only do this on PY2? it seems to me like we would either want a string or bytes, but have it be the same on py2 and 3.\n\nAlso surely you want to urlencode it or something here, not direct to bytes?","commit_id":"a53fd7785a29985e9b0e6be9a577a7f96095a0e9"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"d63e6afe3d1b40bdaa7fa42910187d36f0c0ebed","unresolved":false,"context_lines":[{"line_number":251,"context_line":"        req.headers[\u0027X-Auth-Token\u0027] \u003d token_id"},{"line_number":252,"context_line":"        tenant_to_connect \u003d force_tenant or tenant[\u0027id\u0027]"},{"line_number":253,"context_line":"        if six.PY2 and isinstance(tenant_to_connect, six.text_type):"},{"line_number":254,"context_line":"            tenant_to_connect \u003d tenant_to_connect.encode(\u0027utf-8\u0027)"},{"line_number":255,"context_line":"        self.logger.debug(\u0027Connecting with tenant: %s\u0027, tenant_to_connect)"},{"line_number":256,"context_line":"        new_tenant_name \u003d \u0027%s%s\u0027 % (self.reseller_prefix, tenant_to_connect)"},{"line_number":257,"context_line":"        environ[\u0027PATH_INFO\u0027] \u003d environ[\u0027PATH_INFO\u0027].replace(account,"}],"source_content_type":"text/x-python","patch_set":1,"id":"9a80dd14_f36432e6","line":254,"in_reply_to":"9a80dd14_62a04ea6","updated":"2015-03-16 13:11:13.000000000","message":"\u003e why would you only do this on PY2?\n\nBecause we want unicode (type str) in Python 3, so we must not encode.\n\n\u003e Also surely you want to urlencode it or something here, not direct to bytes?\n\nI don\u0027t see why we should use urlencode(), it wasn\u0027t used before. WSGI doesn\u0027t do that for us? Anyway, the tenant id is probably just ASCII.","commit_id":"a53fd7785a29985e9b0e6be9a577a7f96095a0e9"},{"author":{"_account_id":8122,"name":"Cyril Roelandt","email":"cyril@redhat.com","username":"cyril.roelandt.enovance"},"change_message_id":"a332cc50713d68358c0d41ab2f8adc07ad662cd5","unresolved":false,"context_lines":[{"line_number":251,"context_line":"        req.headers[\u0027X-Auth-Token\u0027] \u003d token_id"},{"line_number":252,"context_line":"        tenant_to_connect \u003d force_tenant or tenant[\u0027id\u0027]"},{"line_number":253,"context_line":"        if six.PY2 and isinstance(tenant_to_connect, six.text_type):"},{"line_number":254,"context_line":"            tenant_to_connect \u003d tenant_to_connect.encode(\u0027utf-8\u0027)"},{"line_number":255,"context_line":"        self.logger.debug(\u0027Connecting with tenant: %s\u0027, tenant_to_connect)"},{"line_number":256,"context_line":"        new_tenant_name \u003d \u0027%s%s\u0027 % (self.reseller_prefix, tenant_to_connect)"},{"line_number":257,"context_line":"        environ[\u0027PATH_INFO\u0027] \u003d environ[\u0027PATH_INFO\u0027].replace(account,"}],"source_content_type":"text/x-python","patch_set":1,"id":"9a80dd14_4149638a","line":254,"in_reply_to":"9a80dd14_fe3592f7","updated":"2015-03-11 14:36:42.000000000","message":"tenant[\u0027id\u0027] comes from a call to keystone and is unicode. Why ? Well, don\u0027t know. Probably because it comes from a JSON value (resp.json()).","commit_id":"a53fd7785a29985e9b0e6be9a577a7f96095a0e9"}],"keystoneclient/tests/unit/test_s3_token_middleware.py":[{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"a25344b6492649c8391c658b71574516aa2e7cb9","unresolved":false,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"GOOD_RESPONSE \u003d {\u0027access\u0027: {\u0027token\u0027: {\u0027id\u0027: \u0027TOKEN_ID\u0027,"},{"line_number":27,"context_line":"                                      \u0027tenant\u0027: {\u0027id\u0027: u\u0027TENANT_ID\u0027}}}}"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"class FakeApp(object):"}],"source_content_type":"text/x-python","patch_set":1,"id":"9a80dd14_5eae9ee8","line":27,"updated":"2015-03-11 14:03:47.000000000","message":"I don\u0027t understand this change.\n\nWithout this change, test_unicode_path() still fails if the patch on s3_token.py is not applied.","commit_id":"a53fd7785a29985e9b0e6be9a577a7f96095a0e9"},{"author":{"_account_id":8122,"name":"Cyril Roelandt","email":"cyril@redhat.com","username":"cyril.roelandt.enovance"},"change_message_id":"a332cc50713d68358c0d41ab2f8adc07ad662cd5","unresolved":false,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"GOOD_RESPONSE \u003d {\u0027access\u0027: {\u0027token\u0027: {\u0027id\u0027: \u0027TOKEN_ID\u0027,"},{"line_number":27,"context_line":"                                      \u0027tenant\u0027: {\u0027id\u0027: u\u0027TENANT_ID\u0027}}}}"},{"line_number":28,"context_line":""},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"class FakeApp(object):"}],"source_content_type":"text/x-python","patch_set":1,"id":"9a80dd14_f4785391","line":27,"in_reply_to":"9a80dd14_5eae9ee8","updated":"2015-03-11 14:36:42.000000000","message":"In real life, the tenant id is Unicode, so I thought it would be best to use Unicode here. Of course, that might apply to other fields as well...","commit_id":"a53fd7785a29985e9b0e6be9a577a7f96095a0e9"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"081c8fe474b4635822bf88f690a7780481b22ec6","unresolved":false,"context_lines":[{"line_number":142,"context_line":"        mock_args, mock_kwargs \u003d MOCK_REQUEST.call_args"},{"line_number":143,"context_line":"        self.assertIs(mock_kwargs[\u0027verify\u0027], False)"},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"    if six.PY2:"},{"line_number":146,"context_line":"        def test_unicode_path(self):"},{"line_number":147,"context_line":"            req \u003d webob.Request.blank(\u0027/v1/AUTH_cfa/c/\\xc3\\xa9\u0027)"},{"line_number":148,"context_line":"            req.headers[\u0027Authorization\u0027] \u003d \u0027access:signature\u0027"}],"source_content_type":"text/x-python","patch_set":2,"id":"fa963961_292b6eed","line":145,"updated":"2015-03-26 16:03:34.000000000","message":"Would it hurt to run the test on Python 3?","commit_id":"b965751ccdd9b4399b8148b1639712bc5577dd12"},{"author":{"_account_id":8122,"name":"Cyril Roelandt","email":"cyril@redhat.com","username":"cyril.roelandt.enovance"},"change_message_id":"f8bb5db39e2baaed03e9f3cb796abe1116289caa","unresolved":false,"context_lines":[{"line_number":142,"context_line":"        mock_args, mock_kwargs \u003d MOCK_REQUEST.call_args"},{"line_number":143,"context_line":"        self.assertIs(mock_kwargs[\u0027verify\u0027], False)"},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"    if six.PY2:"},{"line_number":146,"context_line":"        def test_unicode_path(self):"},{"line_number":147,"context_line":"            req \u003d webob.Request.blank(\u0027/v1/AUTH_cfa/c/\\xc3\\xa9\u0027)"},{"line_number":148,"context_line":"            req.headers[\u0027Authorization\u0027] \u003d \u0027access:signature\u0027"}],"source_content_type":"text/x-python","patch_set":2,"id":"dac4157f_be2f9ca0","line":145,"in_reply_to":"fa963961_1d3104a3","updated":"2015-04-20 17:03:07.000000000","message":"If I use \"/v1/AUTH_cfa/c/%c3%a9\" as the test URL, the test pass with both py27 and py34... without my fix :)","commit_id":"b965751ccdd9b4399b8148b1639712bc5577dd12"},{"author":{"_account_id":8122,"name":"Cyril Roelandt","email":"cyril@redhat.com","username":"cyril.roelandt.enovance"},"change_message_id":"38756d2904d28a755249dac4d2c591388a513b40","unresolved":false,"context_lines":[{"line_number":142,"context_line":"        mock_args, mock_kwargs \u003d MOCK_REQUEST.call_args"},{"line_number":143,"context_line":"        self.assertIs(mock_kwargs[\u0027verify\u0027], False)"},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"    if six.PY2:"},{"line_number":146,"context_line":"        def test_unicode_path(self):"},{"line_number":147,"context_line":"            req \u003d webob.Request.blank(\u0027/v1/AUTH_cfa/c/\\xc3\\xa9\u0027)"},{"line_number":148,"context_line":"            req.headers[\u0027Authorization\u0027] \u003d \u0027access:signature\u0027"}],"source_content_type":"text/x-python","patch_set":2,"id":"fa963961_6c34e4dd","line":145,"in_reply_to":"fa963961_292b6eed","updated":"2015-03-26 16:10:56.000000000","message":"It fails with:\n\nTraceback (most recent call last):\n  File \"./keystoneclient/tests/unit/test_s3_token_middleware.py\", line 146, in test_unicode_path\n    req \u003d webob.Request.blank(\u0027/v1/AUTH_cfa/c/\\xc3\\xa9\u0027)\n  File \"/home/cyril/openstack/python-keystoneclient/.tox/py33/lib/python3.3/site-packages/webob/request.py\", line 1353, in blank\n    env \u003d environ_from_url(path)\n  File \"/home/cyril/openstack/python-keystoneclient/.tox/py33/lib/python3.3/site-packages/webob/request.py\", line 1450, in environ_from_url\n    path_info \u003d url_unquote(path)\n  File \"/home/cyril/openstack/python-keystoneclient/.tox/py33/lib/python3.3/site-packages/webob/compat.py\", line 101, in url_unquote\n    return unquote(s.encode(\u0027ascii\u0027)).decode(\u0027latin-1\u0027)\nUnicodeEncodeError: \u0027ascii\u0027 codec can\u0027t encode characters in position 15-16: ordinal not in range(128)\n\nProbably an issue with webob. Any idea?","commit_id":"b965751ccdd9b4399b8148b1639712bc5577dd12"},{"author":{"_account_id":9107,"name":"Victor Stinner","email":"vstinner@redhat.com","username":"haypo"},"change_message_id":"b3ac4784c5f23c0f0276a892625bf37733737db0","unresolved":false,"context_lines":[{"line_number":142,"context_line":"        mock_args, mock_kwargs \u003d MOCK_REQUEST.call_args"},{"line_number":143,"context_line":"        self.assertIs(mock_kwargs[\u0027verify\u0027], False)"},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"    if six.PY2:"},{"line_number":146,"context_line":"        def test_unicode_path(self):"},{"line_number":147,"context_line":"            req \u003d webob.Request.blank(\u0027/v1/AUTH_cfa/c/\\xc3\\xa9\u0027)"},{"line_number":148,"context_line":"            req.headers[\u0027Authorization\u0027] \u003d \u0027access:signature\u0027"}],"source_content_type":"text/x-python","patch_set":2,"id":"fa963961_1d3104a3","line":145,"in_reply_to":"fa963961_6c34e4dd","updated":"2015-03-26 17:10:30.000000000","message":"Can you try \"/v1/AUTH_cfa/c/%c3%a9\" URL instead for Python 2 and Python 3? The test must still fail without your fix, otherwise the test is useless :-)","commit_id":"b965751ccdd9b4399b8148b1639712bc5577dd12"}]}
