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/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 diff --git a/aiohttp/web_urldispatcher.py b/aiohttp/web_urldispatcher.py index a444b67c708..83b3c9c4a94 100644 --- a/aiohttp/web_urldispatcher.py +++ b/aiohttp/web_urldispatcher.py @@ -405,8 +405,7 @@ def _match(self, path): return None else: return {key: URL.build(path=value, encoded=True).path - for key, value in - match.groupdict().items()} + for key, value in match.groupdict().items()} def raw_match(self, path): return self._formatter == path @@ -416,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.build(path=url) def __repr__(self): diff --git a/tests/test_urldispatch.py b/tests/test_urldispatch.py index 86d64044da7..293225d3e60 100644 --- a/tests/test_urldispatch.py +++ b/tests/test_urldispatch.py @@ -604,10 +604,18 @@ 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) +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)