)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":24,"context_line":"    + /v1/AUTH_acct/cont/subdir/v1/AUTH_acct/cont/subdir,"},{"line_number":25,"context_line":"which ended up in a 404 error."},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"The patch fix bug #1 in domain_remap by appending the PATH_INFO as-is. It"},{"line_number":28,"context_line":"is now possible to access access an object named \"/v1\" in a container"},{"line_number":29,"context_line":"accessed by domain_remap."},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"Bug #2 is fixed in cname_lookup and domain_remap by catching the"},{"line_number":32,"context_line":"redirection and replacing the rewritten domain/path by the originals"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"1a1ced50_04a21499","line":29,"range":{"start_line":27,"start_character":71,"end_line":29,"end_character":24},"updated":"2017-03-22 14:08:53.000000000","message":"there should be a unit test to verify this assertion, it isn\u0027t clear to me how this works","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":13852,"name":"Romain LE DISEZ","email":"romain.le-disez@corp.ovh.com","username":"rledisez"},"change_message_id":"8cf8f820c06095a28fd4640936df51d96a69b373","unresolved":false,"context_lines":[{"line_number":24,"context_line":"    + /v1/AUTH_acct/cont/subdir/v1/AUTH_acct/cont/subdir,"},{"line_number":25,"context_line":"which ended up in a 404 error."},{"line_number":26,"context_line":""},{"line_number":27,"context_line":"The patch fix bug #1 in domain_remap by appending the PATH_INFO as-is. It"},{"line_number":28,"context_line":"is now possible to access access an object named \"/v1\" in a container"},{"line_number":29,"context_line":"accessed by domain_remap."},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"Bug #2 is fixed in cname_lookup and domain_remap by catching the"},{"line_number":32,"context_line":"redirection and replacing the rewritten domain/path by the originals"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"1a1ced50_f1f3ca70","line":29,"range":{"start_line":27,"start_character":71,"end_line":29,"end_character":24},"in_reply_to":"1a1ced50_04a21499","updated":"2017-03-23 10:06:52.000000000","message":"I added two new tests for that:\n- test_domain_remap_account_container_with_path_obj_slash_v1\n- test_domain_remap_account_container_with_root_path_obj_slash_v1.\n\nThe point is that you can upload an object named /v1 (/ is the first char of the object name, not the separator with container. full path: /v1/AUTH_abc/cont//v1). You must be able to access it through domain_remap. But the way domain_remap strip all /, it is not possible without this commit.","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"}],"swift/common/middleware/cname_lookup.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":179,"context_line":"            else:"},{"line_number":180,"context_line":"                new_host \u003d env[\u0027HTTP_HOST\u0027]"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"                def _start_response(status, headers, exc_info\u003dNone):"},{"line_number":183,"context_line":"                    headers \u003d dict(headers)"},{"line_number":184,"context_line":"                    if str(status)[0:4] in (\u0027301 \u0027, \u0027302 \u0027, \u0027303 \u0027, \u0027307 \u0027) \\"},{"line_number":185,"context_line":"                            and headers.get(\u0027Location\u0027):"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_81c276e7","line":182,"updated":"2017-03-22 14:08:53.000000000","message":"see comments in domain_remap.py re using WSGIContext","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":13852,"name":"Romain LE DISEZ","email":"romain.le-disez@corp.ovh.com","username":"rledisez"},"change_message_id":"8cf8f820c06095a28fd4640936df51d96a69b373","unresolved":false,"context_lines":[{"line_number":179,"context_line":"            else:"},{"line_number":180,"context_line":"                new_host \u003d env[\u0027HTTP_HOST\u0027]"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"                def _start_response(status, headers, exc_info\u003dNone):"},{"line_number":183,"context_line":"                    headers \u003d dict(headers)"},{"line_number":184,"context_line":"                    if str(status)[0:4] in (\u0027301 \u0027, \u0027302 \u0027, \u0027303 \u0027, \u0027307 \u0027) \\"},{"line_number":185,"context_line":"                            and headers.get(\u0027Location\u0027):"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_7100ba34","line":182,"in_reply_to":"1a1ced50_81c276e7","updated":"2017-03-23 10:06:52.000000000","message":"Done","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":84,"context_line":""},{"line_number":85,"context_line":"class _CnameLookupContext(WSGIContext):"},{"line_number":86,"context_line":"    def __init__(self, app, requested_domain, rewritten_domain):"},{"line_number":87,"context_line":"        WSGIContext.__init__(self, app)"},{"line_number":88,"context_line":"        self.app \u003d app"},{"line_number":89,"context_line":"        self.requested_domain \u003d requested_domain"},{"line_number":90,"context_line":"        self.rewritten_domain \u003d rewritten_domain"}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_0c4a07ab","line":87,"updated":"2017-05-10 03:32:17.000000000","message":"I think we call this\n\n super(RewriteContext, self).__init__(app)\n\nthese days? Calling inherited methods is weird in Python...","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":85,"context_line":"class _CnameLookupContext(WSGIContext):"},{"line_number":86,"context_line":"    def __init__(self, app, requested_domain, rewritten_domain):"},{"line_number":87,"context_line":"        WSGIContext.__init__(self, app)"},{"line_number":88,"context_line":"        self.app \u003d app"},{"line_number":89,"context_line":"        self.requested_domain \u003d requested_domain"},{"line_number":90,"context_line":"        self.rewritten_domain \u003d rewritten_domain"},{"line_number":91,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_569e5b54","line":88,"range":{"start_line":88,"start_character":8,"end_line":88,"end_character":22},"updated":"2017-05-10 03:32:17.000000000","message":"I think that\u0027s covered by the super call, no?","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":90,"context_line":"        self.rewritten_domain \u003d rewritten_domain"},{"line_number":91,"context_line":""},{"line_number":92,"context_line":"    def _rewrite_location(self, header):"},{"line_number":93,"context_line":"        if header[0].lower() \u003d\u003d \u0027location\u0027:"},{"line_number":94,"context_line":"            new_location \u003d re.sub("},{"line_number":95,"context_line":"                r\u0027^(https?://)%s(/.*)?$\u0027 % self.rewritten_domain,"},{"line_number":96,"context_line":"                r\u0027\\1%s\\2\u0027 % self.requested_domain, header[1])"}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_6c618b05","line":93,"updated":"2017-05-10 03:32:17.000000000","message":"In the symlink patch at https://review.openstack.org/#/c/232162/ I recommended including a Content-Location header, to tell clients the original source without actually redirecting them. Might be worth translating that header, as well, if we see it.","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":92,"context_line":"    def _rewrite_location(self, header):"},{"line_number":93,"context_line":"        if header[0].lower() \u003d\u003d \u0027location\u0027:"},{"line_number":94,"context_line":"            new_location \u003d re.sub("},{"line_number":95,"context_line":"                r\u0027^(https?://)%s(/.*)?$\u0027 % self.rewritten_domain,"},{"line_number":96,"context_line":"                r\u0027\\1%s\\2\u0027 % self.requested_domain, header[1])"},{"line_number":97,"context_line":"            return (\u0027Location\u0027, new_location)"},{"line_number":98,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_af25455e","line":95,"range":{"start_line":95,"start_character":43,"end_line":95,"end_character":64},"updated":"2017-05-10 03:32:17.000000000","message":"Maybe should have a re.escape()?","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":101,"context_line":"    def handle_request(self, env, start_response):"},{"line_number":102,"context_line":"        resp \u003d self._app_call(env)"},{"line_number":103,"context_line":"        if self._response_status is not None \\"},{"line_number":104,"context_line":"                and self._response_headers is not None \\"},{"line_number":105,"context_line":"                and self._get_status_int() in (301, 302, 303, 307):"},{"line_number":106,"context_line":"            self._response_headers \u003d map(self._rewrite_location,"},{"line_number":107,"context_line":"                                         self._response_headers)"}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_ec1b5b7e","line":104,"updated":"2017-05-10 03:32:17.000000000","message":"Might be safe to drop these first couple checks -- if the response status is still None after calling self._app_call(env), the underlying application isn\u0027t living up to its contract and we\u0027re well off the rails. That\u0027s the point of the reiterate call at https://github.com/openstack/swift/blob/2.14.0/swift/common/wsgi.py#L1059-L1062\n\nThe test failures just indicate that we\u0027re doing a terrible job of writing a fake application; applying something like\n\n diff --git a/test/unit/common/middleware/test_cname_lookup.py b/test/unit/common/middleware/test_cname_lookup.py\n index b2bcfb61..9d1f8598 100644\n --- a/test/unit/common/middleware/test_cname_lookup.py\n +++ b/test/unit/common/middleware/test_cname_lookup.py\n @@ -33,6 +33,7 @@ from swift.common.swob import Request, HTTPMovedPermanently\n  class FakeApp(object):\n  \n      def __call__(self, env, start_response):\n +        start_response(\u0027200 OK\u0027, [])\n          return [\"FAKE APP\"]\n  \n  \n diff --git a/test/unit/common/middleware/test_domain_remap.py b/test/unit/common/middleware/test_domain_remap.py\n index ef6e4b37..0b5e2fab 100644\n --- a/test/unit/common/middleware/test_domain_remap.py\n +++ b/test/unit/common/middleware/test_domain_remap.py\n @@ -23,6 +23,7 @@ from swift.common import utils\n  class FakeApp(object):\n  \n      def __call__(self, env, start_response):\n +        start_response(\u0027200 OK\u0027, [])\n          return [env[\u0027PATH_INFO\u0027]]\n  \n  \n\nis totally reasonable to resolve them.","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":102,"context_line":"        resp \u003d self._app_call(env)"},{"line_number":103,"context_line":"        if self._response_status is not None \\"},{"line_number":104,"context_line":"                and self._response_headers is not None \\"},{"line_number":105,"context_line":"                and self._get_status_int() in (301, 302, 303, 307):"},{"line_number":106,"context_line":"            self._response_headers \u003d map(self._rewrite_location,"},{"line_number":107,"context_line":"                                         self._response_headers)"},{"line_number":108,"context_line":"        start_response(self._response_status, self._response_headers,"}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_6c786bc3","line":105,"updated":"2017-05-10 03:32:17.000000000","message":"Might we ever encounter a location header for other statuses? If we do, should those get translated as well?\n\nAt the very least, it seems like we ought to include 308... maybe just use swift.common.http.is_redirection()? Though I\u0027m not sure what it\u0027d mean to have a Location header on a 300, 304, 305, or 306...","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        if self._response_status is not None \\"},{"line_number":104,"context_line":"                and self._response_headers is not None \\"},{"line_number":105,"context_line":"                and self._get_status_int() in (301, 302, 303, 307):"},{"line_number":106,"context_line":"            self._response_headers \u003d map(self._rewrite_location,"},{"line_number":107,"context_line":"                                         self._response_headers)"},{"line_number":108,"context_line":"        start_response(self._response_status, self._response_headers,"},{"line_number":109,"context_line":"                       self._response_exc_info)"}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_0cdfa7d6","line":106,"updated":"2017-05-10 03:32:17.000000000","message":"May as well go for a list comprehension; if/when we get around to py3 support, map() won\u0027t work for us anymore.","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"}],"swift/common/middleware/domain_remap.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":127,"context_line":"                    return self.app(env, start_response)"},{"line_number":128,"context_line":""},{"line_number":129,"context_line":"            old_path \u003d path \u003d env[\u0027PATH_INFO\u0027]"},{"line_number":130,"context_line":"            new_path_parts \u003d [\u0027\u0027, self.path_root, account]"},{"line_number":131,"context_line":"            if container:"},{"line_number":132,"context_line":"                new_path_parts.append(container)"},{"line_number":133,"context_line":"            if path.startswith(\u0027/\u0027 + self.path_root):"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_deb2894b","line":130,"updated":"2017-03-22 14:08:53.000000000","message":"whenever self.path_root is used, a \u0027/\u0027 is prefixed, or len incrememted by 1, so self.path_root could have the \u0027/\u0027 added when loaded from config. Then, remove the first element of the list (\u0027\u0027) and I think the outcome is the same at line 138","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":13852,"name":"Romain LE DISEZ","email":"romain.le-disez@corp.ovh.com","username":"rledisez"},"change_message_id":"8cf8f820c06095a28fd4640936df51d96a69b373","unresolved":false,"context_lines":[{"line_number":127,"context_line":"                    return self.app(env, start_response)"},{"line_number":128,"context_line":""},{"line_number":129,"context_line":"            old_path \u003d path \u003d env[\u0027PATH_INFO\u0027]"},{"line_number":130,"context_line":"            new_path_parts \u003d [\u0027\u0027, self.path_root, account]"},{"line_number":131,"context_line":"            if container:"},{"line_number":132,"context_line":"                new_path_parts.append(container)"},{"line_number":133,"context_line":"            if path.startswith(\u0027/\u0027 + self.path_root):"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_f19aea12","line":130,"in_reply_to":"1a1ced50_deb2894b","updated":"2017-03-23 10:06:52.000000000","message":"Done","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":130,"context_line":"            new_path_parts \u003d [\u0027\u0027, self.path_root, account]"},{"line_number":131,"context_line":"            if container:"},{"line_number":132,"context_line":"                new_path_parts.append(container)"},{"line_number":133,"context_line":"            if path.startswith(\u0027/\u0027 + self.path_root):"},{"line_number":134,"context_line":"                path \u003d path[1 + len(self.path_root):]"},{"line_number":135,"context_line":"            if path and path[0] \u003d\u003d \u0027/\u0027:"},{"line_number":136,"context_line":"                path \u003d path[1:]"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_9e7bb17a","line":133,"range":{"start_line":133,"start_character":31,"end_line":133,"end_character":35},"updated":"2017-03-22 14:08:53.000000000","message":"see comment at line 130","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":13852,"name":"Romain LE DISEZ","email":"romain.le-disez@corp.ovh.com","username":"rledisez"},"change_message_id":"8cf8f820c06095a28fd4640936df51d96a69b373","unresolved":false,"context_lines":[{"line_number":130,"context_line":"            new_path_parts \u003d [\u0027\u0027, self.path_root, account]"},{"line_number":131,"context_line":"            if container:"},{"line_number":132,"context_line":"                new_path_parts.append(container)"},{"line_number":133,"context_line":"            if path.startswith(\u0027/\u0027 + self.path_root):"},{"line_number":134,"context_line":"                path \u003d path[1 + len(self.path_root):]"},{"line_number":135,"context_line":"            if path and path[0] \u003d\u003d \u0027/\u0027:"},{"line_number":136,"context_line":"                path \u003d path[1:]"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_119ea606","line":133,"range":{"start_line":133,"start_character":31,"end_line":133,"end_character":35},"in_reply_to":"1a1ced50_9e7bb17a","updated":"2017-03-23 10:06:52.000000000","message":"Done","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":138,"context_line":"            new_path \u003d \u0027/\u0027.join(new_path_parts)"},{"line_number":139,"context_line":"            env[\u0027PATH_INFO\u0027] \u003d new_path"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"            def _start_response(status, headers, exc_info\u003dNone):"},{"line_number":142,"context_line":"                headers \u003d dict(headers)"},{"line_number":143,"context_line":"                if str(status)[0:4] in (\u0027301 \u0027, \u0027302 \u0027, \u0027303 \u0027, \u0027307 \u0027) \\"},{"line_number":144,"context_line":"                        and headers.get(\u0027Location\u0027):"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_f7504d34","line":141,"updated":"2017-03-22 14:08:53.000000000","message":"you may want to use a WSGIContext here [1]. It provides some features you need:\n\n1. a helper method to get status int from status (relevant to line 143)\n2. ensure that start response has been called before returning from the __call__\n\n[1] https://github.com/openstack/swift/blob/2cb3e8c410c2ffa627f49d3bd378a32bada5c9cc/swift/common/wsgi.py#L1034-L1034","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":13852,"name":"Romain LE DISEZ","email":"romain.le-disez@corp.ovh.com","username":"rledisez"},"change_message_id":"8cf8f820c06095a28fd4640936df51d96a69b373","unresolved":false,"context_lines":[{"line_number":138,"context_line":"            new_path \u003d \u0027/\u0027.join(new_path_parts)"},{"line_number":139,"context_line":"            env[\u0027PATH_INFO\u0027] \u003d new_path"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"            def _start_response(status, headers, exc_info\u003dNone):"},{"line_number":142,"context_line":"                headers \u003d dict(headers)"},{"line_number":143,"context_line":"                if str(status)[0:4] in (\u0027301 \u0027, \u0027302 \u0027, \u0027303 \u0027, \u0027307 \u0027) \\"},{"line_number":144,"context_line":"                        and headers.get(\u0027Location\u0027):"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_91a9b626","line":141,"in_reply_to":"1a1ced50_f7504d34","updated":"2017-03-23 10:06:52.000000000","message":"The commit now use a WSGIContext. I had to fix tests because their FakeApp() were not returning iterators.","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":139,"context_line":"            env[\u0027PATH_INFO\u0027] \u003d new_path"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"            def _start_response(status, headers, exc_info\u003dNone):"},{"line_number":142,"context_line":"                headers \u003d dict(headers)"},{"line_number":143,"context_line":"                if str(status)[0:4] in (\u0027301 \u0027, \u0027302 \u0027, \u0027303 \u0027, \u0027307 \u0027) \\"},{"line_number":144,"context_line":"                        and headers.get(\u0027Location\u0027):"},{"line_number":145,"context_line":"                    headers[\u0027Location\u0027] \u003d re.sub("}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_d74b5185","line":142,"updated":"2017-03-22 14:08:53.000000000","message":"the headers list can container more than one (name, value) tuple with same name [1], so converting to a  dict can lose headers. The header list needs to be iterated to search for and replace any Location header. There\u0027s an example here [2] which takes advantage of WSGIContext helper method like _response_header_value().\n\n[1] http://stackoverflow.com/questions/4371328/are-duplicate-http-response-headers-acceptable\n[2] https://github.com/openstack/swift/blob/4d3aa4ea78d1867acc8c7520790a90c748b3285c/swift/common/middleware/crypto/decrypter.py#L189-L189","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":13852,"name":"Romain LE DISEZ","email":"romain.le-disez@corp.ovh.com","username":"rledisez"},"change_message_id":"8cf8f820c06095a28fd4640936df51d96a69b373","unresolved":false,"context_lines":[{"line_number":139,"context_line":"            env[\u0027PATH_INFO\u0027] \u003d new_path"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"            def _start_response(status, headers, exc_info\u003dNone):"},{"line_number":142,"context_line":"                headers \u003d dict(headers)"},{"line_number":143,"context_line":"                if str(status)[0:4] in (\u0027301 \u0027, \u0027302 \u0027, \u0027303 \u0027, \u0027307 \u0027) \\"},{"line_number":144,"context_line":"                        and headers.get(\u0027Location\u0027):"},{"line_number":145,"context_line":"                    headers[\u0027Location\u0027] \u003d re.sub("}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_518c9ed9","line":142,"in_reply_to":"1a1ced50_d74b5185","updated":"2017-03-23 10:06:52.000000000","message":"Done","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":147,"context_line":"                        r\u0027\\1%s\\2\u0027 % old_path, headers[\u0027Location\u0027])"},{"line_number":148,"context_line":"                return start_response(status, list(headers.items()), exc_info)"},{"line_number":149,"context_line":""},{"line_number":150,"context_line":"            return self.app(env, _start_response)"},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"        return self.app(env, start_response)"},{"line_number":153,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_fb8757b2","line":150,"updated":"2017-03-22 14:08:53.000000000","message":"The wsgi spec [1] requires that start_response *must* be called before returning - WSGIContext provides this guarantee by waiting in _app_call for it\u0027s start_response to be called.\n\nThe pattern for using/inheriting WSGIContext would be:\n\n  resp \u003d self._app_call(env)\n  do Location header re-writing, generate new resp headers list\n  call start_response\n  return resp\n\n\n[1] https://www.python.org/dev/peps/pep-0333/#the-start-response-callable","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":13852,"name":"Romain LE DISEZ","email":"romain.le-disez@corp.ovh.com","username":"rledisez"},"change_message_id":"8cf8f820c06095a28fd4640936df51d96a69b373","unresolved":false,"context_lines":[{"line_number":147,"context_line":"                        r\u0027\\1%s\\2\u0027 % old_path, headers[\u0027Location\u0027])"},{"line_number":148,"context_line":"                return start_response(status, list(headers.items()), exc_info)"},{"line_number":149,"context_line":""},{"line_number":150,"context_line":"            return self.app(env, _start_response)"},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"        return self.app(env, start_response)"},{"line_number":153,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_b1523233","line":150,"in_reply_to":"1a1ced50_fb8757b2","updated":"2017-03-23 10:06:52.000000000","message":"Done","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":56,"context_line":"from swift.common.wsgi import WSGIContext"},{"line_number":57,"context_line":""},{"line_number":58,"context_line":""},{"line_number":59,"context_line":"class _DomainRemapContext(WSGIContext):"},{"line_number":60,"context_line":"    def __init__(self, app, requested_path, rewritten_path):"},{"line_number":61,"context_line":"        WSGIContext.__init__(self, app)"},{"line_number":62,"context_line":"        self.app \u003d app"}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_4fcfe155","line":59,"updated":"2017-05-10 03:32:17.000000000","message":"This seems to share a lot of commonality with the cname context... worth doing something like http://paste.openstack.org/show/609237/ ?","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"}],"test/unit/common/middleware/test_cname_lookup.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b1eaa6de10b12f8333f53a5b964659317414114c","unresolved":false,"context_lines":[{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    def __call__(self, env, start_response):"},{"line_number":42,"context_line":"        loc \u003d env[\u0027PATH_INFO\u0027] + \u0027/\u0027"},{"line_number":43,"context_line":"        return HTTPMovedPermanently(location\u003dloc)(env, start_response)"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"def start_response(*args):"}],"source_content_type":"text/x-python","patch_set":8,"id":"3f044301_4f26c117","line":43,"updated":"2017-05-10 03:32:17.000000000","message":"Ah, nice, so we have swob.Response handle turning that back into an absolute URL.","commit_id":"f95c2f3251068c22c9488d8d0e37f4bcd60615f0"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"42209756906ed7f47eaf6c09c5fbb41575a55274","unresolved":false,"context_lines":[{"line_number":37,"context_line":"        return [\"FAKE APP\"]"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"class RedirectSlashApp(object):"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":"    def __call__(self, env, start_response):"},{"line_number":43,"context_line":"        loc \u003d env[\u0027PATH_INFO\u0027] + \u0027/\u0027"}],"source_content_type":"text/x-python","patch_set":9,"id":"df140735_7e25aec1","line":40,"updated":"2017-06-01 19:37:02.000000000","message":"nit: this could be in test/unit/common/middlewre/helpers.py\nand then re-used here and in test_domain_remap","commit_id":"107ba797708e07071028e021f2a261151562c9d7"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"42209756906ed7f47eaf6c09c5fbb41575a55274","unresolved":false,"context_lines":[{"line_number":330,"context_line":"    def test_redirect(self):"},{"line_number":331,"context_line":"        app \u003d cname_lookup.CNAMELookupMiddleware(RedirectSlashApp(), {})"},{"line_number":332,"context_line":""},{"line_number":333,"context_line":"        module \u003d \u0027swift.common.middleware.cname_lookup.lookup_cname\u0027"},{"line_number":334,"context_line":"        with mock.patch(module, lambda x: (0, \u0027cont.acct.example.com\u0027)):"},{"line_number":335,"context_line":"            req \u003d Request.blank(\u0027/test\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":336,"context_line":"                                headers\u003d{\u0027Host\u0027: \u0027mysite.com\u0027})"}],"source_content_type":"text/x-python","patch_set":9,"id":"df140735_b909202d","line":333,"range":{"start_line":333,"start_character":8,"end_line":333,"end_character":14},"updated":"2017-06-01 19:37:02.000000000","message":"nit: this is a function not a module, but it\u0027s same in other tests","commit_id":"107ba797708e07071028e021f2a261151562c9d7"}],"test/unit/common/middleware/test_domain_remap.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":94,"context_line":"        req \u003d Request.blank(\u0027/v1\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":95,"context_line":"                            headers\u003d{\u0027Host\u0027: \u0027c.AUTH_a.example.com\u0027})"},{"line_number":96,"context_line":"        resp \u003d self.app(req.environ, start_response)"},{"line_number":97,"context_line":"        self.assertEqual(resp, \u0027/v1/AUTH_a/c/\u0027)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    def test_domain_remap_account_container_with_path(self):"},{"line_number":100,"context_line":"        req \u003d Request.blank(\u0027/obj\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_e1ea4ada","line":97,"updated":"2017-03-22 14:08:53.000000000","message":"this change isn\u0027t intuitive to me; before:\n\n  \u0027/v1\u0027 -\u003e \u0027/v1/AUTH_a/c\u0027\n  \u0027\u0027    -\u003e \u0027/v1/AUTH_a/c\u0027\n\nnow:\n\n  \u0027/v1\u0027 -\u003e \u0027/v1/AUTH_a/c/\u0027 - why append \u0027/\u0027 ?\n  \u0027\u0027    -\u003e \u0027/v1/AUTH_a/c/\u0027 - why append \u0027/\u0027 ?","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":13852,"name":"Romain LE DISEZ","email":"romain.le-disez@corp.ovh.com","username":"rledisez"},"change_message_id":"8cf8f820c06095a28fd4640936df51d96a69b373","unresolved":false,"context_lines":[{"line_number":94,"context_line":"        req \u003d Request.blank(\u0027/v1\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":95,"context_line":"                            headers\u003d{\u0027Host\u0027: \u0027c.AUTH_a.example.com\u0027})"},{"line_number":96,"context_line":"        resp \u003d self.app(req.environ, start_response)"},{"line_number":97,"context_line":"        self.assertEqual(resp, \u0027/v1/AUTH_a/c/\u0027)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    def test_domain_remap_account_container_with_path(self):"},{"line_number":100,"context_line":"        req \u003d Request.blank(\u0027/obj\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_743fc8b3","line":97,"in_reply_to":"1a1ced50_e1ea4ada","updated":"2017-03-23 10:06:52.000000000","message":"When accessing container root through a remapped domain, the request is:\nGET / HTTP/1.1\nHost: cont.acct.example.com\n\nNow that the module is not stripping every /, the / is passed directly. It seems no harm, and it avoids loop redirection with staticweb which want to redirect /v1/AATH_abc/cont to /v1/AATH_abc/cont/","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e03d0771e7b557d6f9d8b112180dc68a6b211843","unresolved":false,"context_lines":[{"line_number":97,"context_line":"        self.assertEqual(resp, \u0027/v1/AUTH_a/c/\u0027)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    def test_domain_remap_account_container_with_path(self):"},{"line_number":100,"context_line":"        req \u003d Request.blank(\u0027/obj\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":101,"context_line":"                            headers\u003d{\u0027Host\u0027: \u0027c.AUTH_a.example.com\u0027})"},{"line_number":102,"context_line":"        resp \u003d self.app(req.environ, start_response)"},{"line_number":103,"context_line":"        self.assertEqual(resp, \u0027/v1/AUTH_a/c/obj\u0027)"}],"source_content_type":"text/x-python","patch_set":4,"id":"1a1ced50_e498987a","line":100,"updated":"2017-03-22 14:08:53.000000000","message":"I\u0027m confused by the handling of \u0027/v1\u0027 vs \u0027/obj\u0027:\n\n  \u0027/obj\u0027 -\u003e \u0027/v1/AUTH_a/c/obj\u0027\n  \u0027obj\u0027  -\u003e \u0027/v1/AUTH_a/c/obj\u0027\n  \u0027/v1\u0027  -\u003e \u0027/v1/AUTH_a/c/\u0027\n  \u0027v1\u0027   -\u003e \u0027/v1/AUTH_a/c/v1\u0027\n\nBUT, in practice, doesn\u0027t PATH_INFO always include the leading \u0027/\u0027? (I may be wrong) - if so how in practice do we access an object name \u0027v1\u0027?","commit_id":"4ecd787fed0a00404a2af487c6819769fb6077e1"}]}
