From 1b4b765bed1a3b07a5ced44c90af0090810ec448 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 16 Jan 2018 10:17:40 +0200 Subject: [PATCH 1/3] Poslish quoting --- aiohttp/web_urldispatcher.py | 21 +++++++++++---------- tests/test_urldispatch.py | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py index f4332a8ec99..829c054a696 100644 --- a/aiohttp/web_urldispatcher.py +++ b/aiohttp/web_urldispatcher.py @@ -343,7 +343,7 @@ def get_info(self): return {'path': self._path} def url_for(self): - return URL(self._path) + return URL(self._path, encoded=True) def __repr__(self): name = "'" + self.name + "' " if self.name is not None else "" @@ -378,7 +378,7 @@ def __init__(self, path, *, name=None): if '{' in part or '}' in part: raise ValueError("Invalid path '{}'['{}']".format(path, part)) - path = URL(part).raw_path + path = URL.build(path=part).raw_path formatter += path pattern += re.escape(path) @@ -404,8 +404,8 @@ def _match(self, path): if match is None: return None else: - return {key: URL(value, encoded=True).path for key, value in - match.groupdict().items()} + return {key: URL.build(path=value, encoded=True).path + for key, value in match.groupdict().items()} def raw_match(self, path): return self._formatter == path @@ -415,7 +415,8 @@ def get_info(self): 'pattern': self._pattern} def url_for(self, **parts): - url = self._formatter.format_map(parts) + url = self._formatter.format_map({k: URL.build(path=v).raw_path + for k, v in parts.items()}) return URL(url) def __repr__(self): @@ -430,7 +431,7 @@ def __init__(self, prefix, *, name=None): assert not prefix or prefix.startswith('/'), prefix assert prefix in ('', '/') or not prefix.endswith('/'), prefix super().__init__(name=name) - self._prefix = URL(prefix).raw_path + self._prefix = URL.build(path=prefix).raw_path def add_prefix(self, prefix): assert prefix.startswith('/') @@ -483,7 +484,7 @@ def url_for(self, *, filename, append_version=None): while filename.startswith('/'): filename = filename[1:] filename = '/' + filename - url = self._prefix + URL(filename).raw_path + url = self._prefix + URL.build(path=filename).raw_path url = URL(url) if append_version is True: try: @@ -534,8 +535,8 @@ async def resolve(self, request): if method not in allowed_methods: return None, allowed_methods - match_dict = {'filename': URL(path[len(self._prefix)+1:], - encoded=True).path} + match_dict = {'filename': URL.build(path=path[len(self._prefix)+1:], + encoded=True).path} return (UrlMappingMatchInfo(match_dict, self._routes[method]), allowed_methods) @@ -850,7 +851,7 @@ def add_resource(self, path, *, name=None): if resource.name == name and resource.raw_match(path): return resource if not ('{' in path or '}' in path or ROUTE_RE.search(path)): - url = URL(path) + url = URL.build(path=path) resource = PlainResource(url.raw_path, name=name) self.register_resource(resource) return resource diff --git a/tests/test_urldispatch.py b/tests/test_urldispatch.py index 04e11060e5e..80b4bda3f8e 100644 --- a/tests/test_urldispatch.py +++ b/tests/test_urldispatch.py @@ -593,7 +593,7 @@ def test_route_dynamic_with_regex(router): handler = make_handler() route = router.add_route('GET', r'/{one}/{two:.+}', handler) - url = route.url_for(one=1, two=2) + url = route.url_for(one='1', two='2') assert '/1/2' == str(url) From 2410d9ade91ac2ba178570bd37e4638ec3d0db72 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 16 Jan 2018 10:18:53 +0200 Subject: [PATCH 2/3] Add CHANGE note --- CHANGES/2668.removal | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGES/2668.removal diff --git a/CHANGES/2668.removal b/CHANGES/2668.removal new file mode 100644 index 00000000000..809d533c196 --- /dev/null +++ b/CHANGES/2668.removal @@ -0,0 +1 @@ +Forbid non-strings in `resource.url_for()` parameters. \ No newline at end of file From 73f56b71502cbd27e6f785b3bc9f7e57989a8e30 Mon Sep 17 00:00:00 2001 From: Andrew Svetlov Date: Tue, 16 Jan 2018 13:58:05 +0200 Subject: [PATCH 3/3] More tests --- CHANGES/2668.bugfix | 1 + tests/test_urldispatch.py | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 CHANGES/2668.bugfix diff --git a/CHANGES/2668.bugfix b/CHANGES/2668.bugfix new file mode 100644 index 00000000000..e9176354c45 --- /dev/null +++ b/CHANGES/2668.bugfix @@ -0,0 +1 @@ +Do percent encoding for `.url_for()` parameters \ No newline at end of file diff --git a/tests/test_urldispatch.py b/tests/test_urldispatch.py index 80b4bda3f8e..2b7027cfa77 100644 --- a/tests/test_urldispatch.py +++ b/tests/test_urldispatch.py @@ -597,6 +597,14 @@ def test_route_dynamic_with_regex(router): assert '/1/2' == str(url) +def test_route_dynamic_quoting(router): + handler = make_handler() + route = router.add_route('GET', r'/{arg}', handler) + + url = route.url_for(arg='1 2/текст') + assert '/1%202/%D1%82%D0%B5%D0%BA%D1%81%D1%82' == str(url) + + async def test_regular_match_info(router): handler = make_handler() router.add_route('GET', '/get/{name}', handler)